verification: check transaction size in TransactionAcceptor

This commit is contained in:
Svyatoslav Nikolsky 2018-11-14 15:52:43 +03:00
parent 56b2def7e1
commit ed119f633a
4 changed files with 75 additions and 18 deletions

View File

@ -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
}
}
}

View File

@ -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(())
}
}
}

View File

@ -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(),
}
}

View File

@ -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(())