segwit: premature witness check

This commit is contained in:
Svyatoslav Nikolsky 2017-08-16 13:47:51 +03:00
parent d4a191aec1
commit b90c8add96
4 changed files with 58 additions and 6 deletions

View File

@ -39,7 +39,7 @@ impl<'a> ChainAcceptor<'a> {
height,
block.header.raw.time,
tx_index,
deployments,
active_deployments,
headers,
))
.collect(),

View File

@ -1,10 +1,10 @@
use primitives::hash::H256;
use primitives::bytes::Bytes;
use db::{TransactionMetaProvider, TransactionOutputProvider, BlockHeaderProvider};
use network::{ConsensusParams, ConsensusFork};
use network::{ConsensusParams, ConsensusFork, Deployments as NetworkDeployments};
use script::{Script, ScriptWitness, verify_script, VerificationFlags, TransactionSignatureChecker, TransactionInputSigner, SignatureVersion};
use duplex_store::DuplexTransactionOutputProvider;
use deployments::Deployments;
use deployments::{Deployments, ActiveDeployments};
use script::Builder;
use sigops::transaction_sigops;
use canon::CanonTransaction;
@ -13,6 +13,7 @@ use error::TransactionError;
use VerificationLevel;
pub struct TransactionAcceptor<'a> {
pub premature_witness: TransactionPrematureWitness<'a>,
pub bip30: TransactionBip30<'a>,
pub missing_inputs: TransactionMissingInputs<'a>,
pub maturity: TransactionMaturity<'a>,
@ -36,22 +37,24 @@ impl<'a> TransactionAcceptor<'a> {
height: u32,
time: u32,
transaction_index: usize,
deployments: &'a Deployments,
deployments: ActiveDeployments<'a>,
headers: &'a BlockHeaderProvider,
) -> Self {
trace!(target: "verification", "Tx verification {}", transaction.hash.to_reversed_str());
TransactionAcceptor {
premature_witness: TransactionPrematureWitness::new(transaction, deployments.is_active("segwit")),
bip30: TransactionBip30::new_for_sync(transaction, meta_store, consensus, block_hash, height),
missing_inputs: TransactionMissingInputs::new(transaction, output_store, transaction_index),
maturity: TransactionMaturity::new(transaction, meta_store, height),
overspent: TransactionOverspent::new(transaction, output_store),
double_spent: TransactionDoubleSpend::new(transaction, output_store),
return_replay_protection: TransactionReturnReplayProtection::new(transaction, consensus, height),
eval: TransactionEval::new(transaction, output_store, consensus, verification_level, height, time, deployments, headers),
eval: TransactionEval::new(transaction, output_store, consensus, verification_level, height, time, deployments.deployments, headers),
}
}
pub fn check(&self) -> Result<(), TransactionError> {
try!(self.premature_witness.check());
try!(self.bip30.check());
try!(self.missing_inputs.check());
try!(self.maturity.check());
@ -435,6 +438,28 @@ impl<'a> TransactionReturnReplayProtection<'a> {
}
}
pub struct TransactionPrematureWitness<'a> {
transaction: CanonTransaction<'a>,
is_segwit_active: bool,
}
impl<'a> TransactionPrematureWitness<'a> {
pub fn new(transaction: CanonTransaction<'a>, is_segwit_active: bool) -> Self {
TransactionPrematureWitness {
transaction: transaction,
is_segwit_active: is_segwit_active,
}
}
pub fn check(&self) -> Result<(), TransactionError> {
if !self.is_segwit_active && (*self.transaction).raw.has_witness() {
Err(TransactionError::PrematureWitness)
} else {
Ok(())
}
}
}
#[cfg(test)]
mod tests {
use chain::{IndexedTransaction, Transaction, TransactionOutput};

View File

@ -95,5 +95,7 @@ pub enum TransactionError {
UsingSpentOutput(H256, u32),
/// Transaction, protected using BitcoinCash OP_RETURN replay protection (REQ-6-1).
ReturnReplayProtection,
/// Transaction with witness is received before SegWit is activated.
PrematureWitness,
}

View File

@ -1,7 +1,7 @@
use std::ops;
use ser::Serializable;
use chain::IndexedTransaction;
use network::{ConsensusParams, ConsensusFork};
use network::{ConsensusParams, ConsensusFork, Deployments};
use duplex_store::NoopStore;
use sigops::transaction_sigops;
use error::TransactionError;
@ -37,6 +37,7 @@ pub struct MemoryPoolTransactionVerifier<'a> {
pub null_non_coinbase: TransactionNullNonCoinbase<'a>,
pub is_coinbase: TransactionMemoryPoolCoinbase<'a>,
pub size: TransactionSize<'a>,
pub premature_witness: TransactionPrematureWitness<'a>,
pub sigops: TransactionSigops<'a>,
}
@ -48,6 +49,7 @@ impl<'a> MemoryPoolTransactionVerifier<'a> {
null_non_coinbase: TransactionNullNonCoinbase::new(transaction),
is_coinbase: TransactionMemoryPoolCoinbase::new(transaction),
size: TransactionSize::new(transaction, deployments, consensus),
premature_witness: TransactionPrematureWitness::new(transaction, deployments),
sigops: TransactionSigops::new(transaction, ConsensusFork::absolute_maximum_block_sigops()),
}
}
@ -57,6 +59,7 @@ impl<'a> MemoryPoolTransactionVerifier<'a> {
try!(self.null_non_coinbase.check());
try!(self.is_coinbase.check());
try!(self.size.check());
try!(self.premature_witness.check());
try!(self.sigops.check());
Ok(())
}
@ -192,3 +195,25 @@ impl<'a> TransactionSigops<'a> {
}
}
}
pub struct TransactionPrematureWitness<'a> {
transaction: &'a IndexedTransaction,
deployments: ActiveDeployments<'a>,
}
impl<'a> TransactionPrematureWitness<'a> {
pub fn new(transaction: &'a IndexedTransaction, deployments: ActiveDeployments<'a>) -> Self {
TransactionPrematureWitness {
transaction: transaction,
deployments: deployments,
}
}
pub fn check(&self) -> Result<(), TransactionError> {
if self.transaction.raw.has_witness() && !self.deployments.is_active("segwit") {
Err(TransactionError::PrematureWitness)
} else {
Ok(())
}
}
}