Transaction Output Observer
This commit is contained in:
parent
f669a27d06
commit
56e4e54074
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue