refactor indexed_block, avoid unnecessery copying

This commit is contained in:
debris 2016-12-09 15:43:00 +01:00
parent da80c69a80
commit 4204f8b1b9
12 changed files with 146 additions and 202 deletions

View File

@ -1,158 +1,68 @@
use chain;
use primitives::hash::H256;
use chain::{Block, BlockHeader, OutPoint, TransactionOutput, merkle_root};
use serialization::Serializable;
use indexed_header::IndexedBlockHeader;
use indexed_transaction::IndexedTransaction;
use PreviousTransactionOutputProvider;
#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct IndexedBlock {
header: chain::BlockHeader,
header_hash: H256,
transactions: Vec<chain::Transaction>,
// guaranteed to be the same length as transactions
transaction_hashes: Vec<H256>,
pub header: IndexedBlockHeader,
pub transactions: Vec<IndexedTransaction>,
}
impl PreviousTransactionOutputProvider for IndexedBlock {
fn previous_transaction_output(&self, prevout: &chain::OutPoint) -> Option<chain::TransactionOutput> {
self.transaction(&prevout.hash)
.and_then(|tx| tx.outputs.get(prevout.index as usize))
.cloned()
fn previous_transaction_output(&self, prevout: &OutPoint) -> Option<TransactionOutput> {
let txs: &[_] = &self.transactions;
txs.previous_transaction_output(prevout)
}
fn is_spent(&self, _prevout: &chain::OutPoint) -> bool {
// block does not need it to be checked
false
fn is_spent(&self, _prevout: &OutPoint) -> bool {
unimplemented!();
}
}
impl From<chain::Block> for IndexedBlock {
fn from(block: chain::Block) -> Self {
let chain::Block { block_header, transactions } = block;
let header_hash = block_header.hash();
let hashes = transactions.iter().map(chain::Transaction::hash).collect();
impl From<Block> for IndexedBlock {
fn from(block: Block) -> Self {
let Block { block_header, transactions } = block;
IndexedBlock {
header: block_header,
header_hash: header_hash,
transactions: transactions,
transaction_hashes: hashes,
header: block_header.into(),
transactions: transactions.into_iter().map(Into::into).collect(),
}
}
}
impl IndexedBlock {
pub fn new(header: chain::BlockHeader, transaction_index: Vec<(H256, chain::Transaction)>) -> Self {
let mut block = IndexedBlock {
header_hash: header.hash(),
pub fn new(header: IndexedBlockHeader, transactions: Vec<IndexedTransaction>) -> Self {
IndexedBlock {
header: header,
transactions: Vec::with_capacity(transaction_index.len()),
transaction_hashes: Vec::with_capacity(transaction_index.len()),
};
for (h256, tx) in transaction_index {
block.transactions.push(tx);
block.transaction_hashes.push(h256);
transactions: transactions,
}
block
}
pub fn transaction(&self, hash: &H256) -> Option<&chain::Transaction> {
self.transaction_hashes.iter()
.position(|x| x == hash)
.map(|position| &self.transactions[position])
}
pub fn transactions(&self) -> IndexedTransactions {
IndexedTransactions {
position: 0,
block: self,
}
}
pub fn transaction_hashes(&self) -> &[H256] {
&self.transaction_hashes
}
pub fn header(&self) -> &chain::BlockHeader {
&self.header
}
pub fn hash(&self) -> &H256 {
&self.header_hash
&self.header.hash
}
pub fn transaction_count(&self) -> usize {
self.transaction_hashes.len()
pub fn header(&self) -> &BlockHeader {
&self.header.raw
}
pub fn to_block(&self) -> chain::Block {
chain::Block::new(
self.header.clone(),
self.transactions.clone(),
)
pub fn to_raw_block(self) -> Block {
Block::new(self.header.raw, self.transactions.into_iter().map(|tx| tx.raw).collect())
}
pub fn size(&self) -> usize {
// todo: optimize
self.to_block().serialized_size()
let txs_size = self.transactions.iter().map(|tx| tx.raw.serialized_size()).sum::<usize>();
self.header.raw.serialized_size() + txs_size
}
pub fn merkle_root(&self) -> H256 {
chain::merkle_root(&self.transaction_hashes)
merkle_root(&self.transactions.iter().map(|tx| tx.hash.clone()).collect::<Vec<_>>())
}
pub fn is_final(&self, height: u32) -> bool {
self.transactions.iter().all(|t| t.is_final(height, self.header.time))
}
pub fn transaction_at(&self, index: usize) -> (&H256, &chain::Transaction) {
(&self.transaction_hashes[index], &self.transactions[index])
}
}
pub struct IndexedTransactions<'a> {
position: usize,
block: &'a IndexedBlock,
}
impl<'a> Iterator for IndexedTransactions<'a> {
type Item = (&'a H256, &'a chain::Transaction);
fn next(&mut self) -> Option<(&'a H256, &'a chain::Transaction)> {
if self.position >= self.block.transactions.len() {
None
}
else {
let result = Some((&self.block.transaction_hashes[self.position], &self.block.transactions[self.position]));
self.position += 1;
result
}
}
}
#[cfg(test)]
mod tests {
use test_data;
use super::IndexedBlock;
#[test]
fn index() {
let block = test_data::block_h1();
let indexed_block: IndexedBlock = block.clone().into();
assert_eq!(*indexed_block.transactions().nth(0).unwrap().0, block.transactions()[0].hash());
}
#[test]
fn iter() {
let block = test_data::block_builder()
.header().build()
.transaction().coinbase().output().value(3).build().build()
.transaction().coinbase().output().value(5).build().build()
.build();
let indexed_block: IndexedBlock = block.clone().into();
assert_eq!(*indexed_block.transactions().nth(1).unwrap().0, block.transactions()[1].hash());
self.transactions.iter().all(|tx| tx.raw.is_final(height, self.header.raw.time))
}
}

26
db/src/indexed_header.rs Normal file
View File

@ -0,0 +1,26 @@
use primitives::hash::H256;
use chain::BlockHeader;
#[derive(Debug, Clone)]
pub struct IndexedBlockHeader {
pub hash: H256,
pub raw: BlockHeader,
}
impl From<BlockHeader> for IndexedBlockHeader {
fn from(header: BlockHeader) -> Self {
IndexedBlockHeader {
hash: header.hash(),
raw: header,
}
}
}
impl IndexedBlockHeader {
pub fn new(hash: H256, header: BlockHeader) -> Self {
IndexedBlockHeader {
hash: hash,
raw: header,
}
}
}

View File

@ -3,18 +3,26 @@ use primitives::hash::H256;
use chain::{Transaction, OutPoint, TransactionOutput};
use PreviousTransactionOutputProvider;
#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct IndexedTransaction {
pub transaction: Transaction,
pub hash: H256,
pub raw: Transaction,
}
impl From<Transaction> for IndexedTransaction {
fn from(t: Transaction) -> Self {
let hash = t.hash();
fn from(tx: Transaction) -> Self {
IndexedTransaction {
hash: tx.hash(),
raw: tx,
}
}
}
impl IndexedTransaction {
pub fn new(hash: H256, transaction: Transaction) -> Self {
IndexedTransaction {
transaction: t,
hash: hash,
raw: transaction,
}
}
}
@ -29,7 +37,7 @@ impl<'a> PreviousTransactionOutputProvider for &'a [IndexedTransaction] {
fn previous_transaction_output(&self, prevout: &OutPoint) -> Option<TransactionOutput> {
self.iter()
.find(|tx| tx.hash == prevout.hash)
.map(|tx| tx.transaction.outputs[prevout.index as usize].clone())
.map(|tx| tx.raw.outputs[prevout.index as usize].clone())
}
fn is_spent(&self, _prevout: &OutPoint) -> bool {

View File

@ -28,6 +28,7 @@ mod transaction_meta_provider;
mod error;
mod update_context;
mod indexed_block;
mod indexed_header;
mod indexed_transaction;
#[derive(Debug, Clone)]
@ -72,8 +73,9 @@ pub use transaction_provider::{TransactionProvider, AsTransactionProvider, Previ
pub use transaction_meta_provider::TransactionMetaProvider;
pub use block_stapler::{BlockStapler, BlockInsertedChain};
pub use block_provider::{BlockProvider, BlockHeaderProvider, AsBlockHeaderProvider};
pub use indexed_block::{IndexedBlock, IndexedTransactions};
pub use indexed_transaction::{IndexedTransaction};
pub use indexed_block::IndexedBlock;
pub use indexed_header::IndexedBlockHeader;
pub use indexed_transaction::IndexedTransaction;
#[cfg(feature="dev")]
pub use test_storage::TestStorage;

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, IndexedBlock, IndexedTransactions};
use super::{BlockRef, BestBlock, BlockLocation, IndexedBlock};
use serialization::{serialize, deserialize};
use chain;
use parking_lot::RwLock;
@ -19,6 +19,9 @@ use transaction_provider::TransactionProvider;
use transaction_meta_provider::TransactionMetaProvider;
use block_stapler::{BlockStapler, BlockInsertedChain, Reorganization};
use indexed_header::IndexedBlockHeader;
use indexed_transaction::IndexedTransaction;
pub const COL_COUNT: u32 = 10;
pub const COL_META: u32 = 0;
pub const COL_BLOCK_HASHES: u32 = 1;
@ -166,32 +169,34 @@ impl Storage {
fn block_by_hash(&self, h: &H256) -> Option<IndexedBlock> {
self.block_header_by_hash(h).map(|header| {
let tx_hashes = self.block_transaction_hashes_by_hash(h);
let txs = tx_hashes.iter()
.map(|tx_hash| self.transaction(tx_hash).expect("Missing transaction, possible db corruption"))
let txs = tx_hashes.into_iter()
.map(|tx_hash| {
let tx = self.transaction(&tx_hash).expect("Missing transaction, possible db corruption");
IndexedTransaction::new(tx_hash, tx)
})
.collect::<Vec<_>>();
let tx_index = tx_hashes.into_iter().zip(txs.into_iter()).collect();
IndexedBlock::new(header, tx_index)
IndexedBlock::new(IndexedBlockHeader::new(h.clone(), header), txs)
})
}
/// update transactions metadata in the specified database transaction
fn update_transactions_meta(&self, context: &mut UpdateContext, number: u32, accepted_txs: &mut IndexedTransactions)
fn update_transactions_meta(&self, context: &mut UpdateContext, number: u32, accepted_txs: &[IndexedTransaction])
-> Result<(), Error>
{
if let Some((accepted_hash, accepted_tx)) = accepted_txs.next() {
if let Some(tx) = accepted_txs.first() {
context.meta.insert(
accepted_hash.clone(),
TransactionMeta::new_coinbase(number, accepted_tx.outputs.len())
tx.hash.clone(),
TransactionMeta::new_coinbase(number, tx.raw.outputs.len())
);
}
for (accepted_hash, accepted_tx) in accepted_txs {
for tx in accepted_txs {
context.meta.insert(
accepted_hash.clone(),
TransactionMeta::new(number, accepted_tx.outputs.len())
tx.hash.clone(),
TransactionMeta::new(number, tx.raw.outputs.len())
);
for input in &accepted_tx.inputs {
for input in &tx.raw.inputs {
use std::collections::hash_map::Entry;
match context.meta.entry(input.previous_output.hash.clone()) {
@ -303,7 +308,7 @@ impl Storage {
trace!(target: "db", "Canonizing block {}", hash.to_reversed_str());
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()));
try!(self.update_transactions_meta(context, at_height, &block.transactions));
// only canonical blocks are allowed to wield a number
context.db_transaction.put(Some(COL_BLOCK_HASHES), &u32_key(at_height), &**hash);
@ -470,7 +475,7 @@ impl BlockStapler for Storage {
let block_hash = block.hash();
let mut new_best_hash = match best_block.as_ref().map(|bb| &bb.hash) {
Some(best_hash) if &block.header().previous_header_hash != best_hash => best_hash.clone(),
Some(best_hash) if &block.header.raw.previous_header_hash != best_hash => best_hash.clone(),
_ => block_hash.clone(),
};
@ -482,14 +487,14 @@ impl BlockStapler for Storage {
None => 0,
};
let tx_space = block.transaction_count() * 32;
let tx_space = block.transactions.len() * 32;
let mut tx_refs = Vec::with_capacity(tx_space);
for (tx_hash, tx) in block.transactions() {
tx_refs.extend(&**tx_hash);
for tx in &block.transactions {
tx_refs.extend(&*tx.hash);
context.db_transaction.put(
Some(COL_TRANSACTIONS),
&**tx_hash,
&serialize(tx),
&*tx.hash,
&serialize(&tx.raw),
);
}
context.db_transaction.put(Some(COL_BLOCK_TRANSACTIONS), &**block_hash, &tx_refs);
@ -497,12 +502,12 @@ impl BlockStapler for Storage {
context.db_transaction.put(
Some(COL_BLOCK_HEADERS),
&**block_hash,
&serialize(block.header())
&serialize(&block.header.raw)
);
// 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, &mut block.transactions()));
try!(self.update_transactions_meta(&mut context, new_best_number, &block.transactions));
context.db_transaction.write_u32(Some(COL_META), KEY_BEST_BLOCK_NUMBER, new_best_number);
// updating main chain height reference
@ -516,14 +521,14 @@ impl BlockStapler for Storage {
// but can cause reorganization here
// this can canonize the block parent if block parent + this block is longer than the main chain
else {
match self.maybe_reorganize(&mut context, &block.header().previous_header_hash) {
match self.maybe_reorganize(&mut context, &block.header.raw.previous_header_hash) {
Ok(Some(mut reorg)) => {
// if so, we have new best main chain block
new_best_number = reorg.height + 1;
new_best_hash = block_hash.clone();
// and we canonize it also by provisioning transactions
try!(self.update_transactions_meta(&mut context, new_best_number, &mut block.transactions()));
try!(self.update_transactions_meta(&mut context, new_best_number, &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

@ -126,7 +126,7 @@ 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())
self.insert_block(&block.clone().to_raw_block())
}
fn insert_block(&self, block: &chain::Block) -> Result<BlockInsertedChain, Error> {

View File

@ -183,20 +183,17 @@ impl BlockAssembler {
let size_step = block_size.decide(transaction_size);
let sigops_step = sigops.decide(sigops_count);
let transaction = IndexedTransaction {
transaction: entry.transaction.clone(),
hash: entry.hash.clone(),
};
match size_step.and(sigops_step) {
NextStep::Append => {
let tx = IndexedTransaction::new(entry.hash.clone(), entry.transaction.clone());
// miner_fee is i64, but we can safely cast it to u64
// memory pool should restrict miner fee to be positive
*coinbase_value += entry.miner_fee as u64;
transactions.push(transaction);
transactions.push(tx);
},
NextStep::FinishAndAppend => {
transactions.push(transaction);
let tx = IndexedTransaction::new(entry.hash.clone(), entry.transaction.clone());
transactions.push(tx);
break;
},
NextStep::Ignore => (),

View File

@ -15,27 +15,27 @@ pub fn build_compact_block(block: IndexedBlock, prefilled_transactions_indexes:
let nonce: u64 = thread_rng().gen();
let prefilled_transactions_len = prefilled_transactions_indexes.len();
let mut short_ids: Vec<ShortTransactionID> = Vec::with_capacity(block.transaction_count() - prefilled_transactions_len);
let mut short_ids: Vec<ShortTransactionID> = Vec::with_capacity(block.transactions.len() - prefilled_transactions_len);
let mut prefilled_transactions: Vec<PrefilledTransaction> = Vec::with_capacity(prefilled_transactions_len);
let mut prefilled_transactions_size: usize = 0;
let (key0, key1) = short_transaction_id_keys(nonce, block.header());
for (transaction_index, (transaction_hash, transaction)) in block.transactions().enumerate() {
let transaction_size = transaction.serialized_size();
let (key0, key1) = short_transaction_id_keys(nonce, &block.header.raw);
for (transaction_index, transaction) in block.transactions.into_iter().enumerate() {
let transaction_size = transaction.raw.serialized_size();
if prefilled_transactions_size + transaction_size < MAX_COMPACT_BLOCK_PREFILLED_SIZE
&& prefilled_transactions_indexes.contains(&transaction_index) {
prefilled_transactions_size += transaction_size;
prefilled_transactions.push(PrefilledTransaction {
index: transaction_index,
transaction: transaction.clone(),
transaction: transaction.raw,
})
} else {
short_ids.push(short_transaction_id(key0, key1, transaction_hash));
short_ids.push(short_transaction_id(key0, key1, &transaction.hash));
}
}
BlockHeaderAndIDs {
header: block.header().clone(),
header: block.header.raw,
nonce: nonce,
short_ids: short_ids,
prefilled_transactions: prefilled_transactions,

View File

@ -371,10 +371,10 @@ impl Chain {
// all transactions from this block were accepted
// => delete accepted transactions from verification queue and from the memory pool
// + also remove transactions which spent outputs which have been spent by transactions from the block
for (tx_hash, tx) in block.transactions() {
self.memory_pool.remove_by_hash(tx_hash);
self.verifying_transactions.remove(tx_hash);
for tx_input in &tx.inputs {
for tx in &block.transactions {
self.memory_pool.remove_by_hash(&tx.hash);
self.verifying_transactions.remove(&tx.hash);
for tx_input in &tx.raw.inputs {
self.memory_pool.remove_by_prevout(&tx_input.previous_output);
}
}
@ -398,7 +398,7 @@ impl Chain {
// all transactions from this block were accepted
// + all transactions from previous blocks of this fork were accepted
// => delete accepted transactions from verification queue and from the memory pool
let this_block_transactions_hashes: Vec<H256> = block.transaction_hashes().iter().cloned().collect();
let this_block_transactions_hashes = block.transactions.iter().map(|tx| tx.hash.clone()).collect::<Vec<_>>();
let mut canonized_blocks_hashes: Vec<H256> = Vec::new();
let mut new_main_blocks_transactions_hashes: Vec<H256> = Vec::new();
while let Some(canonized_block_hash) = reorganization.pop_canonized() {

View File

@ -583,9 +583,9 @@ impl<T> ClientCore for SynchronizationClientCore<T> where T: TaskExecutor {
None => notfound.push(item),
Some(block) => {
let indexed_block: IndexedBlock = block.into();
let prefilled_transactions_indexes = indexed_block.transactions().enumerate()
let prefilled_transactions_indexes = indexed_block.transactions.iter().enumerate()
// we do not filter by fee rate here, because it only reasonable for non-mined transactions
.filter(|&(_, (h, t))| filter.filter_transaction(h, t, None))
.filter(|&(_, tx)| filter.filter_transaction(&tx.hash, &tx.raw, None))
.map(|(idx, _)| idx)
.collect();
let compact_block = types::CompactBlock {
@ -1296,9 +1296,9 @@ impl<T> SynchronizationClientCore<T> where T: TaskExecutor {
let block_header_and_ids: Vec<_> = indexed_blocks.into_iter()
.filter_map(|b| if self.peers.filter(peer_index).filter_block(&b.hash()) {
let prefilled_transactions_indexes = b.transactions().enumerate()
let prefilled_transactions_indexes = b.transactions.iter().enumerate()
// we do not filter by fee rate here, because it only reasonable for non-mined transactions
.filter(|&(_, (h, t))| self.peers.filter_mut(peer_index).filter_transaction(h, t, None))
.filter(|&(_, tx)| self.peers.filter_mut(peer_index).filter_transaction(&tx.hash, &tx.raw, None))
.map(|(idx, _)| idx)
.collect();
Some(build_compact_block(b, prefilled_transactions_indexes))

View File

@ -78,8 +78,8 @@ impl ChainVerifier {
// strict pay-to-script-hash signature operations count toward block
// signature operations limit is enforced with BIP16
let store = StoreWithUnretainedOutputs::new(&self.store, block);
let bip16_active = self.verify_p2sh(block.header().time);
block.transactions().map(|(_, tx)| transaction_sigops(tx, &store, bip16_active)).sum()
let bip16_active = self.verify_p2sh(block.header.raw.time);
block.transactions.iter().map(|tx| transaction_sigops(&tx.raw, &store, bip16_active)).sum()
}
fn ordered_verify(&self, block: &db::IndexedBlock, at_height: u32) -> Result<(), Error> {
@ -98,28 +98,24 @@ impl ChainVerifier {
//if let Some(work) = self.work_required(block, at_height) {
if at_height != 0 && !self.skip_pow {
let work = utils::work_required(
block.header().previous_header_hash.clone(),
block.header().time,
block.header.raw.previous_header_hash.clone(),
block.header.raw.time,
at_height,
self.store.as_block_header_provider(),
self.network
);
if !self.skip_pow && work != block.header().bits {
if !self.skip_pow && work != block.header.raw.bits {
trace!(target: "verification", "pow verification error at height: {}", at_height);
trace!(target: "verification", "expected work: {:?}, got {:?}", work, block.header().bits);
trace!(target: "verification", "expected work: {:?}, got {:?}", work, block.header.raw.bits);
return Err(Error::Difficulty);
}
}
let coinbase_spends = block.transactions()
.nth(0)
.expect("block emptyness should be checked at this point")
.1
.total_spends();
let coinbase_spends = block.transactions[0].raw.total_spends();
// bip30
for (tx_index, (tx_hash, _)) in block.transactions().enumerate() {
if let Some(meta) = self.store.transaction_meta(tx_hash) {
for (tx_index, tx) in block.transactions.iter().enumerate() {
if let Some(meta) = self.store.transaction_meta(&tx.hash) {
if !meta.is_fully_spent() && !self.consensus_params.is_bip30_exception(&block_hash, at_height) {
return Err(Error::Transaction(tx_index, TransactionError::UnspentTransactionWithTheSameHash));
}
@ -128,9 +124,9 @@ impl ChainVerifier {
let unretained_store = StoreWithUnretainedOutputs::new(&self.store, block);
let mut total_unspent = 0u64;
for (tx_index, (_, tx)) in block.transactions().enumerate().skip(1) {
for (tx_index, tx) in block.transactions.iter().enumerate().skip(1) {
let mut total_claimed: u64 = 0;
for input in &tx.inputs {
for input in &tx.raw.inputs {
// Coinbase maturity check
if let Some(previous_meta) = self.store.transaction_meta(&input.previous_output.hash) {
// check if it exists only
@ -147,7 +143,7 @@ impl ChainVerifier {
total_claimed += previous_output.value;
}
let total_spends = tx.total_spends();
let total_spends = tx.raw.total_spends();
if total_claimed < total_spends {
return Err(Error::Transaction(tx_index, TransactionError::Overspend));
@ -265,12 +261,12 @@ impl ChainVerifier {
let hash = block.hash();
// There should be at least 1 transaction
if block.transaction_count() == 0 {
if block.transactions.is_empty() {
return Err(Error::Empty);
}
// block header checks
try!(self.verify_block_header(self.store.as_block_header_provider(), &hash, block.header()));
try!(self.verify_block_header(self.store.as_block_header_provider(), &hash, &block.header.raw));
// todo: serialized_size function is at least suboptimal
let size = block.size();
@ -279,11 +275,11 @@ impl ChainVerifier {
}
// verify merkle root
if block.merkle_root() != block.header().merkle_root_hash {
if block.merkle_root() != block.header.raw.merkle_root_hash {
return Err(Error::MerkleRoot);
}
let first_tx = block.transactions().nth(0).expect("transaction count is checked above to be greater than 0").1;
let first_tx = &block.transactions[0].raw;
// check first transaction is a coinbase transaction
if !first_tx.is_coinbase() {
return Err(Error::Coinbase)
@ -295,19 +291,19 @@ impl ChainVerifier {
return Err(Error::CoinbaseSignatureLength(coinbase_script_len));
}
let location = match self.store.accepted_location(block.header()) {
let location = match self.store.accepted_location(&block.header.raw) {
Some(location) => location,
None => return Ok(Chain::Orphan),
};
if block.transaction_count() > TRANSACTIONS_VERIFY_PARALLEL_THRESHOLD {
if block.transactions.len() > TRANSACTIONS_VERIFY_PARALLEL_THRESHOLD {
// todo: might use on-stack vector (smallvec/elastic array)
let mut transaction_tasks: Vec<Task> = Vec::with_capacity(TRANSACTIONS_VERIFY_THREADS);
let mut last = 0;
for num_task in 0..TRANSACTIONS_VERIFY_THREADS {
let from = last;
last = ::std::cmp::max(1, block.transaction_count() / TRANSACTIONS_VERIFY_THREADS);
if num_task == TRANSACTIONS_VERIFY_THREADS - 1 { last = block.transaction_count(); };
last = ::std::cmp::max(1, block.transactions.len() / TRANSACTIONS_VERIFY_THREADS);
if num_task == TRANSACTIONS_VERIFY_THREADS - 1 { last = block.transactions.len(); };
transaction_tasks.push(Task::new(block, location.height(), from, last));
}
@ -325,8 +321,8 @@ impl ChainVerifier {
}
}
else {
for (index, (_, tx)) in block.transactions().enumerate() {
if let Err(tx_err) = self.verify_transaction(block, location.height(), block.header().time, tx, index) {
for (index, tx) in block.transactions.iter().enumerate() {
if let Err(tx_err) = self.verify_transaction(block, location.height(), block.header.raw.time, &tx.raw, index) {
return Err(Error::Transaction(index, tx_err));
}
}
@ -372,7 +368,7 @@ impl Verify for ChainVerifier {
trace!(
target: "verification", "Block {} (transactions: {}) verification finished. Result {:?}",
block.hash().to_reversed_str(),
block.transaction_count(),
block.transactions.len(),
result,
);
result

View File

@ -25,7 +25,7 @@ impl<'a> Task<'a> {
pub fn progress(&mut self, verifier: &ChainVerifier) {
for index in self.from..self.to {
if let Err(e) = verifier.verify_transaction(self.block, self.block_height, self.block.header().time, self.block.transaction_at(index).1, index) {
if let Err(e) = verifier.verify_transaction(self.block, self.block_height, self.block.header.raw.time, &self.block.transactions[index].raw, index) {
self.result = Err((index, e))
}
}