Skip to content

Commit

Permalink
refactor: Halve target block interval
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
Sword-Smith and aszepieniec committed Jan 30, 2025
1 parent fd4652d commit 89c04cb
Show file tree
Hide file tree
Showing 5 changed files with 33 additions and 26 deletions.
4 changes: 2 additions & 2 deletions src/models/blockchain/block/block_header.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
///
Expand Down
10 changes: 6 additions & 4 deletions src/models/blockchain/block/block_height.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down
6 changes: 3 additions & 3 deletions src/models/blockchain/block/difficulty_control.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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]);

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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 =
Expand Down
26 changes: 16 additions & 10 deletions src/models/blockchain/block/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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| {
Expand Down Expand Up @@ -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)
Expand Down
13 changes: 6 additions & 7 deletions src/models/blockchain/type_scripts/native_currency_amount.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}

Expand Down

0 comments on commit 89c04cb

Please sign in to comment.