verification: check transaction size in TransactionAcceptor
This commit is contained in:
parent
56b2def7e1
commit
ed119f633a
|
@ -24,6 +24,14 @@ pub struct ConsensusParams {
|
|||
/// BIP68, BIP112, BIP113 deployment
|
||||
pub csv_deployment: Option<Deployment>,
|
||||
|
||||
/// Height of Overwinter activation.
|
||||
/// Details: https://zcash.readthedocs.io/en/latest/rtd_pages/nu_dev_guide.html#overwinter
|
||||
pub overwinter_height: u32,
|
||||
|
||||
/// Height of Sapling activation.
|
||||
/// Details: https://zcash.readthedocs.io/en/latest/rtd_pages/nu_dev_guide.html#sapling
|
||||
pub sapling_height: u32,
|
||||
|
||||
/// Interval (in blocks) to calculate average work.
|
||||
pub pow_averaging_window: u32,
|
||||
/// % of possible down adjustment of work.
|
||||
|
@ -47,6 +55,9 @@ impl ConsensusParams {
|
|||
miner_confirmation_window: 2016,
|
||||
csv_deployment: None,
|
||||
|
||||
overwinter_height: 347500,
|
||||
sapling_height: 419200,
|
||||
|
||||
pow_averaging_window: 17,
|
||||
pow_max_adjust_down: 32,
|
||||
pow_max_adjust_up: 16,
|
||||
|
@ -62,6 +73,9 @@ impl ConsensusParams {
|
|||
miner_confirmation_window: 2016,
|
||||
csv_deployment: None,
|
||||
|
||||
overwinter_height: 207500,
|
||||
sapling_height: 280000,
|
||||
|
||||
pow_averaging_window: 17,
|
||||
pow_max_adjust_down: 32,
|
||||
pow_max_adjust_up: 16,
|
||||
|
@ -77,6 +91,9 @@ impl ConsensusParams {
|
|||
miner_confirmation_window: 144,
|
||||
csv_deployment: None,
|
||||
|
||||
overwinter_height: ::std::u32::MAX,
|
||||
sapling_height: ::std::u32::MAX,
|
||||
|
||||
pow_averaging_window: 17,
|
||||
pow_max_adjust_down: 0,
|
||||
pow_max_adjust_up: 0,
|
||||
|
@ -109,7 +126,15 @@ impl ConsensusParams {
|
|||
20_000
|
||||
}
|
||||
|
||||
pub fn max_transaction_size(&self) -> usize {
|
||||
100_000 // TODO: changed after sapling
|
||||
pub fn absolute_max_transaction_size(&self) -> usize {
|
||||
2_000_000
|
||||
}
|
||||
|
||||
pub fn max_transaction_size(&self, height: u32) -> usize {
|
||||
if height >= self.sapling_height {
|
||||
2_000_000
|
||||
} else {
|
||||
100_000
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use ser::Serializable;
|
||||
use storage::{TransactionMetaProvider, TransactionOutputProvider};
|
||||
use network::{ConsensusParams};
|
||||
use script::{Script, verify_script, VerificationFlags, TransactionSignatureChecker, TransactionInputSigner};
|
||||
|
@ -10,6 +11,7 @@ use error::TransactionError;
|
|||
use VerificationLevel;
|
||||
|
||||
pub struct TransactionAcceptor<'a> {
|
||||
pub size: TransactionSize<'a>,
|
||||
pub bip30: TransactionBip30<'a>,
|
||||
pub missing_inputs: TransactionMissingInputs<'a>,
|
||||
pub maturity: TransactionMaturity<'a>,
|
||||
|
@ -54,6 +56,7 @@ impl<'a> TransactionAcceptor<'a> {
|
|||
|
||||
trace!(target: "verification", "Tx verification {}", transaction.hash.to_reversed_str());
|
||||
TransactionAcceptor {
|
||||
size: TransactionSize::new(transaction, consensus, height),
|
||||
bip30: TransactionBip30::new_for_sync(transaction, meta_store),
|
||||
missing_inputs: TransactionMissingInputs::new(transaction, output_store, transaction_index),
|
||||
maturity: TransactionMaturity::new(transaction, meta_store, height),
|
||||
|
@ -64,12 +67,13 @@ impl<'a> TransactionAcceptor<'a> {
|
|||
}
|
||||
|
||||
pub fn check(&self) -> Result<(), TransactionError> {
|
||||
try!(self.bip30.check());
|
||||
try!(self.missing_inputs.check());
|
||||
try!(self.maturity.check());
|
||||
try!(self.overspent.check());
|
||||
try!(self.double_spent.check());
|
||||
try!(self.eval.check());
|
||||
self.size.check()?;
|
||||
self.bip30.check()?;
|
||||
self.missing_inputs.check()?;
|
||||
self.maturity.check()?;
|
||||
self.overspent.check()?;
|
||||
self.double_spent.check()?;
|
||||
self.eval.check()?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -415,3 +419,27 @@ impl<'a> TransactionDoubleSpend<'a> {
|
|||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// The encoded size of the transaction MUST be less than or equal to current max limit.
|
||||
pub struct TransactionSize<'a> {
|
||||
transaction: CanonTransaction<'a>,
|
||||
max_size: usize,
|
||||
}
|
||||
|
||||
impl<'a> TransactionSize<'a> {
|
||||
fn new(transaction: CanonTransaction<'a>, consensus: &'a ConsensusParams, height: u32) -> Self {
|
||||
TransactionSize {
|
||||
transaction: transaction,
|
||||
max_size: consensus.max_transaction_size(height),
|
||||
}
|
||||
}
|
||||
|
||||
fn check(&self) -> Result<(), TransactionError> {
|
||||
let size = self.transaction.raw.serialized_size();
|
||||
if size > self.max_size {
|
||||
Err(TransactionError::MaxSize)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ impl<'a> ChainVerifier<'a> {
|
|||
ChainVerifier {
|
||||
block: BlockVerifier::new(block, consensus),
|
||||
header: HeaderVerifier::new(&block.header, consensus, current_time),
|
||||
transactions: block.transactions.iter().map(TransactionVerifier::new).collect(),
|
||||
transactions: block.transactions.iter().map(|tx| TransactionVerifier::new(tx, consensus)).collect(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -13,10 +13,11 @@ pub struct TransactionVerifier<'a> {
|
|||
pub null_non_coinbase: TransactionNullNonCoinbase<'a>,
|
||||
pub oversized_coinbase: TransactionOversizedCoinbase<'a>,
|
||||
pub joint_split_in_coinbase: TransactionJointSplitInCoinbase<'a>,
|
||||
pub size: TransactionAbsoluteSize<'a>,
|
||||
}
|
||||
|
||||
impl<'a> TransactionVerifier<'a> {
|
||||
pub fn new(transaction: &'a IndexedTransaction) -> Self {
|
||||
pub fn new(transaction: &'a IndexedTransaction, consensus: &'a ConsensusParams) -> Self {
|
||||
trace!(target: "verification", "Tx pre-verification {}", transaction.hash.to_reversed_str());
|
||||
TransactionVerifier {
|
||||
version: TransactionVersion::new(transaction),
|
||||
|
@ -24,6 +25,7 @@ impl<'a> TransactionVerifier<'a> {
|
|||
null_non_coinbase: TransactionNullNonCoinbase::new(transaction),
|
||||
oversized_coinbase: TransactionOversizedCoinbase::new(transaction, MIN_COINBASE_SIZE..MAX_COINBASE_SIZE),
|
||||
joint_split_in_coinbase: TransactionJointSplitInCoinbase::new(transaction),
|
||||
size: TransactionAbsoluteSize::new(transaction, consensus),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -33,6 +35,7 @@ impl<'a> TransactionVerifier<'a> {
|
|||
self.null_non_coinbase.check()?;
|
||||
self.oversized_coinbase.check()?;
|
||||
self.joint_split_in_coinbase.check()?;
|
||||
self.size.check()?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -41,7 +44,7 @@ pub struct MemoryPoolTransactionVerifier<'a> {
|
|||
pub empty: TransactionEmpty<'a>,
|
||||
pub null_non_coinbase: TransactionNullNonCoinbase<'a>,
|
||||
pub is_coinbase: TransactionMemoryPoolCoinbase<'a>,
|
||||
pub size: TransactionSize<'a>,
|
||||
pub size: TransactionAbsoluteSize<'a>,
|
||||
pub sigops: TransactionSigops<'a>,
|
||||
}
|
||||
|
||||
|
@ -52,7 +55,7 @@ impl<'a> MemoryPoolTransactionVerifier<'a> {
|
|||
empty: TransactionEmpty::new(transaction),
|
||||
null_non_coinbase: TransactionNullNonCoinbase::new(transaction),
|
||||
is_coinbase: TransactionMemoryPoolCoinbase::new(transaction),
|
||||
size: TransactionSize::new(transaction, consensus),
|
||||
size: TransactionAbsoluteSize::new(transaction, consensus),
|
||||
sigops: TransactionSigops::new(transaction, consensus.max_block_sigops()),
|
||||
}
|
||||
}
|
||||
|
@ -166,22 +169,23 @@ impl<'a> TransactionMemoryPoolCoinbase<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct TransactionSize<'a> {
|
||||
/// The encoded size of the transaction MUST be less than or equal to EVER possible max limit.
|
||||
pub struct TransactionAbsoluteSize<'a> {
|
||||
transaction: &'a IndexedTransaction,
|
||||
consensus: &'a ConsensusParams,
|
||||
absoute_max_size: usize,
|
||||
}
|
||||
|
||||
impl<'a> TransactionSize<'a> {
|
||||
impl<'a> TransactionAbsoluteSize<'a> {
|
||||
fn new(transaction: &'a IndexedTransaction, consensus: &'a ConsensusParams) -> Self {
|
||||
TransactionSize {
|
||||
TransactionAbsoluteSize {
|
||||
transaction: transaction,
|
||||
consensus: consensus,
|
||||
absoute_max_size: consensus.absolute_max_transaction_size(),
|
||||
}
|
||||
}
|
||||
|
||||
fn check(&self) -> Result<(), TransactionError> {
|
||||
let size = self.transaction.raw.serialized_size();
|
||||
if size > self.consensus.max_transaction_size() {
|
||||
if size > self.absoute_max_size {
|
||||
Err(TransactionError::MaxSize)
|
||||
} else {
|
||||
Ok(())
|
||||
|
|
Loading…
Reference in New Issue