From 4f9811fe6f854ee602360848ada56bcd6be12418 Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Tue, 22 Aug 2017 12:49:33 +0300 Subject: [PATCH] segwit2x: get rid of hardcoded SegWit constants --- network/src/consensus.rs | 39 ++++++++++++++++++++------------ network/src/lib.rs | 2 +- verification/src/accept_block.rs | 6 ++--- verification/src/sigops.rs | 5 ++-- 4 files changed, 31 insertions(+), 21 deletions(-) diff --git a/network/src/consensus.rs b/network/src/consensus.rs index 945d39ab..0660b00b 100644 --- a/network/src/consensus.rs +++ b/network/src/consensus.rs @@ -7,16 +7,6 @@ pub const SEGWIT2X_FORK_BLOCK: u32 = 0xFFFFFFFF; // not known (yet?) /// First block of BitcoinCash fork. pub const BITCOIN_CASH_FORK_BLOCK: u32 = 478559; // https://blockchair.com/bitcoin-cash/block/478559 -/// Segwit-related constants. -pub mod segwit { - /// The maximum allowed weight for a block, see BIP 141 (network rule). - pub const MAX_BLOCK_WEIGHT: usize = 4_000_000; - /// The maximum allowed number of signature check operations in a block (network rule). - pub const MAX_BLOCK_SIGOPS_COST: usize = 80_000; - /// Witness scale factor. - pub const WITNESS_SCALE_FACTOR: usize = 4; -} - #[derive(Debug, Clone)] /// Parameters that influence chain consensus. pub struct ConsensusParams { @@ -57,6 +47,7 @@ pub enum ConsensusFork { /// Technical specification: /// Segregated Witness (Consensus layer) - https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki /// Block size increase to 2MB - https://github.com/bitcoin/bips/blob/master/bip-0102.mediawiki + /// Readiness checklist - https://segwit2x.github.io/segwit2x-announce.html SegWit2x(u32), /// Bitcoin Cash (aka UAHF). /// `u32` is height of the first block, for which new consensus rules are applied. @@ -171,6 +162,11 @@ impl ConsensusFork { 160_000 } + /// Witness scale factor (equal among all forks) + pub fn witness_scale_factor() -> usize { + 4 + } + pub fn max_transaction_size(&self) -> usize { // BitcoinCash: according to REQ-5: max size of tx is still 1_000_000 // SegWit: size * 4 <= 4_000_000 ===> max size of tx is still 1_000_000 @@ -198,6 +194,8 @@ impl ConsensusFork { // 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::SegWit2x(fork_height) if height >= fork_height => + 40_000, ConsensusFork::NoFork | ConsensusFork::SegWit2x(_) | ConsensusFork::BitcoinCash(_) => 20_000, } } @@ -205,9 +203,22 @@ impl ConsensusFork { pub fn max_block_sigops_cost(&self, height: u32, block_size: usize) -> usize { match *self { ConsensusFork::BitcoinCash(_) => - self.max_block_sigops(height, block_size) * segwit::WITNESS_SCALE_FACTOR, + self.max_block_sigops(height, block_size) * Self::witness_scale_factor(), + ConsensusFork::SegWit2x(fork_height) if height >= fork_height => + 160_000, ConsensusFork::NoFork | ConsensusFork::SegWit2x(_) => - segwit::MAX_BLOCK_SIGOPS_COST, + 80_000, + } + } + + pub fn max_block_weight(&self, height: u32) -> usize { + match *self { + ConsensusFork::SegWit2x(fork_height) if height >= fork_height => + 8_000_000, + ConsensusFork::NoFork | ConsensusFork::SegWit2x(_) => + 4_000_000, + ConsensusFork::BitcoinCash(_) => + unreachable!("BitcoinCash has no SegWit; weight is only checked with SegWit activated; qed"), } } } @@ -272,8 +283,8 @@ mod tests { 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::SegWit2x(100).max_block_sigops(100, 2_000_000), 40_000); + assert_eq!(ConsensusFork::SegWit2x(100).max_block_sigops(200, 3_000_000), 40_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); diff --git a/network/src/lib.rs b/network/src/lib.rs index 8c562948..7b97f698 100644 --- a/network/src/lib.rs +++ b/network/src/lib.rs @@ -8,7 +8,7 @@ mod magic; pub use primitives::{hash, compact}; -pub use consensus::{ConsensusParams, ConsensusFork, SEGWIT2X_FORK_BLOCK, BITCOIN_CASH_FORK_BLOCK, segwit}; +pub use consensus::{ConsensusParams, ConsensusFork, SEGWIT2X_FORK_BLOCK, BITCOIN_CASH_FORK_BLOCK}; pub use deployments::Deployment; pub use magic::Magic; diff --git a/verification/src/accept_block.rs b/verification/src/accept_block.rs index 808c8d87..4f169bf2 100644 --- a/verification/src/accept_block.rs +++ b/verification/src/accept_block.rs @@ -1,4 +1,4 @@ -use network::{ConsensusParams, segwit}; +use network::{ConsensusParams, ConsensusFork}; use crypto::dhash256; use db::{TransactionOutputProvider, BlockHeaderProvider}; use script; @@ -113,8 +113,8 @@ impl<'a> BlockSerializedSize<'a> { if self.segwit_active { let size_with_witness = self.block.size_with_witness(); - let weight = size * (segwit::WITNESS_SCALE_FACTOR - 1) + size_with_witness; - if weight > segwit::MAX_BLOCK_WEIGHT { + let weight = size * (ConsensusFork::witness_scale_factor() - 1) + size_with_witness; + if weight > self.consensus.fork.max_block_weight(self.height) { return Err(Error::Weight); } } diff --git a/verification/src/sigops.rs b/verification/src/sigops.rs index d24340a0..e2181f32 100644 --- a/verification/src/sigops.rs +++ b/verification/src/sigops.rs @@ -1,5 +1,4 @@ -// TODO: excess clones -use network::segwit; +use network::ConsensusFork; use chain::Transaction; use db::TransactionOutputProvider; use script::{Script, ScriptWitness}; @@ -47,7 +46,7 @@ pub fn transaction_sigops_cost( store: &TransactionOutputProvider, sigops: usize, ) -> usize { - let sigops_cost = sigops * segwit::WITNESS_SCALE_FACTOR; + let sigops_cost = sigops * ConsensusFork::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()), &input.script_witness,))