From 4204f8b1b9148b9b0f40b6c3e343ba82f8d0b459 Mon Sep 17 00:00:00 2001 From: debris Date: Fri, 9 Dec 2016 15:43:00 +0100 Subject: [PATCH] refactor indexed_block, avoid unnecessery copying --- db/src/indexed_block.rs | 146 ++++++----------------------- db/src/indexed_header.rs | 26 +++++ db/src/indexed_transaction.rs | 20 ++-- db/src/lib.rs | 6 +- db/src/storage.rs | 53 ++++++----- db/src/test_storage.rs | 2 +- miner/src/block_assembler.rs | 11 +-- sync/src/compact_block_builder.rs | 14 +-- sync/src/synchronization_chain.rs | 10 +- sync/src/synchronization_client.rs | 8 +- verification/src/chain_verifier.rs | 50 +++++----- verification/src/task.rs | 2 +- 12 files changed, 146 insertions(+), 202 deletions(-) create mode 100644 db/src/indexed_header.rs diff --git a/db/src/indexed_block.rs b/db/src/indexed_block.rs index ad178160..b11061c7 100644 --- a/db/src/indexed_block.rs +++ b/db/src/indexed_block.rs @@ -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, - // guaranteed to be the same length as transactions - transaction_hashes: Vec, + pub header: IndexedBlockHeader, + pub transactions: Vec, } impl PreviousTransactionOutputProvider for IndexedBlock { - fn previous_transaction_output(&self, prevout: &chain::OutPoint) -> Option { - self.transaction(&prevout.hash) - .and_then(|tx| tx.outputs.get(prevout.index as usize)) - .cloned() + fn previous_transaction_output(&self, prevout: &OutPoint) -> Option { + 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 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 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) -> 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::(); + 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::>()) } 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)) } } diff --git a/db/src/indexed_header.rs b/db/src/indexed_header.rs new file mode 100644 index 00000000..df117833 --- /dev/null +++ b/db/src/indexed_header.rs @@ -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 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, + } + } +} diff --git a/db/src/indexed_transaction.rs b/db/src/indexed_transaction.rs index 14aaf100..950566f3 100644 --- a/db/src/indexed_transaction.rs +++ b/db/src/indexed_transaction.rs @@ -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 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 { 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 { diff --git a/db/src/lib.rs b/db/src/lib.rs index 6ee59779..56f107ba 100644 --- a/db/src/lib.rs +++ b/db/src/lib.rs @@ -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; diff --git a/db/src/storage.rs b/db/src/storage.rs index bd675d25..0032a1ff 100644 --- a/db/src/storage.rs +++ b/db/src/storage.rs @@ -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 { 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::>(); - 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); diff --git a/db/src/test_storage.rs b/db/src/test_storage.rs index 8fdd9d9e..d95af684 100644 --- a/db/src/test_storage.rs +++ b/db/src/test_storage.rs @@ -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 { - self.insert_block(&block.to_block()) + self.insert_block(&block.clone().to_raw_block()) } fn insert_block(&self, block: &chain::Block) -> Result { diff --git a/miner/src/block_assembler.rs b/miner/src/block_assembler.rs index 9d29b83a..de9a76c7 100644 --- a/miner/src/block_assembler.rs +++ b/miner/src/block_assembler.rs @@ -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 => (), diff --git a/sync/src/compact_block_builder.rs b/sync/src/compact_block_builder.rs index 78d54b61..3084f337 100644 --- a/sync/src/compact_block_builder.rs +++ b/sync/src/compact_block_builder.rs @@ -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 = Vec::with_capacity(block.transaction_count() - prefilled_transactions_len); + let mut short_ids: Vec = Vec::with_capacity(block.transactions.len() - prefilled_transactions_len); let mut prefilled_transactions: Vec = 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, diff --git a/sync/src/synchronization_chain.rs b/sync/src/synchronization_chain.rs index 0e049481..2c7ccc03 100644 --- a/sync/src/synchronization_chain.rs +++ b/sync/src/synchronization_chain.rs @@ -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 = block.transaction_hashes().iter().cloned().collect(); + let this_block_transactions_hashes = block.transactions.iter().map(|tx| tx.hash.clone()).collect::>(); let mut canonized_blocks_hashes: Vec = Vec::new(); let mut new_main_blocks_transactions_hashes: Vec = Vec::new(); while let Some(canonized_block_hash) = reorganization.pop_canonized() { diff --git a/sync/src/synchronization_client.rs b/sync/src/synchronization_client.rs index 437a08ee..954970f9 100644 --- a/sync/src/synchronization_client.rs +++ b/sync/src/synchronization_client.rs @@ -583,9 +583,9 @@ impl ClientCore for SynchronizationClientCore 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 SynchronizationClientCore 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)) diff --git a/verification/src/chain_verifier.rs b/verification/src/chain_verifier.rs index 27597119..d7f6e333 100644 --- a/verification/src/chain_verifier.rs +++ b/verification/src/chain_verifier.rs @@ -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 = 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 diff --git a/verification/src/task.rs b/verification/src/task.rs index 0a7d8bb3..f13c070d 100644 --- a/verification/src/task.rs +++ b/verification/src/task.rs @@ -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)) } }