From 89c04cb79b2f2583d67418b4d9b3b4b83b5e1c11 Mon Sep 17 00:00:00 2001 From: sword_smith Date: Thu, 30 Jan 2025 12:24:16 +0100 Subject: [PATCH] refactor: Halve target block interval Mess with time. Why? Current top-end CPUs can compose in less than five minutes. Future GPU composers will be significantly faster. We believe this hits a sweet-spot where future advances in proving time are assumed and where current state-of-the-art CPU proving can still compose in less time than the target interval. Also: network quality in practice is good enough for faster blocks, as evidenced by other blockchains than Bitcoin with faster blocks and no more frequent block races than Bitcoin. Co-authored-by: Alan Szepieniec --- src/models/blockchain/block/block_header.rs | 4 +-- src/models/blockchain/block/block_height.rs | 10 ++++--- .../blockchain/block/difficulty_control.rs | 6 ++--- src/models/blockchain/block/mod.rs | 26 ++++++++++++------- .../type_scripts/native_currency_amount.rs | 13 +++++----- 5 files changed, 33 insertions(+), 26 deletions(-) diff --git a/src/models/blockchain/block/block_header.rs b/src/models/blockchain/block/block_header.rs index 21a8cac8..cf26bc1f 100644 --- a/src/models/blockchain/block/block_header.rs +++ b/src/models/blockchain/block/block_header.rs @@ -26,8 +26,8 @@ use crate::prelude::twenty_first; /// Desired/average time between blocks. /// -/// 588000 milliseconds equals 9.8 minutes. -pub(crate) const TARGET_BLOCK_INTERVAL: Timestamp = Timestamp::millis(588000); +/// 294000 milliseconds equals 4.9 minutes. +pub(crate) const TARGET_BLOCK_INTERVAL: Timestamp = Timestamp::millis(294000); /// Minimum time between blocks. /// diff --git a/src/models/blockchain/block/block_height.rs b/src/models/blockchain/block/block_height.rs index 3ad0948c..1a73442f 100644 --- a/src/models/blockchain/block/block_height.rs +++ b/src/models/blockchain/block/block_height.rs @@ -22,9 +22,9 @@ use crate::prelude::twenty_first; #[cfg_attr(any(test, feature = "arbitrary-impls"), derive(Arbitrary))] pub struct BlockHeight(BFieldElement); -// Assuming a block time of 588 seconds, and a halving every three years, -// the number of blocks per halving cycle is 160815. -pub const BLOCKS_PER_GENERATION: u64 = 160815; +// Assuming a block time of 294 seconds, and a halving every three years, +// the number of blocks per halving cycle is 321630. +pub const BLOCKS_PER_GENERATION: u64 = 321630; impl BlockHeight { pub fn get_generation(&self) -> u64 { @@ -133,6 +133,7 @@ mod test { use tracing_test::traced_test; use super::*; + use crate::models::blockchain::block::block_tests::PREMINE_MAX_SIZE; use crate::models::blockchain::block::Block; use crate::models::blockchain::block::TARGET_BLOCK_INTERVAL; use crate::models::blockchain::type_scripts::native_currency_amount::NativeCurrencyAmount; @@ -171,7 +172,8 @@ mod test { .checked_sub(&generation_0_subsidy) .unwrap(); - let designated_premine = NativeCurrencyAmount::coins(831488); + println!("mineable_amount: {mineable_amount}"); + let designated_premine = PREMINE_MAX_SIZE; let asymptotic_limit = mineable_amount.checked_add(&designated_premine).unwrap(); let expected_limit = NativeCurrencyAmount::coins(42_000_000); diff --git a/src/models/blockchain/block/difficulty_control.rs b/src/models/blockchain/block/difficulty_control.rs index f4289b81..8d673509 100644 --- a/src/models/blockchain/block/difficulty_control.rs +++ b/src/models/blockchain/block/difficulty_control.rs @@ -45,7 +45,7 @@ pub struct Difficulty([u32; DIFFICULTY_NUM_LIMBS]); impl Difficulty { pub const NUM_LIMBS: usize = DIFFICULTY_NUM_LIMBS; - const LIMBS_FOR_MINIMUM: [u32; Self::NUM_LIMBS] = [1000, 0, 0, 0, 0]; + const LIMBS_FOR_MINIMUM: [u32; Self::NUM_LIMBS] = [6000, 0, 0, 0, 0]; pub const MINIMUM: Self = Self::new(Self::LIMBS_FOR_MINIMUM); pub const MAXIMUM: Self = Self::new([u32::MAX; Self::NUM_LIMBS]); @@ -472,7 +472,7 @@ pub(crate) fn max_cumulative_pow_after( // allowed by the consensus rules, the clamped relative error is almost -1. // In this case the PID adjustment factor is // f = 1 + (MINIMUM_BLOCK_TIME - TARGET_BLOCK_INTERVAL) / TARGET_BLOCK_INTERVAL * P - // = 1 - (60 - 588) / 588 / 16, + // = 1 - (60 - 294) / 294 / 16, const EPSILON: f64 = 0.000001; let f = 1.0_f64 + (TARGET_BLOCK_INTERVAL.to_millis() - MINIMUM_BLOCK_TIME.to_millis()) as f64 @@ -907,7 +907,7 @@ mod test { fn test_sanity_max_pow_after_unit() { let init_cumpow = 100u64; let init_cumpow = ProofOfWork::from_u64(init_cumpow); - let init_difficulty = Difficulty::from_u64(1000u64); + let init_difficulty = Difficulty::MINIMUM; let num_blocks = 1000; let calculated = max_cumulative_pow_after(init_cumpow, init_difficulty, num_blocks); let approximation = diff --git a/src/models/blockchain/block/mod.rs b/src/models/blockchain/block/mod.rs index e6dd9891..591fb166 100644 --- a/src/models/blockchain/block/mod.rs +++ b/src/models/blockchain/block/mod.rs @@ -84,6 +84,8 @@ pub(crate) const MAX_BLOCK_SIZE: usize = 250_000; /// is time locked for this period. pub(crate) const MINING_REWARD_TIME_LOCK_PERIOD: Timestamp = Timestamp::years(3); +pub(crate) const INITIAL_BLOCK_SUBSIDY: NativeCurrencyAmount = NativeCurrencyAmount::coins(64); + /// All blocks have proofs except the genesis block #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, BFieldCodec, GetSize, Default)] pub enum BlockProof { @@ -409,15 +411,17 @@ impl Block { /// The number of coins that can be printed into existence with the mining /// a block with this height. pub fn block_subsidy(block_height: BlockHeight) -> NativeCurrencyAmount { - let mut reward: NativeCurrencyAmount = NativeCurrencyAmount::coins(128); + let mut reward: NativeCurrencyAmount = INITIAL_BLOCK_SUBSIDY; let generation = block_height.get_generation(); - if generation > 128 { - return NativeCurrencyAmount::zero(); - } - for _ in 0..generation { - reward.div_two() + reward.div_two(); + + // Early return here is important bc of test-case generators with + // arbitrary block heights. + if reward.is_zero() { + return NativeCurrencyAmount::zero(); + } } reward @@ -1034,7 +1038,7 @@ impl Block { } #[cfg(test)] -mod block_tests { +pub(crate) mod block_tests { use rand::random; use rand::rngs::StdRng; use rand::thread_rng; @@ -1062,6 +1066,8 @@ mod block_tests { use crate::tests::shared::mock_genesis_global_state; use crate::util_types::archival_mmr::ArchivalMmr; + pub(crate) const PREMINE_MAX_SIZE: NativeCurrencyAmount = NativeCurrencyAmount::coins(831424); + #[test] fn all_genesis_blocks_have_unique_mutator_set_hashes() { let mutator_set_hash = |network| { @@ -1232,11 +1238,11 @@ mod block_tests { #[test] fn test_premine_size() { - // 831488 = 42000000 * 0.019797333333333333 + // 831424 = 42000000 * 0.01979581 // where 42000000 is the asymptotical limit of the token supply - // and 1.9797333...% is the relative size of the premine + // and 0.01979581...% is the relative size of the premine let asymptotic_total_cap = NativeCurrencyAmount::coins(42_000_000); - let premine_max_size = NativeCurrencyAmount::coins(831488); + let premine_max_size = PREMINE_MAX_SIZE; let total_premine = Block::premine_distribution() .iter() .map(|(_receiving_address, amount)| *amount) diff --git a/src/models/blockchain/type_scripts/native_currency_amount.rs b/src/models/blockchain/type_scripts/native_currency_amount.rs index 668b8b2e..308efef5 100644 --- a/src/models/blockchain/type_scripts/native_currency_amount.rs +++ b/src/models/blockchain/type_scripts/native_currency_amount.rs @@ -100,18 +100,17 @@ impl NativeCurrencyAmount { product } - /// Return the element that corresponds to 1. Use in tests only. + /// Return the element that corresponds to 1 nau. Use in tests only. pub fn one() -> NativeCurrencyAmount { NativeCurrencyAmount(1i128) } /// Create an NativeCurrencyAmount object of the given number of whole coins. - pub fn coins(num_whole_coins: u32) -> NativeCurrencyAmount { - assert!( - num_whole_coins <= 42000000, - "Number of coins must be less than 42000000" - ); - let number: i128 = num_whole_coins.into(); + pub const fn coins(num_whole_coins: u32) -> NativeCurrencyAmount { + if num_whole_coins > 42_000_000 { + panic!("Number of coins must be less than 42000000"); + } + let number: i128 = num_whole_coins as i128; Self(Self::conversion_factor() * number) }