segwit: sigops cost stub
This commit is contained in:
parent
bda2277b71
commit
1e28ec4ed5
|
@ -230,6 +230,15 @@ impl ConsensusFork {
|
|||
sigops <= 20_000,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_block_sigops_cost(&self, sigops_cost: usize, deployments: &Deployments) -> bool {
|
||||
match *self {
|
||||
ConsensusFork::NoFork | ConsensusFork::SegWit2x(_) if deployments.is_active("segwit") =>
|
||||
sigops_cost <= segwit::MAX_BLOCK_SIGOPS_COST,
|
||||
ConsensusFork::NoFork | ConsensusFork::SegWit2x(_) | ConsensusFork::BitcoinCash(_) =>
|
||||
true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -305,7 +305,7 @@ pub fn verify_script(
|
|||
|
||||
if flags.verify_witness {
|
||||
if let Some((witness_version, witness_program)) = pubkey2.parse_witness_program() {
|
||||
if script_sig != Builder::default().push_data(&pubkey2) {
|
||||
if script_sig != &Builder::default().push_data(&pubkey2).into_script() {
|
||||
return Err(Error::WitnessMalleatedP2SH);
|
||||
}
|
||||
|
||||
|
|
|
@ -146,7 +146,7 @@ impl Script {
|
|||
|
||||
/// Parse witness program. Returns Some(witness program version, code) or None if not a witness program.
|
||||
pub fn parse_witness_program(&self) -> Option<(u8, &[u8])> {
|
||||
if self.data.len() > 4 || self.data.len() > 42 || self.data.len() != self.data[1] as usize + 2 {
|
||||
if self.data.len() < 4 || self.data.len() > 42 || self.data.len() != self.data[1] as usize + 2 {
|
||||
return None;
|
||||
}
|
||||
let witness_version = match Opcode::from_u8(self.data[0]) {
|
||||
|
|
|
@ -3,7 +3,7 @@ use crypto::dhash256;
|
|||
use db::{TransactionOutputProvider, BlockHeaderProvider};
|
||||
use script;
|
||||
use ser::Stream;
|
||||
use sigops::transaction_sigops;
|
||||
use sigops::{transaction_sigops, transaction_sigops_cost} ;
|
||||
use work::block_reward_satoshi;
|
||||
use duplex_store::DuplexTransactionOutputProvider;
|
||||
use deployments::{Deployments, ActiveDeployments};
|
||||
|
@ -35,7 +35,7 @@ impl<'a> BlockAcceptor<'a> {
|
|||
serialized_size: BlockSerializedSize::new(block, consensus, deployments, height),
|
||||
coinbase_script: BlockCoinbaseScript::new(block, consensus, height),
|
||||
coinbase_claim: BlockCoinbaseClaim::new(block, store, height),
|
||||
sigops: BlockSigops::new(block, store, consensus, height),
|
||||
sigops: BlockSigops::new(block, store, consensus, deployments, height),
|
||||
witness: BlockWitness::new(block, deployments),
|
||||
}
|
||||
}
|
||||
|
@ -128,15 +128,17 @@ pub struct BlockSigops<'a> {
|
|||
block: CanonBlock<'a>,
|
||||
store: &'a TransactionOutputProvider,
|
||||
consensus: &'a ConsensusParams,
|
||||
deployments: ActiveDeployments<'a>,
|
||||
height: u32,
|
||||
}
|
||||
|
||||
impl<'a> BlockSigops<'a> {
|
||||
fn new(block: CanonBlock<'a>, store: &'a TransactionOutputProvider, consensus: &'a ConsensusParams, height: u32) -> Self {
|
||||
fn new(block: CanonBlock<'a>, store: &'a TransactionOutputProvider, consensus: &'a ConsensusParams, deployments: ActiveDeployments<'a>, height: u32) -> Self {
|
||||
BlockSigops {
|
||||
block: block,
|
||||
store: store,
|
||||
consensus: consensus,
|
||||
deployments: deployments,
|
||||
height: height,
|
||||
}
|
||||
}
|
||||
|
@ -150,6 +152,14 @@ impl<'a> BlockSigops<'a> {
|
|||
|
||||
let size = self.block.size();
|
||||
if sigops > self.consensus.fork.max_block_sigops(self.height, size) {
|
||||
return Err(Error::MaximumSigops)
|
||||
}
|
||||
|
||||
// TODO: when segwit is enabled, only sigop_cost must be checked!!!
|
||||
let sigops_cost = self.block.transactions.iter()
|
||||
.map(|tx| transaction_sigops_cost(&tx.raw, &store, bip16_active))
|
||||
.sum::<usize>();
|
||||
if !self.consensus.fork.check_block_sigops_cost(sigops_cost, &self.deployments) {
|
||||
Err(Error::MaximumSigops)
|
||||
} else {
|
||||
Ok(())
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
// TODO: excess clones
|
||||
use network::segwit;
|
||||
use chain::Transaction;
|
||||
use db::TransactionOutputProvider;
|
||||
use script::Script;
|
||||
use script::{Script, ScriptWitness};
|
||||
|
||||
/// Counts signature operations in given transaction
|
||||
/// bip16_active flag indicates if we should also count signature operations
|
||||
|
@ -16,6 +18,7 @@ pub fn transaction_sigops(
|
|||
output_script.sigops_count(false)
|
||||
}).sum();
|
||||
|
||||
// TODO: bitcoin/bitcoin also includes input_sigops here
|
||||
if transaction.is_coinbase() {
|
||||
return output_sigops;
|
||||
}
|
||||
|
@ -38,3 +41,55 @@ pub fn transaction_sigops(
|
|||
|
||||
input_sigops + output_sigops + bip16_sigops
|
||||
}
|
||||
|
||||
pub fn transaction_sigops_cost(
|
||||
transaction: &Transaction,
|
||||
store: &TransactionOutputProvider,
|
||||
bip16_active: bool,
|
||||
) -> usize {
|
||||
let sigops_cost = transaction_sigops(transaction, store, bip16_active) * segwit::WITNESS_SCALE_FACTOR;
|
||||
let witness_sigops_cost: usize = transaction.inputs.iter()
|
||||
.map(|input| store.transaction_output(&input.previous_output, usize::max_value())
|
||||
.map(|output| witness_sigops(&Script::new(input.script_sig.clone()), &Script::new(output.script_pubkey.clone()), &ScriptWitness { stack: input.script_witness.clone().into() }))
|
||||
.unwrap_or(0))
|
||||
.sum();
|
||||
sigops_cost + witness_sigops_cost
|
||||
}
|
||||
|
||||
fn witness_sigops(
|
||||
script_sig: &Script,
|
||||
script_pubkey: &Script,
|
||||
script_witness: &ScriptWitness,
|
||||
) -> usize {
|
||||
if let Some((witness_version, witness_program)) = script_pubkey.parse_witness_program() {
|
||||
return witness_program_sigops(witness_version, witness_program, script_witness);
|
||||
}
|
||||
|
||||
if script_pubkey.is_pay_to_script_hash() && script_sig.is_push_only() {
|
||||
if let Some(Ok(instruction)) = script_sig.iter().last() {
|
||||
if let Some(data) = instruction.data {
|
||||
let subscript = Script::new(data.into());
|
||||
if let Some((witness_version, witness_program)) = subscript.parse_witness_program() {
|
||||
return witness_program_sigops(witness_version, witness_program, script_witness);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
0
|
||||
}
|
||||
|
||||
fn witness_program_sigops(
|
||||
witness_version: u8,
|
||||
witness_program: &[u8],
|
||||
script_witness: &ScriptWitness,
|
||||
) -> usize {
|
||||
match witness_version {
|
||||
0 if witness_program.len() == 20 => 1,
|
||||
0 if witness_program.len() == 32 => match script_witness.stack.last().ok() {
|
||||
Some(subscript) => Script::new(subscript.clone()).sigops_count(true),
|
||||
_ => 0
|
||||
},
|
||||
_ => 0,
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue