memory pool transaction acceptor
This commit is contained in:
parent
1d2e0ce495
commit
74817084ab
|
@ -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(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue