From 56e4e540745502d004dc4c7f0fdc92fd1d9a5ea9 Mon Sep 17 00:00:00 2001 From: debris Date: Sat, 10 Dec 2016 22:34:04 +0100 Subject: [PATCH] Transaction Output Observer --- db/src/indexed_block.rs | 8 +++++++- db/src/lib.rs | 2 +- db/src/transaction_meta_provider.rs | 9 ++++----- sync/src/synchronization_verifier.rs | 19 +++++++++++++++++-- verification/src/chain_verifier.rs | 6 +++--- 5 files changed, 32 insertions(+), 12 deletions(-) diff --git a/db/src/indexed_block.rs b/db/src/indexed_block.rs index dc6b49cc..15cf15d7 100644 --- a/db/src/indexed_block.rs +++ b/db/src/indexed_block.rs @@ -3,7 +3,7 @@ use chain::{Block, OutPoint, TransactionOutput, merkle_root}; use serialization::{Serializable, CompactInteger}; use indexed_header::IndexedBlockHeader; use indexed_transaction::IndexedTransaction; -use PreviousTransactionOutputProvider; +use {TransactionOutputObserver, PreviousTransactionOutputProvider}; #[derive(Debug, Clone)] pub struct IndexedBlock { @@ -18,6 +18,12 @@ impl PreviousTransactionOutputProvider for IndexedBlock { } } +impl TransactionOutputObserver for IndexedBlock { + fn is_spent(&self, prevout: &OutPoint) -> Option { + self.previous_transaction_output(prevout).map(|_output| false) + } +} + impl From for IndexedBlock { fn from(block: Block) -> Self { let Block { block_header, transactions } = block; diff --git a/db/src/lib.rs b/db/src/lib.rs index eaf73d6a..8c08c640 100644 --- a/db/src/lib.rs +++ b/db/src/lib.rs @@ -71,7 +71,7 @@ pub use storage::{Storage, Store, AsSubstore}; pub use error::{Error, ConsistencyError}; pub use kvdb::Database; pub use transaction_provider::{TransactionProvider, PreviousTransactionOutputProvider}; -pub use transaction_meta_provider::TransactionMetaProvider; +pub use transaction_meta_provider::{TransactionMetaProvider, TransactionOutputObserver}; pub use block_stapler::{BlockStapler, BlockInsertedChain}; pub use block_provider::{BlockProvider, BlockHeaderProvider}; pub use indexed_block::IndexedBlock; diff --git a/db/src/transaction_meta_provider.rs b/db/src/transaction_meta_provider.rs index 6d79e975..a352b143 100644 --- a/db/src/transaction_meta_provider.rs +++ b/db/src/transaction_meta_provider.rs @@ -2,12 +2,11 @@ use primitives::hash::H256; use chain::OutPoint; use transaction_meta::TransactionMeta; +pub trait TransactionOutputObserver { + fn is_spent(&self, prevout: &OutPoint) -> Option; +} + pub trait TransactionMetaProvider { /// get transaction metadata fn transaction_meta(&self, hash: &H256) -> Option; - - fn is_spent(&self, prevout: &OutPoint) -> Option { - self.transaction_meta(&prevout.hash) - .and_then(|meta| meta.is_spent(prevout.index as usize)) - } } diff --git a/sync/src/synchronization_verifier.rs b/sync/src/synchronization_verifier.rs index 3d9ad350..aee732f5 100644 --- a/sync/src/synchronization_verifier.rs +++ b/sync/src/synchronization_verifier.rs @@ -7,7 +7,7 @@ use network::Magic; use primitives::hash::H256; use synchronization_chain::ChainRef; use verification::{ChainVerifier, Verify as VerificationVerify, Chain}; -use db::{SharedStore, IndexedBlock, PreviousTransactionOutputProvider}; +use db::{SharedStore, IndexedBlock, PreviousTransactionOutputProvider, TransactionOutputObserver}; use time::get_time; /// Block verification events sink @@ -153,7 +153,7 @@ impl Verifier for SyncVerifier where T: VerificationSink { } /// Execute single verification task -fn execute_verification_task(sink: &Arc, tx_output_provider: &U, verifier: &ChainVerifier, task: VerificationTask) { +fn execute_verification_task(sink: &Arc, tx_output_provider: &U, verifier: &ChainVerifier, task: VerificationTask) { let mut tasks_queue: VecDeque = VecDeque::new(); tasks_queue.push_back(task); @@ -202,12 +202,27 @@ impl PreviousTransactionOutputProvider for ChainMemoryPoolTransactionOutputProvi } } +impl TransactionOutputObserver for ChainMemoryPoolTransactionOutputProvider { + fn is_spent(&self, prevout: &OutPoint) -> Option { + self.chain.read() + .storage() + .transaction_meta(&prevout.hash) + .and_then(|tm| tm.is_spent(prevout.index as usize)) + } +} + impl PreviousTransactionOutputProvider for EmptyTransactionOutputProvider { fn previous_transaction_output(&self, _prevout: &OutPoint) -> Option { None } } +impl TransactionOutputObserver for EmptyTransactionOutputProvider { + fn is_spent(&self, _prevout: &OutPoint) -> Option { + None + } +} + #[cfg(test)] pub mod tests { use std::sync::Arc; diff --git a/verification/src/chain_verifier.rs b/verification/src/chain_verifier.rs index c0fa2789..265182c0 100644 --- a/verification/src/chain_verifier.rs +++ b/verification/src/chain_verifier.rs @@ -3,7 +3,7 @@ use std::collections::BTreeSet; use scoped_pool::Pool; use hash::H256; -use db::{self, BlockLocation, PreviousTransactionOutputProvider, BlockHeaderProvider}; +use db::{self, BlockLocation, PreviousTransactionOutputProvider, BlockHeaderProvider, TransactionOutputObserver}; use network::{Magic, ConsensusParams}; use error::{Error, TransactionError}; use sigops::{StoreWithUnretainedOutputs, transaction_sigops}; @@ -168,7 +168,7 @@ impl ChainVerifier { time: u32, transaction: &chain::Transaction, sequence: usize - ) -> Result<(), TransactionError> where T: PreviousTransactionOutputProvider { + ) -> Result<(), TransactionError> where T: PreviousTransactionOutputProvider + TransactionOutputObserver { use script::{ TransactionInputSigner, @@ -201,7 +201,7 @@ impl ChainVerifier { // - if we process transactions from mempool we shouldn't care if transactions before it // spent this output, cause they may not make their way into the block due to their size // or sigops limit - if self.store.is_spent(&input.previous_output).unwrap_or(false) { + if prevout_provider.is_spent(&input.previous_output).unwrap_or(false) { return Err(TransactionError::UsingSpentOutput(input.previous_output.hash.clone(), input.previous_output.index)) }