diff --git a/db/src/block_chain_db.rs b/db/src/block_chain_db.rs index 2f338e33..51946438 100644 --- a/db/src/block_chain_db.rs +++ b/db/src/block_chain_db.rs @@ -19,8 +19,8 @@ use kv::{ use best_block::BestBlock; use { BlockRef, Error, BlockHeaderProvider, BlockProvider, BlockOrigin, TransactionMeta, IndexedBlockProvider, - TransactionMetaProvider, TransactionProvider, PreviousTransactionOutputProvider, BlockChain, Store, - SideChainOrigin, ForkChain, TransactionOutputObserver, Forkable, CanonStore + TransactionMetaProvider, TransactionProvider, TransactionOutputProvider, BlockChain, Store, + SideChainOrigin, ForkChain, Forkable, CanonStore }; const COL_COUNT: u32 = 10; @@ -463,17 +463,15 @@ impl TransactionProvider for BlockChainDatabase where T: KeyValueDatabase } } -impl PreviousTransactionOutputProvider for BlockChainDatabase where T: KeyValueDatabase { - fn previous_transaction_output(&self, prevout: &OutPoint, _transaction_index: usize) -> Option { +impl TransactionOutputProvider for BlockChainDatabase where T: KeyValueDatabase { + fn transaction_output(&self, prevout: &OutPoint, _transaction_index: usize) -> Option { // return previous transaction outputs only for canon chain transactions self.transaction_meta(&prevout.hash) .and_then(|_| self.transaction(&prevout.hash)) .and_then(|tx| tx.outputs.into_iter().nth(prevout.index as usize)) } -} -impl TransactionOutputObserver for BlockChainDatabase where T: KeyValueDatabase { - fn is_spent(&self, prevout: &OutPoint) -> bool { + fn is_double_spent(&self, prevout: &OutPoint) -> bool { self.transaction_meta(&prevout.hash) .and_then(|meta| meta.is_spent(prevout.index as usize)) .unwrap_or(false) diff --git a/db/src/impls.rs b/db/src/block_impls.rs similarity index 53% rename from db/src/impls.rs rename to db/src/block_impls.rs index a53c47cd..279c6b1d 100644 --- a/db/src/impls.rs +++ b/db/src/block_impls.rs @@ -1,6 +1,6 @@ +use std::cmp; use chain::{OutPoint, TransactionOutput, IndexedBlock, IndexedTransaction}; -use transaction_provider::PreviousTransactionOutputProvider; -use transaction_meta_provider::TransactionOutputObserver; +use {TransactionOutputProvider}; fn transaction_output(transactions: &[IndexedTransaction], prevout: &OutPoint) -> Option { transactions.iter() @@ -9,7 +9,7 @@ fn transaction_output(transactions: &[IndexedTransaction], prevout: &OutPoint) - .cloned() } -fn is_spent(transactions: &[IndexedTransaction], prevout: &OutPoint) -> bool { +fn is_double_spent(transactions: &[IndexedTransaction], prevout: &OutPoint) -> bool { // the code below is valid, but has rather poor performance // if previous transaction output appears more than once than we can safely @@ -23,14 +23,13 @@ fn is_spent(transactions: &[IndexedTransaction], prevout: &OutPoint) -> bool { spends == 2 } -impl PreviousTransactionOutputProvider for IndexedBlock { - fn previous_transaction_output(&self, prevout: &OutPoint, transaction_index: usize) -> Option { - transaction_output(&self.transactions[..transaction_index], prevout) +impl TransactionOutputProvider for IndexedBlock { + fn transaction_output(&self, outpoint: &OutPoint, transaction_index: usize) -> Option { + let take = cmp::min(transaction_index, self.transactions.len()); + transaction_output(&self.transactions[..take], outpoint) } -} -impl TransactionOutputObserver for IndexedBlock { - fn is_spent(&self, prevout: &OutPoint) -> bool { - is_spent(&self.transactions, prevout) + fn is_double_spent(&self, outpoint: &OutPoint) -> bool { + is_double_spent(&self.transactions, outpoint) } } diff --git a/db/src/lib.rs b/db/src/lib.rs index c643b326..7b060415 100644 --- a/db/src/lib.rs +++ b/db/src/lib.rs @@ -17,10 +17,9 @@ mod block_ref; mod block_chain; mod block_chain_db; mod error; -mod impls; +mod block_impls; mod store; mod transaction_meta; -mod transaction_meta_provider; mod transaction_provider; pub use primitives::{hash, bytes}; @@ -34,6 +33,5 @@ pub use block_chain_db::{BlockChainDatabase, ForkChainDatabase}; pub use error::Error; pub use store::{AsSubstore, Store, SharedStore, CanonStore}; pub use transaction_meta::TransactionMeta; -pub use transaction_meta_provider::{TransactionMetaProvider, TransactionOutputObserver}; -pub use transaction_provider::{TransactionProvider, PreviousTransactionOutputProvider}; +pub use transaction_provider::{TransactionProvider, TransactionOutputProvider, TransactionMetaProvider}; diff --git a/db/src/store.rs b/db/src/store.rs index 61ae2738..ac410a9f 100644 --- a/db/src/store.rs +++ b/db/src/store.rs @@ -2,8 +2,7 @@ use std::sync::Arc; use chain::BlockHeader; use { BestBlock, BlockProvider, BlockHeaderProvider, TransactionProvider, TransactionMetaProvider, - PreviousTransactionOutputProvider, BlockChain, IndexedBlockProvider, TransactionOutputObserver, - Forkable + TransactionOutputProvider, BlockChain, IndexedBlockProvider, Forkable }; pub trait CanonStore: Store + Forkable { @@ -23,21 +22,19 @@ pub trait Store: AsSubstore { } /// Allows casting Arc to reference to any substore type -pub trait AsSubstore: BlockChain + IndexedBlockProvider + TransactionProvider + TransactionMetaProvider + PreviousTransactionOutputProvider + TransactionOutputObserver { +pub trait AsSubstore: BlockChain + IndexedBlockProvider + TransactionProvider + TransactionMetaProvider + TransactionOutputProvider { fn as_block_provider(&self) -> &BlockProvider; fn as_block_header_provider(&self) -> &BlockHeaderProvider; fn as_transaction_provider(&self) -> &TransactionProvider; - fn as_previous_transaction_output_provider(&self) -> &PreviousTransactionOutputProvider; + fn as_transaction_output_provider(&self) -> &TransactionOutputProvider; fn as_transaction_meta_provider(&self) -> &TransactionMetaProvider; - - fn as_transaction_output_observer(&self) -> &TransactionOutputObserver; } -impl AsSubstore for T where T: BlockChain + IndexedBlockProvider + TransactionProvider + TransactionMetaProvider + PreviousTransactionOutputProvider + TransactionOutputObserver { +impl AsSubstore for T where T: BlockChain + IndexedBlockProvider + TransactionProvider + TransactionMetaProvider + TransactionOutputProvider { fn as_block_provider(&self) -> &BlockProvider { &*self } @@ -50,17 +47,13 @@ impl AsSubstore for T where T: BlockChain + IndexedBlockProvider + Transactio &*self } - fn as_previous_transaction_output_provider(&self) -> &PreviousTransactionOutputProvider { + fn as_transaction_output_provider(&self) -> &TransactionOutputProvider { &*self } fn as_transaction_meta_provider(&self) -> &TransactionMetaProvider { &*self } - - fn as_transaction_output_observer(&self) -> &TransactionOutputObserver { - &*self - } } pub type SharedStore = Arc; diff --git a/db/src/transaction_meta_provider.rs b/db/src/transaction_meta_provider.rs deleted file mode 100644 index 9f107ea5..00000000 --- a/db/src/transaction_meta_provider.rs +++ /dev/null @@ -1,16 +0,0 @@ -use primitives::hash::H256; -use chain::OutPoint; -use transaction_meta::TransactionMeta; - -/// Transaction output observers track if output has been spent -pub trait TransactionOutputObserver: Send + Sync { - /// Returns true if we know that output has been spent - fn is_spent(&self, prevout: &OutPoint) -> bool; -} - -/// Transaction meta provider stores transaction meta information -pub trait TransactionMetaProvider: Send + Sync { - /// Returns None if transactin with given hash does not exist - /// Otherwise returns transaction meta object - fn transaction_meta(&self, hash: &H256) -> Option; -} diff --git a/db/src/transaction_provider.rs b/db/src/transaction_provider.rs index 68e4c0ab..6ad2b8a3 100644 --- a/db/src/transaction_provider.rs +++ b/db/src/transaction_provider.rs @@ -1,23 +1,34 @@ use hash::H256; use bytes::Bytes; use chain::{Transaction, OutPoint, TransactionOutput}; +use {TransactionMeta}; +/// Should be used to obtain all transactions from canon chain and forks. pub trait TransactionProvider { - /// returns true if store contains given transaction + /// Returns true if store contains given transaction. fn contains_transaction(&self, hash: &H256) -> bool { self.transaction(hash).is_some() } - /// resolves transaction body bytes by transaction hash + /// Resolves transaction body bytes by transaction hash. fn transaction_bytes(&self, hash: &H256) -> Option; - /// resolves serialized transaction info by transaction hash + /// Resolves serialized transaction info by transaction hash. fn transaction(&self, hash: &H256) -> Option; } -/// During transaction verifiction the only part of old transaction that we need is `TransactionOutput`. -/// Structures like `IndexedBlock` or `MemoryPool` already have it in memory, so it would be -/// a shame to clone the whole transaction just to get single output. -pub trait PreviousTransactionOutputProvider: Send + Sync { - fn previous_transaction_output(&self, prevout: &OutPoint, transaction_index: usize) -> Option; +/// Should be used to get canon chain transaction outputs. +pub trait TransactionOutputProvider: Send + Sync { + /// Returns transaction output. + fn transaction_output(&self, outpoint: &OutPoint, transaction_index: usize) -> Option; + + /// Returns true if we know that output is double spent. + fn is_double_spent(&self, outpoint: &OutPoint) -> bool; +} + +/// Transaction meta provider stores transaction meta information +pub trait TransactionMetaProvider: Send + Sync { + /// Returns None if transactin with given hash does not exist + /// Otherwise returns transaction meta object + fn transaction_meta(&self, hash: &H256) -> Option; } diff --git a/miner/src/block_assembler.rs b/miner/src/block_assembler.rs index 3894eff5..06afa215 100644 --- a/miner/src/block_assembler.rs +++ b/miner/src/block_assembler.rs @@ -2,7 +2,7 @@ use std::collections::HashSet; use primitives::hash::H256; use primitives::compact::Compact; use chain::{OutPoint, TransactionOutput, IndexedTransaction}; -use db::{SharedStore, PreviousTransactionOutputProvider}; +use db::{SharedStore, TransactionOutputProvider}; use network::Magic; use memory_pool::{MemoryPool, OrderingStrategy, Entry}; use verification::{work_required, block_reward_satoshi, transaction_sigops}; @@ -133,7 +133,7 @@ impl Default for BlockAssembler { /// Iterator iterating over mempool transactions and yielding only those which fit the block struct FittingTransactionsIterator<'a, T> { /// Shared store is used to query previous transaction outputs from database - store: &'a PreviousTransactionOutputProvider, + store: &'a TransactionOutputProvider, /// Memory pool transactions iterator iter: T, /// New block height @@ -153,7 +153,7 @@ struct FittingTransactionsIterator<'a, T> { } impl<'a, T> FittingTransactionsIterator<'a, T> where T: Iterator { - fn new(store: &'a PreviousTransactionOutputProvider, iter: T, max_block_size: u32, max_block_sigops: u32, block_height: u32, block_time: u32) -> Self { + fn new(store: &'a TransactionOutputProvider, iter: T, max_block_size: u32, max_block_sigops: u32, block_height: u32, block_time: u32) -> Self { FittingTransactionsIterator { store: store, iter: iter, @@ -169,9 +169,9 @@ impl<'a, T> FittingTransactionsIterator<'a, T> where T: Iterator PreviousTransactionOutputProvider for FittingTransactionsIterator<'a, T> where T: Send + Sync { - fn previous_transaction_output(&self, prevout: &OutPoint, transaction_index: usize) -> Option { - self.store.previous_transaction_output(prevout, transaction_index) +impl<'a, T> TransactionOutputProvider for FittingTransactionsIterator<'a, T> where T: Send + Sync { + fn transaction_output(&self, prevout: &OutPoint, transaction_index: usize) -> Option { + self.store.transaction_output(prevout, transaction_index) .or_else(|| { self.previous_entries.iter() .find(|e| e.hash == prevout.hash) @@ -179,6 +179,10 @@ impl<'a, T> PreviousTransactionOutputProvider for FittingTransactionsIterator<'a .cloned() }) } + + fn is_double_spent(&self, _outpoint: &OutPoint) -> bool { + unimplemented!(); + } } impl<'a, T> Iterator for FittingTransactionsIterator<'a, T> where T: Iterator + Send + Sync { @@ -252,7 +256,7 @@ impl BlockAssembler { let mut transactions = Vec::new(); let mempool_iter = mempool.iter(OrderingStrategy::ByTransactionScore); - let tx_iter = FittingTransactionsIterator::new(store.as_previous_transaction_output_provider(), mempool_iter, self.max_block_size, self.max_block_sigops, height, time); + let tx_iter = FittingTransactionsIterator::new(store.as_transaction_output_provider(), mempool_iter, self.max_block_size, self.max_block_sigops, height, time); for entry in tx_iter { // miner_fee is i64, but we can safely cast it to u64 // memory pool should restrict miner fee to be positive diff --git a/miner/src/memory_pool.rs b/miner/src/memory_pool.rs index 40166e40..b9634aae 100644 --- a/miner/src/memory_pool.rs +++ b/miner/src/memory_pool.rs @@ -5,7 +5,7 @@ //! transactions. //! It also guarantees that ancestor-descendant relation won't break during ordered removal (ancestors always removed //! before descendants). Removal using `remove_by_hash` can break this rule. -use db::{TransactionProvider, PreviousTransactionOutputProvider}; +use db::{TransactionProvider, TransactionOutputProvider}; use primitives::bytes::Bytes; use primitives::hash::H256; use chain::{IndexedTransaction, Transaction, OutPoint, TransactionOutput}; @@ -812,12 +812,16 @@ impl TransactionProvider for MemoryPool { } } -impl PreviousTransactionOutputProvider for MemoryPool { - fn previous_transaction_output(&self, prevout: &OutPoint, _transaction_index: usize) -> Option { +impl TransactionOutputProvider for MemoryPool { + fn transaction_output(&self, prevout: &OutPoint, _transaction_index: usize) -> Option { self.get(&prevout.hash) .and_then(|tx| tx.outputs.get(prevout.index as usize)) .cloned() } + + fn is_double_spent(&self, outpoint: &OutPoint) -> bool { + self.is_spent(outpoint) + } } impl HeapSizeOf for MemoryPool { diff --git a/sync/src/utils/memory_pool_transaction_provider.rs b/sync/src/utils/memory_pool_transaction_provider.rs index 5a12575d..32b03cda 100644 --- a/sync/src/utils/memory_pool_transaction_provider.rs +++ b/sync/src/utils/memory_pool_transaction_provider.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; use chain::{Transaction, TransactionOutput, OutPoint}; -use db::{PreviousTransactionOutputProvider, TransactionOutputObserver}; +use db::TransactionOutputProvider; use miner::{DoubleSpendCheckResult, HashedOutPoint, NonFinalDoubleSpendSet}; use verification::TransactionError; use super::super::types::{MemoryPoolRef, StorageRef}; @@ -32,7 +32,7 @@ impl MemoryPoolTransactionOutputProvider { mempool_inputs: transaction.inputs.iter() .map(|input| ( input.previous_output.clone().into(), - memory_pool.previous_transaction_output(&input.previous_output, usize::max_value()), + memory_pool.transaction_output(&input.previous_output, usize::max_value()), )).collect(), nonfinal_spends: None, }), @@ -42,7 +42,7 @@ impl MemoryPoolTransactionOutputProvider { mempool_inputs: transaction.inputs.iter() .map(|input| ( input.previous_output.clone().into(), - memory_pool.previous_transaction_output(&input.previous_output, usize::max_value()), + memory_pool.transaction_output(&input.previous_output, usize::max_value()), )).collect(), nonfinal_spends: Some(nonfinal_spends), }), @@ -50,23 +50,8 @@ impl MemoryPoolTransactionOutputProvider { } } -impl TransactionOutputObserver for MemoryPoolTransactionOutputProvider { - fn is_spent(&self, prevout: &OutPoint) -> bool { - // check if this output is spent by some non-final mempool transaction - if let Some(ref nonfinal_spends) = self.nonfinal_spends { - if nonfinal_spends.double_spends.contains(&prevout.clone().into()) { - return false; - } - } - - // we can omit memory_pool check here, because it has been completed in `for_transaction` method - // => just check spending in storage - self.storage_provider.is_spent(prevout) - } -} - -impl PreviousTransactionOutputProvider for MemoryPoolTransactionOutputProvider { - fn previous_transaction_output(&self, prevout: &OutPoint, transaction_index: usize) -> Option { +impl TransactionOutputProvider for MemoryPoolTransactionOutputProvider { + fn transaction_output(&self, prevout: &OutPoint, transaction_index: usize) -> Option { let hashed_prevout: HashedOutPoint = prevout.clone().into(); // check if that is output of some transaction, which is vitually removed from memory pool @@ -87,7 +72,20 @@ impl PreviousTransactionOutputProvider for MemoryPoolTransactionOutputProvider { } // now check in storage - self.storage_provider.previous_transaction_output(prevout, transaction_index) + self.storage_provider.transaction_output(prevout, transaction_index) + } + + fn is_double_spent(&self, prevout: &OutPoint) -> bool { + // check if this output is spent by some non-final mempool transaction + if let Some(ref nonfinal_spends) = self.nonfinal_spends { + if nonfinal_spends.double_spends.contains(&prevout.clone().into()) { + return false; + } + } + + // we can omit memory_pool check here, because it has been completed in `for_transaction` method + // => just check spending in storage + self.storage_provider.is_double_spent(prevout) } } @@ -96,7 +94,7 @@ mod tests { use std::sync::Arc; use parking_lot::RwLock; use chain::OutPoint; - use db::{TransactionOutputObserver, PreviousTransactionOutputProvider, BlockChainDatabase}; + use db::{TransactionOutputProvider, BlockChainDatabase}; use miner::MemoryPool; use test_data; use super::MemoryPoolTransactionOutputProvider; @@ -128,11 +126,11 @@ mod tests { // => // if t3 is also depending on t1[0] || t2[0], it will be rejected by verification as missing inputs let provider = MemoryPoolTransactionOutputProvider::for_transaction(storage, &memory_pool, &dchain.at(3)).unwrap(); - assert_eq!(provider.is_spent(&OutPoint { hash: dchain.at(0).hash(), index: 0, }), false); - assert_eq!(provider.is_spent(&OutPoint { hash: dchain.at(1).hash(), index: 0, }), false); - assert_eq!(provider.is_spent(&OutPoint { hash: dchain.at(2).hash(), index: 0, }), false); - assert_eq!(provider.previous_transaction_output(&OutPoint { hash: dchain.at(0).hash(), index: 0, }, 0), Some(dchain.at(0).outputs[0].clone())); - assert_eq!(provider.previous_transaction_output(&OutPoint { hash: dchain.at(1).hash(), index: 0, }, 0), None); - assert_eq!(provider.previous_transaction_output(&OutPoint { hash: dchain.at(2).hash(), index: 0, }, 0), None); + assert_eq!(provider.is_double_spent(&OutPoint { hash: dchain.at(0).hash(), index: 0, }), false); + assert_eq!(provider.is_double_spent(&OutPoint { hash: dchain.at(1).hash(), index: 0, }), false); + assert_eq!(provider.is_double_spent(&OutPoint { hash: dchain.at(2).hash(), index: 0, }), false); + assert_eq!(provider.transaction_output(&OutPoint { hash: dchain.at(0).hash(), index: 0, }, 0), Some(dchain.at(0).outputs[0].clone())); + assert_eq!(provider.transaction_output(&OutPoint { hash: dchain.at(1).hash(), index: 0, }, 0), None); + assert_eq!(provider.transaction_output(&OutPoint { hash: dchain.at(2).hash(), index: 0, }, 0), None); } } diff --git a/verification/src/accept_block.rs b/verification/src/accept_block.rs index 72598e05..46ba6480 100644 --- a/verification/src/accept_block.rs +++ b/verification/src/accept_block.rs @@ -1,5 +1,5 @@ use network::{Magic, ConsensusParams}; -use db::PreviousTransactionOutputProvider; +use db::TransactionOutputProvider; use sigops::transaction_sigops; use work::block_reward_satoshi; use duplex_store::DuplexTransactionOutputProvider; @@ -15,7 +15,7 @@ pub struct BlockAcceptor<'a> { } impl<'a> BlockAcceptor<'a> { - pub fn new(store: &'a PreviousTransactionOutputProvider, network: Magic, block: CanonBlock<'a>, height: u32) -> Self { + pub fn new(store: &'a TransactionOutputProvider, network: Magic, block: CanonBlock<'a>, height: u32) -> Self { let params = network.consensus_params(); BlockAcceptor { finality: BlockFinality::new(block, height), @@ -56,13 +56,13 @@ impl<'a> BlockFinality<'a> { pub struct BlockSigops<'a> { block: CanonBlock<'a>, - store: &'a PreviousTransactionOutputProvider, + store: &'a TransactionOutputProvider, consensus_params: ConsensusParams, max_sigops: usize, } impl<'a> BlockSigops<'a> { - fn new(block: CanonBlock<'a>, store: &'a PreviousTransactionOutputProvider, consensus_params: ConsensusParams, max_sigops: usize) -> Self { + fn new(block: CanonBlock<'a>, store: &'a TransactionOutputProvider, consensus_params: ConsensusParams, max_sigops: usize) -> Self { BlockSigops { block: block, store: store, @@ -88,12 +88,12 @@ impl<'a> BlockSigops<'a> { pub struct BlockCoinbaseClaim<'a> { block: CanonBlock<'a>, - store: &'a PreviousTransactionOutputProvider, + store: &'a TransactionOutputProvider, height: u32, } impl<'a> BlockCoinbaseClaim<'a> { - fn new(block: CanonBlock<'a>, store: &'a PreviousTransactionOutputProvider, height: u32) -> Self { + fn new(block: CanonBlock<'a>, store: &'a TransactionOutputProvider, height: u32) -> Self { BlockCoinbaseClaim { block: block, store: store, @@ -111,7 +111,7 @@ impl<'a> BlockCoinbaseClaim<'a> { let mut incoming: u64 = 0; for input in tx.raw.inputs.iter() { let (sum, overflow) = incoming.overflowing_add( - store.previous_transaction_output(&input.previous_output, tx_idx).map(|o| o.value).unwrap_or(0)); + store.transaction_output(&input.previous_output, tx_idx).map(|o| o.value).unwrap_or(0)); if overflow { return Err(Error::ReferencedInputsSumOverflow); } diff --git a/verification/src/accept_chain.rs b/verification/src/accept_chain.rs index e6f8f9af..28306ca4 100644 --- a/verification/src/accept_chain.rs +++ b/verification/src/accept_chain.rs @@ -6,7 +6,7 @@ use canon::CanonBlock; use accept_block::BlockAcceptor; use accept_header::HeaderAcceptor; use accept_transaction::TransactionAcceptor; -use duplex_store::{DuplexTransactionOutputProvider, DuplexTransactionOutputObserver}; +use duplex_store::DuplexTransactionOutputProvider; pub struct ChainAcceptor<'a> { pub block: BlockAcceptor<'a>, @@ -17,18 +17,16 @@ pub struct ChainAcceptor<'a> { impl<'a> ChainAcceptor<'a> { pub fn new(store: &'a Store, network: Magic, block: CanonBlock<'a>, height: u32) -> Self { trace!(target: "verification", "Block verification {}", block.hash().to_reversed_str()); - let prevouts = DuplexTransactionOutputProvider::new(store.as_previous_transaction_output_provider(), block.raw()); - let spents = DuplexTransactionOutputObserver::new(store.as_transaction_output_observer(), block.raw()); + let output_store = DuplexTransactionOutputProvider::new(store.as_transaction_output_provider(), block.raw()); ChainAcceptor { - block: BlockAcceptor::new(store.as_previous_transaction_output_provider(), network, block, height), + block: BlockAcceptor::new(store.as_transaction_output_provider(), network, block, height), header: HeaderAcceptor::new(store.as_block_header_provider(), network, block.header(), height), transactions: block.transactions() .into_iter() .enumerate() .map(|(tx_index, tx)| TransactionAcceptor::new( store.as_transaction_meta_provider(), - prevouts, - spents, + output_store, network, tx, block.hash(), diff --git a/verification/src/accept_transaction.rs b/verification/src/accept_transaction.rs index edb85900..5daf0da4 100644 --- a/verification/src/accept_transaction.rs +++ b/verification/src/accept_transaction.rs @@ -1,8 +1,8 @@ use primitives::hash::H256; -use db::{TransactionMetaProvider, PreviousTransactionOutputProvider, TransactionOutputObserver}; +use db::{TransactionMetaProvider, TransactionOutputProvider}; use network::{Magic, ConsensusParams}; use script::{Script, verify_script, VerificationFlags, TransactionSignatureChecker, TransactionInputSigner}; -use duplex_store::{DuplexTransactionOutputProvider, DuplexTransactionOutputObserver}; +use duplex_store::DuplexTransactionOutputProvider; use sigops::transaction_sigops; use canon::CanonTransaction; use constants::{COINBASE_MATURITY, MAX_BLOCK_SIGOPS}; @@ -23,10 +23,7 @@ impl<'a> TransactionAcceptor<'a> { meta_store: &'a TransactionMetaProvider, // previous transaction outputs // in case of block validation, that's database and currently processed block - prevout_store: DuplexTransactionOutputProvider<'a>, - // in case of block validation, that's database and currently processed block - //spent_store: &'a TransactionOutputObserver, - spent_store: DuplexTransactionOutputObserver<'a>, + output_store: DuplexTransactionOutputProvider<'a>, network: Magic, transaction: CanonTransaction<'a>, block_hash: &'a H256, @@ -38,11 +35,11 @@ impl<'a> TransactionAcceptor<'a> { let params = network.consensus_params(); TransactionAcceptor { bip30: TransactionBip30::new_for_sync(transaction, meta_store, params.clone(), block_hash, height), - missing_inputs: TransactionMissingInputs::new(transaction, prevout_store, transaction_index), + missing_inputs: TransactionMissingInputs::new(transaction, output_store, transaction_index), maturity: TransactionMaturity::new(transaction, meta_store, height), - overspent: TransactionOverspent::new(transaction, prevout_store), - double_spent: TransactionDoubleSpend::new(transaction, spent_store), - eval: TransactionEval::new(transaction, prevout_store, params, height, time), + overspent: TransactionOverspent::new(transaction, output_store), + double_spent: TransactionDoubleSpend::new(transaction, output_store), + eval: TransactionEval::new(transaction, output_store, params, height, time), } } @@ -71,10 +68,7 @@ impl<'a> MemoryPoolTransactionAcceptor<'a> { // TODO: in case of memory pool it should be db and memory pool meta_store: &'a TransactionMetaProvider, // in case of memory pool it should be db and memory pool - prevout_store: DuplexTransactionOutputProvider<'a>, - // in case of memory pool it should be db and memory pool - //spent_store: &'a TransactionOutputObserver, - spent_store: DuplexTransactionOutputObserver<'a>, + output_store: DuplexTransactionOutputProvider<'a>, network: Magic, transaction: CanonTransaction<'a>, height: u32, @@ -84,12 +78,12 @@ impl<'a> MemoryPoolTransactionAcceptor<'a> { let params = network.consensus_params(); let transaction_index = 0; MemoryPoolTransactionAcceptor { - missing_inputs: TransactionMissingInputs::new(transaction, prevout_store, transaction_index), + missing_inputs: TransactionMissingInputs::new(transaction, output_store, transaction_index), maturity: TransactionMaturity::new(transaction, meta_store, height), - overspent: TransactionOverspent::new(transaction, prevout_store), - sigops: TransactionSigops::new(transaction, prevout_store, params.clone(), MAX_BLOCK_SIGOPS, time), - double_spent: TransactionDoubleSpend::new(transaction, spent_store), - eval: TransactionEval::new(transaction, prevout_store, params, height, time), + overspent: TransactionOverspent::new(transaction, output_store), + sigops: TransactionSigops::new(transaction, output_store, params.clone(), MAX_BLOCK_SIGOPS, time), + double_spent: TransactionDoubleSpend::new(transaction, output_store), + eval: TransactionEval::new(transaction, output_store, params, height, time), } } @@ -167,7 +161,7 @@ impl<'a> TransactionMissingInputs<'a> { let missing_index = self.transaction.raw.inputs.iter() .position(|input| { let is_not_null = !input.previous_output.is_null(); - let is_missing = self.store.previous_transaction_output(&input.previous_output, self.transaction_index).is_none(); + let is_missing = self.store.transaction_output(&input.previous_output, self.transaction_index).is_none(); is_not_null && is_missing }); @@ -228,7 +222,7 @@ impl<'a> TransactionOverspent<'a> { } let available = self.transaction.raw.inputs.iter() - .map(|input| self.store.previous_transaction_output(&input.previous_output, usize::max_value()).map(|o| o.value).unwrap_or(0)) + .map(|input| self.store.transaction_output(&input.previous_output, usize::max_value()).map(|o| o.value).unwrap_or(0)) .sum::(); let spends = self.transaction.raw.total_spends(); @@ -310,7 +304,7 @@ impl<'a> TransactionEval<'a> { }; for (index, input) in self.transaction.raw.inputs.iter().enumerate() { - let output = self.store.previous_transaction_output(&input.previous_output, usize::max_value()) + let output = self.store.transaction_output(&input.previous_output, usize::max_value()) .ok_or_else(|| TransactionError::UnknownReference(input.previous_output.hash.clone()))?; checker.input_index = index; @@ -331,13 +325,11 @@ impl<'a> TransactionEval<'a> { pub struct TransactionDoubleSpend<'a> { transaction: CanonTransaction<'a>, - //store: &'a TransactionOutputObserver, - store: DuplexTransactionOutputObserver<'a>, + store: DuplexTransactionOutputProvider<'a>, } impl<'a> TransactionDoubleSpend<'a> { - //fn new(transaction: CanonTransaction<'a>, store: &'a TransactionOutputObserver) -> Self { - fn new(transaction: CanonTransaction<'a>, store: DuplexTransactionOutputObserver<'a>) -> Self { + fn new(transaction: CanonTransaction<'a>, store: DuplexTransactionOutputProvider<'a>) -> Self { TransactionDoubleSpend { transaction: transaction, store: store, @@ -346,7 +338,7 @@ impl<'a> TransactionDoubleSpend<'a> { fn check(&self) -> Result<(), TransactionError> { for input in &self.transaction.raw.inputs { - if self.store.is_spent(&input.previous_output) { + if self.store.is_double_spent(&input.previous_output) { return Err(TransactionError::UsingSpentOutput( input.previous_output.hash.clone(), input.previous_output.index diff --git a/verification/src/chain_verifier.rs b/verification/src/chain_verifier.rs index 685b3e50..6330b885 100644 --- a/verification/src/chain_verifier.rs +++ b/verification/src/chain_verifier.rs @@ -2,14 +2,11 @@ use hash::H256; use chain::{IndexedBlock, IndexedBlockHeader, BlockHeader, Transaction}; -use db::{ - SharedStore, PreviousTransactionOutputProvider, BlockHeaderProvider, TransactionOutputObserver, - BlockOrigin -}; +use db::{SharedStore, TransactionOutputProvider, BlockHeaderProvider, BlockOrigin}; use network::Magic; use error::{Error, TransactionError}; use canon::{CanonBlock, CanonTransaction}; -use duplex_store::{DuplexTransactionOutputObserver, DuplexTransactionOutputProvider, NoopStore}; +use duplex_store::{DuplexTransactionOutputProvider, NoopStore}; use verify_chain::ChainVerifier; use verify_header::HeaderVerifier; use verify_transaction::MemoryPoolTransactionVerifier; @@ -89,7 +86,7 @@ impl BackwardsCompatibleChainVerifier { height: u32, time: u32, transaction: &Transaction, - ) -> Result<(), TransactionError> where T: PreviousTransactionOutputProvider + TransactionOutputObserver { + ) -> Result<(), TransactionError> where T: TransactionOutputProvider { let indexed_tx = transaction.clone().into(); // let's do preverification first let tx_verifier = MemoryPoolTransactionVerifier::new(&indexed_tx); @@ -98,12 +95,10 @@ impl BackwardsCompatibleChainVerifier { let canon_tx = CanonTransaction::new(&indexed_tx); // now let's do full verification let noop = NoopStore; - let prevouts = DuplexTransactionOutputProvider::new(prevout_provider, &noop); - let spents = DuplexTransactionOutputObserver::new(prevout_provider, &noop); + let output_store = DuplexTransactionOutputProvider::new(prevout_provider, &noop); let tx_acceptor = MemoryPoolTransactionAcceptor::new( self.store.as_transaction_meta_provider(), - prevouts, - spents, + output_store, self.network, canon_tx, height, diff --git a/verification/src/duplex_store.rs b/verification/src/duplex_store.rs index 31ab8614..ecae4647 100644 --- a/verification/src/duplex_store.rs +++ b/verification/src/duplex_store.rs @@ -2,16 +2,16 @@ //! require sophisticated (in more than one source) previous transaction lookups use chain::{OutPoint, TransactionOutput}; -use db::{PreviousTransactionOutputProvider, TransactionOutputObserver}; +use db::TransactionOutputProvider; #[derive(Clone, Copy)] pub struct DuplexTransactionOutputProvider<'a> { - first: &'a PreviousTransactionOutputProvider, - second: &'a PreviousTransactionOutputProvider, + first: &'a TransactionOutputProvider, + second: &'a TransactionOutputProvider, } impl<'a> DuplexTransactionOutputProvider<'a> { - pub fn new(first: &'a PreviousTransactionOutputProvider, second: &'a PreviousTransactionOutputProvider) -> Self { + pub fn new(first: &'a TransactionOutputProvider, second: &'a TransactionOutputProvider) -> Self { DuplexTransactionOutputProvider { first: first, second: second, @@ -19,44 +19,25 @@ impl<'a> DuplexTransactionOutputProvider<'a> { } } -impl<'a> PreviousTransactionOutputProvider for DuplexTransactionOutputProvider<'a> { - fn previous_transaction_output(&self, prevout: &OutPoint, transaction_index: usize) -> Option { - self.first.previous_transaction_output(prevout, transaction_index) - .or_else(|| self.second.previous_transaction_output(prevout, transaction_index)) +impl<'a> TransactionOutputProvider for DuplexTransactionOutputProvider<'a> { + fn transaction_output(&self, prevout: &OutPoint, transaction_index: usize) -> Option { + self.first.transaction_output(prevout, transaction_index) + .or_else(|| self.second.transaction_output(prevout, transaction_index)) } -} -#[derive(Clone, Copy)] -pub struct DuplexTransactionOutputObserver<'a> { - first: &'a TransactionOutputObserver, - second: &'a TransactionOutputObserver, -} - -impl<'a> DuplexTransactionOutputObserver<'a> { - pub fn new(first: &'a TransactionOutputObserver, second: &'a TransactionOutputObserver) -> Self { - DuplexTransactionOutputObserver { - first: first, - second: second, - } - } -} - -impl<'a> TransactionOutputObserver for DuplexTransactionOutputObserver<'a> { - fn is_spent(&self, prevout: &OutPoint) -> bool { - self.first.is_spent(prevout) || self.second.is_spent(prevout) + fn is_double_spent(&self, prevout: &OutPoint) -> bool { + self.first.is_double_spent(prevout) || self.second.is_double_spent(prevout) } } pub struct NoopStore; -impl PreviousTransactionOutputProvider for NoopStore { - fn previous_transaction_output(&self, _prevout: &OutPoint, _transaction_index: usize) -> Option { +impl TransactionOutputProvider for NoopStore { + fn transaction_output(&self, _prevout: &OutPoint, _transaction_index: usize) -> Option { None } -} -impl TransactionOutputObserver for NoopStore { - fn is_spent(&self, _prevout: &OutPoint) -> bool { + fn is_double_spent(&self, _prevout: &OutPoint) -> bool { false } } diff --git a/verification/src/sigops.rs b/verification/src/sigops.rs index 7dc5d770..cf9e2e16 100644 --- a/verification/src/sigops.rs +++ b/verification/src/sigops.rs @@ -1,5 +1,5 @@ use chain::Transaction; -use db::PreviousTransactionOutputProvider; +use db::TransactionOutputProvider; use script::Script; /// Counts signature operations in given transaction @@ -8,7 +8,7 @@ use script::Script; /// missing, we simply ignore that fact and just carry on counting pub fn transaction_sigops( transaction: &Transaction, - store: &PreviousTransactionOutputProvider, + store: &TransactionOutputProvider, bip16_active: bool ) -> usize { let output_sigops: usize = transaction.outputs.iter().map(|output| { @@ -27,7 +27,7 @@ pub fn transaction_sigops( let input_script: Script = input.script_sig.clone().into(); input_sigops += input_script.sigops_count(false); if bip16_active { - let previous_output = match store.previous_transaction_output(&input.previous_output, usize::max_value()) { + let previous_output = match store.transaction_output(&input.previous_output, usize::max_value()) { Some(output) => output, None => continue, };