From fdf704f6ae65e3a42e3d8def96ae56357b96900d Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Mon, 12 Dec 2016 00:56:32 +0300 Subject: [PATCH] check mempool::is_spent in ChainMemoryPoolTransactionOutputProvider::is_spent --- sync/src/synchronization_chain.rs | 6 +++++ sync/src/synchronization_verifier.rs | 35 ++++++++++++++++++++++------ 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/sync/src/synchronization_chain.rs b/sync/src/synchronization_chain.rs index b40e51ae..1a1299f6 100644 --- a/sync/src/synchronization_chain.rs +++ b/sync/src/synchronization_chain.rs @@ -195,6 +195,12 @@ impl Chain { &self.memory_pool } + /// Get mutable memory pool + #[cfg(test)] + pub fn memory_pool_mut(&mut self) -> &mut MemoryPool { + &mut self.memory_pool + } + /// Get number of blocks in given state pub fn length_of_blocks_state(&self, state: BlockState) -> u32 { match state { diff --git a/sync/src/synchronization_verifier.rs b/sync/src/synchronization_verifier.rs index aee732f5..dd4e8ecb 100644 --- a/sync/src/synchronization_verifier.rs +++ b/sync/src/synchronization_verifier.rs @@ -198,16 +198,19 @@ impl ChainMemoryPoolTransactionOutputProvider { impl PreviousTransactionOutputProvider for ChainMemoryPoolTransactionOutputProvider { fn previous_transaction_output(&self, prevout: &OutPoint) -> Option { - self.chain.read().memory_pool().previous_transaction_output(prevout) + let chain = self.chain.read(); + chain.memory_pool().previous_transaction_output(prevout) + .or_else(|| chain.storage().as_previous_transaction_output_provider().previous_transaction_output(prevout)) } } 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)) + let chain = self.chain.read(); + if chain.memory_pool().is_spent(prevout) { + return Some(true); + } + chain.storage().transaction_meta(&prevout.hash).and_then(|tm| tm.is_spent(prevout.index as usize)) } } @@ -227,12 +230,15 @@ impl TransactionOutputObserver for EmptyTransactionOutputProvider { pub mod tests { use std::sync::Arc; use std::collections::HashMap; + use parking_lot::RwLock; use chain::Transaction; + use synchronization_chain::{Chain, ChainRef}; use synchronization_client::CoreVerificationSink; use synchronization_executor::tests::DummyTaskExecutor; use primitives::hash::H256; - use super::{Verifier, BlockVerificationSink, TransactionVerificationSink}; - use db::IndexedBlock; + use super::{Verifier, BlockVerificationSink, TransactionVerificationSink, ChainMemoryPoolTransactionOutputProvider}; + use db::{self, IndexedBlock}; + use test_data; #[derive(Default)] pub struct DummyVerifier { @@ -274,4 +280,19 @@ pub mod tests { } } } + + #[test] + fn when_transaction_spends_output_twice() { + use db::TransactionOutputObserver; + let tx1: Transaction = test_data::TransactionBuilder::with_default_input(0).into(); + let tx2: Transaction = test_data::TransactionBuilder::with_default_input(1).into(); + let out1 = tx1.inputs[0].previous_output.clone(); + let out2 = tx2.inputs[0].previous_output.clone(); + let mut chain = Chain::new(Arc::new(db::TestStorage::with_genesis_block())); + chain.memory_pool_mut().insert_verified(tx1); + let chain = ChainRef::new(RwLock::new(chain)); + let provider = ChainMemoryPoolTransactionOutputProvider::with_chain(chain); + assert!(provider.is_spent(&out1).unwrap_or_default()); + assert!(!provider.is_spent(&out2).unwrap_or_default()); + } }