uahf: block sigops check
This commit is contained in:
parent
127d662448
commit
6110d94544
|
@ -1,3 +1,4 @@
|
|||
use std::cmp::max;
|
||||
use hash::H256;
|
||||
use {Magic, Deployment};
|
||||
|
||||
|
@ -116,6 +117,16 @@ impl ConsensusParams {
|
|||
}
|
||||
|
||||
impl ConsensusFork {
|
||||
/// Absolute (across all forks) maximum block size. Currently is 8MB for post-HF BitcoinCash
|
||||
pub fn absolute_maximum_block_size() -> usize {
|
||||
8_000_000
|
||||
}
|
||||
|
||||
// Absolute (across all forks) maximum number of sigops in single block. Currently is max(sigops) for 8MB post-HF BitcoinCash block
|
||||
pub fn absolute_maximum_block_sigops() -> usize {
|
||||
160_000
|
||||
}
|
||||
|
||||
pub fn min_block_size(&self, height: u32) -> usize {
|
||||
match *self {
|
||||
ConsensusFork::SegWit2x(fork_height) if height == fork_height => 0,
|
||||
|
@ -133,8 +144,18 @@ impl ConsensusFork {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn max_transaction_size(&self, height: u32) -> usize {
|
||||
self.max_block_size(height)
|
||||
pub fn max_transaction_size(&self, _height: u32) -> usize {
|
||||
// BitcoinCash: according to REQ-5: max size of tx is still 1_000_000
|
||||
1_000_000
|
||||
}
|
||||
|
||||
pub fn max_block_sigops(&self, height: u32, block_size: usize) -> usize {
|
||||
match *self {
|
||||
// according to REQ-5: max_block_sigops = 20000 * ceil((max(blocksize_bytes, 1000000) / 1000000))
|
||||
ConsensusFork::BitcoinCash(fork_height) if height >= fork_height && block_size > 1_000_000 =>
|
||||
20_000 * (max(block_size, 1_000_000) / 1_000_000),
|
||||
ConsensusFork::NoFork | ConsensusFork::SegWit2x(_) | ConsensusFork::BitcoinCash(_) => 20_000,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -188,13 +209,20 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn test_consensus_fork_max_block_size() {
|
||||
assert_eq!(ConsensusFork::NoFork.max_block_size(0), 1_000_000);
|
||||
assert_eq!(ConsensusFork::SegWit2x(100).max_block_size(0), 1_000_000);
|
||||
assert_eq!(ConsensusFork::SegWit2x(100).max_block_size(100), 2_000_000);
|
||||
assert_eq!(ConsensusFork::SegWit2x(100).max_block_size(200), 2_000_000);
|
||||
assert_eq!(ConsensusFork::BitcoinCash(100).max_block_size(0), 1_000_000);
|
||||
assert_eq!(ConsensusFork::BitcoinCash(100).max_block_size(100), 8_000_000);
|
||||
assert_eq!(ConsensusFork::BitcoinCash(100).max_block_size(200), 8_000_000);
|
||||
fn test_consensus_fork_max_transaction_size() {
|
||||
assert_eq!(ConsensusFork::NoFork.max_transaction_size(0), 1_000_000);
|
||||
assert_eq!(ConsensusFork::SegWit2x(100).max_transaction_size(0), 1_000_000);
|
||||
assert_eq!(ConsensusFork::BitcoinCash(100).max_transaction_size(0), 1_000_000);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_consensus_fork_max_block_sigops() {
|
||||
assert_eq!(ConsensusFork::NoFork.max_block_sigops(0, 1_000_000), 20_000);
|
||||
assert_eq!(ConsensusFork::SegWit2x(100).max_block_sigops(0, 1_000_000), 20_000);
|
||||
assert_eq!(ConsensusFork::SegWit2x(100).max_block_sigops(100, 2_000_000), 20_000);
|
||||
assert_eq!(ConsensusFork::SegWit2x(100).max_block_sigops(200, 3_000_000), 20_000);
|
||||
assert_eq!(ConsensusFork::BitcoinCash(100).max_block_sigops(0, 1_000_000), 20_000);
|
||||
assert_eq!(ConsensusFork::BitcoinCash(100).max_block_sigops(100, 2_000_000), 40_000);
|
||||
assert_eq!(ConsensusFork::BitcoinCash(100).max_block_sigops(200, 3_000_000), 60_000);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,6 @@ use synchronization_server::{Server, ServerTask};
|
|||
use synchronization_verifier::{TransactionVerificationSink};
|
||||
use primitives::hash::H256;
|
||||
use miner::BlockTemplate;
|
||||
use verification::constants::MAX_BLOCK_SIGOPS;
|
||||
use synchronization_peers::{TransactionAnnouncementType, BlockAnnouncementType};
|
||||
use types::{PeerIndex, RequestId, StorageRef, MemoryPoolRef, PeersRef, ExecutorRef,
|
||||
ClientRef, ServerRef, SynchronizationStateRef, SyncListenerRef};
|
||||
|
@ -276,9 +275,11 @@ impl<T, U, V> LocalNode<T, U, V> where T: TaskExecutor, U: Server, V: Client {
|
|||
|
||||
/// Get block template for mining
|
||||
pub fn get_block_template(&self) -> BlockTemplate {
|
||||
let height = self.storage.best_block().number;
|
||||
let max_block_size = self.consensus.fork.max_block_size(height);
|
||||
let block_assembler = BlockAssembler {
|
||||
max_block_size: self.consensus.fork.max_block_size(self.storage.best_block().number) as u32,
|
||||
max_block_sigops: MAX_BLOCK_SIGOPS as u32,
|
||||
max_block_size: max_block_size as u32,
|
||||
max_block_sigops: self.consensus.fork.max_block_sigops(height, max_block_size) as u32,
|
||||
};
|
||||
let memory_pool = &*self.memory_pool.read();
|
||||
block_assembler.create_new_block(&self.storage, memory_pool, time::get_time().sec as u32, self.consensus.magic)
|
||||
|
|
|
@ -6,7 +6,6 @@ use work::block_reward_satoshi;
|
|||
use duplex_store::DuplexTransactionOutputProvider;
|
||||
use deployments::Deployments;
|
||||
use canon::CanonBlock;
|
||||
use constants::MAX_BLOCK_SIGOPS;
|
||||
use error::{Error, TransactionError};
|
||||
use timestamp::median_timestamp;
|
||||
|
||||
|
@ -33,7 +32,7 @@ impl<'a> BlockAcceptor<'a> {
|
|||
serialized_size: BlockSerializedSize::new(block, consensus, height),
|
||||
coinbase_script: BlockCoinbaseScript::new(block, consensus, height),
|
||||
coinbase_claim: BlockCoinbaseClaim::new(block, store, height),
|
||||
sigops: BlockSigops::new(block, store, consensus, MAX_BLOCK_SIGOPS),
|
||||
sigops: BlockSigops::new(block, store, consensus, height),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -110,28 +109,29 @@ impl<'a> BlockSerializedSize<'a> {
|
|||
pub struct BlockSigops<'a> {
|
||||
block: CanonBlock<'a>,
|
||||
store: &'a TransactionOutputProvider,
|
||||
consensus_params: &'a ConsensusParams,
|
||||
max_sigops: usize,
|
||||
consensus: &'a ConsensusParams,
|
||||
height: u32,
|
||||
}
|
||||
|
||||
impl<'a> BlockSigops<'a> {
|
||||
fn new(block: CanonBlock<'a>, store: &'a TransactionOutputProvider, consensus_params: &'a ConsensusParams, max_sigops: usize) -> Self {
|
||||
fn new(block: CanonBlock<'a>, store: &'a TransactionOutputProvider, consensus: &'a ConsensusParams, height: u32) -> Self {
|
||||
BlockSigops {
|
||||
block: block,
|
||||
store: store,
|
||||
consensus_params: consensus_params,
|
||||
max_sigops: max_sigops,
|
||||
consensus: consensus,
|
||||
height: height,
|
||||
}
|
||||
}
|
||||
|
||||
fn check(&self) -> Result<(), Error> {
|
||||
let store = DuplexTransactionOutputProvider::new(self.store, &*self.block);
|
||||
let bip16_active = self.block.header.raw.time >= self.consensus_params.bip16_time;
|
||||
let bip16_active = self.block.header.raw.time >= self.consensus.bip16_time;
|
||||
let sigops = self.block.transactions.iter()
|
||||
.map(|tx| transaction_sigops(&tx.raw, &store, bip16_active))
|
||||
.sum::<usize>();
|
||||
|
||||
if sigops > self.max_sigops {
|
||||
let size = self.block.size();
|
||||
if sigops > self.consensus.fork.max_block_sigops(self.height, size) {
|
||||
Err(Error::MaximumSigops)
|
||||
} else {
|
||||
Ok(())
|
||||
|
|
|
@ -6,7 +6,7 @@ use duplex_store::DuplexTransactionOutputProvider;
|
|||
use deployments::Deployments;
|
||||
use sigops::transaction_sigops;
|
||||
use canon::CanonTransaction;
|
||||
use constants::{COINBASE_MATURITY, MAX_BLOCK_SIGOPS};
|
||||
use constants::{COINBASE_MATURITY};
|
||||
use error::TransactionError;
|
||||
|
||||
pub struct TransactionAcceptor<'a> {
|
||||
|
@ -80,11 +80,12 @@ impl<'a> MemoryPoolTransactionAcceptor<'a> {
|
|||
) -> Self {
|
||||
trace!(target: "verification", "Mempool-Tx verification {}", transaction.hash.to_reversed_str());
|
||||
let transaction_index = 0;
|
||||
let max_block_sigops = consensus.fork.max_block_sigops(height, consensus.fork.max_block_size(height));
|
||||
MemoryPoolTransactionAcceptor {
|
||||
missing_inputs: TransactionMissingInputs::new(transaction, output_store, transaction_index),
|
||||
maturity: TransactionMaturity::new(transaction, meta_store, height),
|
||||
overspent: TransactionOverspent::new(transaction, output_store),
|
||||
sigops: TransactionSigops::new(transaction, output_store, consensus, MAX_BLOCK_SIGOPS, time),
|
||||
sigops: TransactionSigops::new(transaction, output_store, consensus, max_block_sigops, time),
|
||||
double_spent: TransactionDoubleSpend::new(transaction, output_store),
|
||||
eval: TransactionEval::new(transaction, output_store, consensus, height, time, deployments, headers),
|
||||
}
|
||||
|
|
|
@ -352,7 +352,7 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn sigops_overflow_block() {
|
||||
fn absoulte_sigops_overflow_block() {
|
||||
let genesis = test_data::block_builder()
|
||||
.transaction()
|
||||
.coinbase()
|
||||
|
@ -367,12 +367,12 @@ mod tests {
|
|||
let reference_tx = genesis.transactions()[1].hash();
|
||||
|
||||
let mut builder_tx1 = script::Builder::default();
|
||||
for _ in 0..11000 {
|
||||
for _ in 0..81000 {
|
||||
builder_tx1 = builder_tx1.push_opcode(script::Opcode::OP_CHECKSIG)
|
||||
}
|
||||
|
||||
let mut builder_tx2 = script::Builder::default();
|
||||
for _ in 0..11001 {
|
||||
for _ in 0..81001 {
|
||||
builder_tx2 = builder_tx2.push_opcode(script::Opcode::OP_CHECKSIG)
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
pub const BLOCK_MAX_FUTURE: i64 = 2 * 60 * 60; // 2 hours
|
||||
pub const COINBASE_MATURITY: u32 = 100; // 2 hours
|
||||
pub const MAX_BLOCK_SIGOPS: usize = 20_000;
|
||||
pub const MIN_COINBASE_SIZE: usize = 2;
|
||||
pub const MAX_COINBASE_SIZE: usize = 100;
|
||||
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
use std::collections::HashSet;
|
||||
use chain::IndexedBlock;
|
||||
use network::ConsensusFork;
|
||||
use sigops::transaction_sigops;
|
||||
use duplex_store::NoopStore;
|
||||
use error::{Error, TransactionError};
|
||||
use constants::MAX_BLOCK_SIGOPS;
|
||||
|
||||
pub struct BlockVerifier<'a> {
|
||||
pub empty: BlockEmpty<'a>,
|
||||
pub coinbase: BlockCoinbase<'a>,
|
||||
pub serialized_size: BlockSerializedSize<'a>,
|
||||
pub extra_coinbases: BlockExtraCoinbases<'a>,
|
||||
pub transactions_uniqueness: BlockTransactionsUniqueness<'a>,
|
||||
pub sigops: BlockSigops<'a>,
|
||||
|
@ -19,9 +20,10 @@ impl<'a> BlockVerifier<'a> {
|
|||
BlockVerifier {
|
||||
empty: BlockEmpty::new(block),
|
||||
coinbase: BlockCoinbase::new(block),
|
||||
serialized_size: BlockSerializedSize::new(block, ConsensusFork::absolute_maximum_block_size()),
|
||||
extra_coinbases: BlockExtraCoinbases::new(block),
|
||||
transactions_uniqueness: BlockTransactionsUniqueness::new(block),
|
||||
sigops: BlockSigops::new(block, MAX_BLOCK_SIGOPS),
|
||||
sigops: BlockSigops::new(block, ConsensusFork::absolute_maximum_block_sigops()),
|
||||
merkle_root: BlockMerkleRoot::new(block),
|
||||
}
|
||||
}
|
||||
|
@ -29,6 +31,7 @@ impl<'a> BlockVerifier<'a> {
|
|||
pub fn check(&self) -> Result<(), Error> {
|
||||
try!(self.empty.check());
|
||||
try!(self.coinbase.check());
|
||||
try!(self.serialized_size.check());
|
||||
try!(self.extra_coinbases.check());
|
||||
try!(self.transactions_uniqueness.check());
|
||||
try!(self.sigops.check());
|
||||
|
@ -57,6 +60,29 @@ impl<'a> BlockEmpty<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct BlockSerializedSize<'a> {
|
||||
block: &'a IndexedBlock,
|
||||
max_size: usize,
|
||||
}
|
||||
|
||||
impl<'a> BlockSerializedSize<'a> {
|
||||
fn new(block: &'a IndexedBlock, max_size: usize) -> Self {
|
||||
BlockSerializedSize {
|
||||
block: block,
|
||||
max_size: max_size,
|
||||
}
|
||||
}
|
||||
|
||||
fn check(&self) -> Result<(), Error> {
|
||||
let size = self.block.size();
|
||||
if size > self.max_size {
|
||||
Err(Error::Size(size))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct BlockCoinbase<'a> {
|
||||
block: &'a IndexedBlock,
|
||||
}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
use std::ops;
|
||||
use ser::Serializable;
|
||||
use chain::IndexedTransaction;
|
||||
use network::ConsensusParams;
|
||||
use network::{ConsensusParams, ConsensusFork};
|
||||
use duplex_store::NoopStore;
|
||||
use sigops::transaction_sigops;
|
||||
use error::TransactionError;
|
||||
use constants::{MAX_BLOCK_SIGOPS, MIN_COINBASE_SIZE, MAX_COINBASE_SIZE};
|
||||
use constants::{MIN_COINBASE_SIZE, MAX_COINBASE_SIZE};
|
||||
|
||||
pub struct TransactionVerifier<'a> {
|
||||
pub empty: TransactionEmpty<'a>,
|
||||
|
@ -47,7 +47,7 @@ impl<'a> MemoryPoolTransactionVerifier<'a> {
|
|||
null_non_coinbase: TransactionNullNonCoinbase::new(transaction),
|
||||
is_coinbase: TransactionMemoryPoolCoinbase::new(transaction),
|
||||
size: TransactionSize::new(transaction, consensus, height),
|
||||
sigops: TransactionSigops::new(transaction, MAX_BLOCK_SIGOPS),
|
||||
sigops: TransactionSigops::new(transaction, ConsensusFork::absolute_maximum_block_sigops()),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue