From b90c8add96659800fbbe049067929e24fc0b7130 Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Wed, 16 Aug 2017 13:47:51 +0300 Subject: [PATCH] segwit: premature witness check --- verification/src/accept_chain.rs | 2 +- verification/src/accept_transaction.rs | 33 ++++++++++++++++++++++---- verification/src/error.rs | 2 ++ verification/src/verify_transaction.rs | 27 ++++++++++++++++++++- 4 files changed, 58 insertions(+), 6 deletions(-) diff --git a/verification/src/accept_chain.rs b/verification/src/accept_chain.rs index f972f3d2..d7f4bbb9 100644 --- a/verification/src/accept_chain.rs +++ b/verification/src/accept_chain.rs @@ -39,7 +39,7 @@ impl<'a> ChainAcceptor<'a> { height, block.header.raw.time, tx_index, - deployments, + active_deployments, headers, )) .collect(), diff --git a/verification/src/accept_transaction.rs b/verification/src/accept_transaction.rs index 9b7fdcc4..fe6d74da 100644 --- a/verification/src/accept_transaction.rs +++ b/verification/src/accept_transaction.rs @@ -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}; diff --git a/verification/src/error.rs b/verification/src/error.rs index 1647e722..7aba27ca 100644 --- a/verification/src/error.rs +++ b/verification/src/error.rs @@ -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, } diff --git a/verification/src/verify_transaction.rs b/verification/src/verify_transaction.rs index 2b143d50..77a9a240 100644 --- a/verification/src/verify_transaction.rs +++ b/verification/src/verify_transaction.rs @@ -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(()) + } + } +}