refactor indexed_block, avoid unnecessery copying
This commit is contained in:
parent
da80c69a80
commit
4204f8b1b9
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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 => (),
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue