segwit2x: get rid of hardcoded SegWit constants

This commit is contained in:
Svyatoslav Nikolsky 2017-08-22 12:49:33 +03:00
parent 07e5064755
commit 4f9811fe6f
4 changed files with 31 additions and 21 deletions

View File

@ -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);

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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,))