memory pool transaction acceptor

This commit is contained in:
debris 2016-12-11 23:00:42 +01:00
parent 1d2e0ce495
commit 74817084ab
2 changed files with 98 additions and 14 deletions

View File

@ -2,8 +2,9 @@ use primitives::hash::H256;
use db::{TransactionMetaProvider, PreviousTransactionOutputProvider}; use db::{TransactionMetaProvider, PreviousTransactionOutputProvider};
use network::{Magic, ConsensusParams}; use network::{Magic, ConsensusParams};
use duplex_store::{DuplexTransactionOutputProvider}; use duplex_store::{DuplexTransactionOutputProvider};
use sigops::transaction_sigops;
use canon::CanonTransaction; use canon::CanonTransaction;
use constants::COINBASE_MATURITY; use constants::{COINBASE_MATURITY, MAX_BLOCK_SIGOPS};
use error::TransactionError; use error::TransactionError;
pub struct TransactionAcceptor<'a> { pub struct TransactionAcceptor<'a> {
@ -15,13 +16,10 @@ pub struct TransactionAcceptor<'a> {
impl<'a> TransactionAcceptor<'a> { impl<'a> TransactionAcceptor<'a> {
pub fn new( pub fn new(
// transactions meta
// in case of block validation, it's only current block, // in case of block validation, it's only current block,
// TODO: in case of memory pool it should be db and memory pool
meta_store: &'a TransactionMetaProvider, meta_store: &'a TransactionMetaProvider,
// previous transaction outputs // previous transaction outputs
// in case of block validation, that's database and currently processed block // in case of block validation, that's database and currently processed block
// in case of memory pool it should be db and memory pool
prevout_store: DuplexTransactionOutputProvider<'a>, prevout_store: DuplexTransactionOutputProvider<'a>,
network: Magic, network: Magic,
transaction: CanonTransaction<'a>, transaction: CanonTransaction<'a>,
@ -29,7 +27,7 @@ impl<'a> TransactionAcceptor<'a> {
height: u32 height: u32
) -> Self { ) -> Self {
TransactionAcceptor { TransactionAcceptor {
bip30: TransactionBip30::new(transaction, meta_store, network.consensus_params(), block_hash, height), bip30: TransactionBip30::new_for_sync(transaction, meta_store, network.consensus_params(), block_hash, height),
missing_inputs: TransactionMissingInputs::new(transaction, prevout_store), missing_inputs: TransactionMissingInputs::new(transaction, prevout_store),
maturity: TransactionMaturity::new(transaction, meta_store, height), maturity: TransactionMaturity::new(transaction, meta_store, height),
overspent: TransactionOverspent::new(transaction, prevout_store), overspent: TransactionOverspent::new(transaction, prevout_store),
@ -46,6 +44,46 @@ impl<'a> TransactionAcceptor<'a> {
} }
} }
pub struct MemoryPoolTransactionAcceptor<'a> {
pub bip30: TransactionBip30<'a>,
pub missing_inputs: TransactionMissingInputs<'a>,
pub maturity: TransactionMaturity<'a>,
pub overspent: TransactionOverspent<'a>,
pub sigops: TransactionSigops<'a>,
}
impl<'a> MemoryPoolTransactionAcceptor<'a> {
pub fn new(
// 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>,
network: Magic,
transaction: CanonTransaction<'a>,
height: u32,
time: u32,
) -> Self {
let params = network.consensus_params();
MemoryPoolTransactionAcceptor {
bip30: TransactionBip30::new_for_mempool(transaction, meta_store),
missing_inputs: TransactionMissingInputs::new(transaction, prevout_store),
maturity: TransactionMaturity::new(transaction, meta_store, height),
overspent: TransactionOverspent::new(transaction, prevout_store),
sigops: TransactionSigops::new(transaction, prevout_store, params, MAX_BLOCK_SIGOPS, time),
}
}
pub fn check(&self) -> Result<(), TransactionError> {
try!(self.bip30.check());
try!(self.missing_inputs.check());
// TODO: double spends
try!(self.maturity.check());
try!(self.overspent.check());
try!(self.sigops.check());
Ok(())
}
}
pub trait TransactionRule { pub trait TransactionRule {
fn check(&self) -> Result<(), TransactionError>; fn check(&self) -> Result<(), TransactionError>;
} }
@ -53,19 +91,31 @@ pub trait TransactionRule {
pub struct TransactionBip30<'a> { pub struct TransactionBip30<'a> {
transaction: CanonTransaction<'a>, transaction: CanonTransaction<'a>,
store: &'a TransactionMetaProvider, store: &'a TransactionMetaProvider,
consensus_params: ConsensusParams, exception: bool,
block_hash: &'a H256,
height: u32,
} }
impl<'a> TransactionBip30<'a> { impl<'a> TransactionBip30<'a> {
fn new(transaction: CanonTransaction<'a>, store: &'a TransactionMetaProvider, consensus_params: ConsensusParams, block_hash: &'a H256, height: u32) -> Self { fn new_for_sync(
transaction: CanonTransaction<'a>,
store: &'a TransactionMetaProvider,
consensus_params: ConsensusParams,
block_hash: &'a H256,
height: u32
) -> Self {
let exception = consensus_params.is_bip30_exception(block_hash, height);
TransactionBip30 { TransactionBip30 {
transaction: transaction, transaction: transaction,
store: store, store: store,
consensus_params: consensus_params, exception: exception,
block_hash: block_hash, }
height: height, }
fn new_for_mempool(transaction: CanonTransaction<'a>, store: &'a TransactionMetaProvider) -> Self {
TransactionBip30 {
transaction: transaction,
store: store,
exception: false,
} }
} }
} }
@ -82,7 +132,7 @@ impl<'a> TransactionRule for TransactionBip30<'a> {
// may have fully spent the output, and we, by checking only storage, have no knowladge // may have fully spent the output, and we, by checking only storage, have no knowladge
// of it // of it
match self.store.transaction_meta(&self.transaction.hash) { match self.store.transaction_meta(&self.transaction.hash) {
Some(ref meta) if !meta.is_fully_spent() && !self.consensus_params.is_bip30_exception(self.block_hash, self.height) => { Some(ref meta) if !meta.is_fully_spent() && !self.exception => {
Err(TransactionError::UnspentTransactionWithTheSameHash) Err(TransactionError::UnspentTransactionWithTheSameHash)
}, },
_ => Ok(()) _ => Ok(())
@ -186,3 +236,37 @@ impl<'a> TransactionRule for TransactionOverspent<'a> {
} }
} }
} }
pub struct TransactionSigops<'a> {
transaction: CanonTransaction<'a>,
store: DuplexTransactionOutputProvider<'a>,
consensus_params: ConsensusParams,
max_sigops: usize,
time: u32,
}
impl<'a> TransactionSigops<'a> {
fn new(transaction: CanonTransaction<'a>, store: DuplexTransactionOutputProvider<'a>, consensus_params: ConsensusParams, max_sigops: usize, time: u32) -> Self {
TransactionSigops {
transaction: transaction,
store: store,
consensus_params: consensus_params,
max_sigops: max_sigops,
time: time,
}
}
}
impl<'a> TransactionRule for TransactionSigops<'a> {
fn check(&self) -> Result<(), TransactionError> {
let bip16_active = self.time >= self.consensus_params.bip16_time;
let error = transaction_sigops(&self.transaction.raw, &self.store, bip16_active)
.map(|sigops| sigops > self.max_sigops)
.unwrap_or(true);
if error {
Err(TransactionError::MaxSigops)
} else {
Ok(())
}
}
}

View File

@ -86,7 +86,7 @@ pub use canon::{CanonBlock, CanonHeader, CanonTransaction};
pub use accept_block::BlockAcceptor; pub use accept_block::BlockAcceptor;
pub use accept_chain::ChainAcceptor; pub use accept_chain::ChainAcceptor;
pub use accept_header::HeaderAcceptor; pub use accept_header::HeaderAcceptor;
pub use accept_transaction::TransactionAcceptor; pub use accept_transaction::{TransactionAcceptor, MemoryPoolTransactionAcceptor};
pub use verify_block::BlockVerifier; pub use verify_block::BlockVerifier;
pub use verify_chain::ChainVerifier as XXXChainVerifier; pub use verify_chain::ChainVerifier as XXXChainVerifier;