Transaction Output Observer

This commit is contained in:
debris 2016-12-10 22:34:04 +01:00
parent f669a27d06
commit 56e4e54074
5 changed files with 32 additions and 12 deletions

View File

@ -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<bool> {
self.previous_transaction_output(prevout).map(|_output| false)
}
}
impl From<Block> for IndexedBlock {
fn from(block: Block) -> Self {
let Block { block_header, transactions } = block;

View File

@ -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;

View File

@ -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<bool>;
}
pub trait TransactionMetaProvider {
/// get transaction metadata
fn transaction_meta(&self, hash: &H256) -> Option<TransactionMeta>;
fn is_spent(&self, prevout: &OutPoint) -> Option<bool> {
self.transaction_meta(&prevout.hash)
.and_then(|meta| meta.is_spent(prevout.index as usize))
}
}

View File

@ -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<T> Verifier for SyncVerifier<T> where T: VerificationSink {
}
/// Execute single verification task
fn execute_verification_task<T: VerificationSink, U: PreviousTransactionOutputProvider>(sink: &Arc<T>, tx_output_provider: &U, verifier: &ChainVerifier, task: VerificationTask) {
fn execute_verification_task<T: VerificationSink, U: PreviousTransactionOutputProvider + TransactionOutputObserver>(sink: &Arc<T>, tx_output_provider: &U, verifier: &ChainVerifier, task: VerificationTask) {
let mut tasks_queue: VecDeque<VerificationTask> = 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<bool> {
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<TransactionOutput> {
None
}
}
impl TransactionOutputObserver for EmptyTransactionOutputProvider {
fn is_spent(&self, _prevout: &OutPoint) -> Option<bool> {
None
}
}
#[cfg(test)]
pub mod tests {
use std::sync::Arc;

View File

@ -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))
}