From 034bd2fd4f4eae55f85154e2ba6edf26fd74256d Mon Sep 17 00:00:00 2001 From: aggstam Date: Tue, 20 Dec 2022 15:32:29 +0200 Subject: [PATCH] consensus: differentiate bootstrap timestamp from genesis, to not break slot calculation on network restarts --- bin/darkfid/src/main.rs | 15 ++++++++++----- bin/faucetd/src/main.rs | 15 ++++++++++----- src/consensus/constants.rs | 10 +++++++++- src/consensus/state.rs | 4 ++++ src/consensus/task/proposal.rs | 6 +++--- src/consensus/validator.rs | 4 +++- src/contract/money/tests/harness.rs | 7 ++++++- 7 files changed, 45 insertions(+), 16 deletions(-) diff --git a/bin/darkfid/src/main.rs b/bin/darkfid/src/main.rs index 21b0cd209..c750be5d0 100644 --- a/bin/darkfid/src/main.rs +++ b/bin/darkfid/src/main.rs @@ -29,8 +29,8 @@ use darkfi::{ async_daemonize, cli_desc, consensus::{ constants::{ - MAINNET_GENESIS_HASH_BYTES, MAINNET_GENESIS_TIMESTAMP, TESTNET_GENESIS_HASH_BYTES, - TESTNET_GENESIS_TIMESTAMP, + MAINNET_BOOTSTRAP_TIMESTAMP, MAINNET_GENESIS_HASH_BYTES, MAINNET_GENESIS_TIMESTAMP, + TESTNET_BOOTSTRAP_TIMESTAMP, TESTNET_GENESIS_HASH_BYTES, TESTNET_GENESIS_TIMESTAMP, }, proto::{ProtocolProposal, ProtocolSync, ProtocolSyncConsensus, ProtocolTx}, task::{block_sync_task, proposal_task}, @@ -298,9 +298,13 @@ async fn realmain(args: Args, ex: Arc>) -> Result<()> { let sled_db = sled::open(&db_path)?; // Initialize validator state - let (genesis_ts, genesis_data) = match args.chain.as_str() { - "mainnet" => (*MAINNET_GENESIS_TIMESTAMP, *MAINNET_GENESIS_HASH_BYTES), - "testnet" => (*TESTNET_GENESIS_TIMESTAMP, *TESTNET_GENESIS_HASH_BYTES), + let (bootstrap_ts, genesis_ts, genesis_data) = match args.chain.as_str() { + "mainnet" => { + (*MAINNET_BOOTSTRAP_TIMESTAMP, *MAINNET_GENESIS_TIMESTAMP, *MAINNET_GENESIS_HASH_BYTES) + } + "testnet" => { + (*TESTNET_BOOTSTRAP_TIMESTAMP, *TESTNET_GENESIS_TIMESTAMP, *TESTNET_GENESIS_HASH_BYTES) + } x => { error!("Unsupported chain `{}`", x); return Err(Error::UnsupportedChain) @@ -323,6 +327,7 @@ async fn realmain(args: Args, ex: Arc>) -> Result<()> { // Initialize validator state let state = ValidatorState::new( &sled_db, + bootstrap_ts, genesis_ts, genesis_data, wallet.clone(), diff --git a/bin/faucetd/src/main.rs b/bin/faucetd/src/main.rs index ba9a92661..9a0e2c894 100644 --- a/bin/faucetd/src/main.rs +++ b/bin/faucetd/src/main.rs @@ -55,8 +55,8 @@ use darkfi::{ async_daemonize, cli_desc, consensus::{ constants::{ - MAINNET_GENESIS_HASH_BYTES, MAINNET_GENESIS_TIMESTAMP, TESTNET_GENESIS_HASH_BYTES, - TESTNET_GENESIS_TIMESTAMP, + MAINNET_BOOTSTRAP_TIMESTAMP, MAINNET_GENESIS_HASH_BYTES, MAINNET_GENESIS_TIMESTAMP, + TESTNET_BOOTSTRAP_TIMESTAMP, TESTNET_GENESIS_HASH_BYTES, TESTNET_GENESIS_TIMESTAMP, }, proto::{ProtocolSync, ProtocolTx}, task::block_sync_task, @@ -528,9 +528,13 @@ async fn realmain(args: Args, ex: Arc>) -> Result<()> { let sled_db = sled::open(&db_path)?; // Initialize validator state - let (genesis_ts, genesis_data) = match args.chain.as_str() { - "mainnet" => (*MAINNET_GENESIS_TIMESTAMP, *MAINNET_GENESIS_HASH_BYTES), - "testnet" => (*TESTNET_GENESIS_TIMESTAMP, *TESTNET_GENESIS_HASH_BYTES), + let (bootstrap_ts, genesis_ts, genesis_data) = match args.chain.as_str() { + "mainnet" => { + (*MAINNET_BOOTSTRAP_TIMESTAMP, *MAINNET_GENESIS_TIMESTAMP, *MAINNET_GENESIS_HASH_BYTES) + } + "testnet" => { + (*TESTNET_BOOTSTRAP_TIMESTAMP, *TESTNET_GENESIS_TIMESTAMP, *TESTNET_GENESIS_HASH_BYTES) + } x => { error!("Unsupported chain `{}`", x); return Err(Error::UnsupportedChain) @@ -553,6 +557,7 @@ async fn realmain(args: Args, ex: Arc>) -> Result<()> { // Initialize validator state let state = ValidatorState::new( &sled_db, + bootstrap_ts, genesis_ts, genesis_data, wallet.clone(), diff --git a/src/consensus/constants.rs b/src/consensus/constants.rs index cc72a306d..f79cb946f 100644 --- a/src/consensus/constants.rs +++ b/src/consensus/constants.rs @@ -24,14 +24,22 @@ lazy_static! { /// Genesis hash for the mainnet chain pub static ref MAINNET_GENESIS_HASH_BYTES: blake3::Hash = blake3::hash(b"darkfi_mainnet"); + // NOTE: On initial network bootstrap, genesis timestamp should be equal to boostrap timestamp. + // On network restart only change bootstrap timestamp to schedule when nodes become active. /// Genesis timestamp for the mainnet chain pub static ref MAINNET_GENESIS_TIMESTAMP: Timestamp = Timestamp(1650887115); + /// Bootstrap timestamp for the mainnet chain + pub static ref MAINNET_BOOTSTRAP_TIMESTAMP: Timestamp = Timestamp(1650887115); + /// Genesis hash for the testnet chain pub static ref TESTNET_GENESIS_HASH_BYTES: blake3::Hash = blake3::hash(b"darkfi_testnet"); /// Genesis timestamp for the testnet chain - pub static ref TESTNET_GENESIS_TIMESTAMP: Timestamp = Timestamp(1671330180); + pub static ref TESTNET_GENESIS_TIMESTAMP: Timestamp = Timestamp(1671546600); + + /// Bootstrap timestamp for the testnet chain + pub static ref TESTNET_BOOTSTRAP_TIMESTAMP: Timestamp = Timestamp(1671546600); // Commonly used Float10 pub static ref FLOAT10_ZERO: Float10 = Float10::from_str_native("0").unwrap().with_precision(RADIX_BITS).value(); diff --git a/src/consensus/state.rs b/src/consensus/state.rs index 117225353..3e97e9d35 100644 --- a/src/consensus/state.rs +++ b/src/consensus/state.rs @@ -42,6 +42,8 @@ use dashu::base::Abs; pub struct ConsensusState { /// Canonical (finalized) blockchain pub blockchain: Blockchain, + /// Network bootstrap timestamp + pub bootstrap_ts: Timestamp, /// Genesis block creation timestamp pub genesis_ts: Timestamp, /// Genesis block hash @@ -78,12 +80,14 @@ pub struct ConsensusState { impl ConsensusState { pub fn new( blockchain: Blockchain, + bootstrap_ts: Timestamp, genesis_ts: Timestamp, genesis_data: blake3::Hash, ) -> Result { let genesis_block = Block::genesis_block(genesis_ts, genesis_data).blockhash(); Ok(Self { blockchain, + bootstrap_ts, genesis_ts, genesis_block, bootstrap_slot: 0, diff --git a/src/consensus/task/proposal.rs b/src/consensus/task/proposal.rs index 95c4bbf9b..70db0a46a 100644 --- a/src/consensus/task/proposal.rs +++ b/src/consensus/task/proposal.rs @@ -40,9 +40,9 @@ pub async fn proposal_task( // NOTE: Network beign configured to start in the future should always be the case // when bootstrapping or restarting a network. let current_ts = Timestamp::current_time(); - let genesis_ts = state.read().await.consensus.genesis_ts; - if current_ts < genesis_ts { - let diff = genesis_ts.0 - current_ts.0; + let bootstrap_ts = state.read().await.consensus.bootstrap_ts; + if current_ts < bootstrap_ts { + let diff = bootstrap_ts.0 - current_ts.0; info!("consensus: Waiting for network bootstrap: {} seconds", diff); sleep(diff as u64).await; } else { diff --git a/src/consensus/validator.rs b/src/consensus/validator.rs index 013d0d256..d7fe74d8b 100644 --- a/src/consensus/validator.rs +++ b/src/consensus/validator.rs @@ -92,6 +92,7 @@ pub struct ValidatorState { impl ValidatorState { pub async fn new( db: &sled::Db, // <-- TODO: Avoid this with some wrapping, sled should only be in blockchain + bootstrap_ts: Timestamp, genesis_ts: Timestamp, genesis_data: blake3::Hash, wallet: WalletPtr, @@ -123,7 +124,8 @@ impl ValidatorState { }; let blockchain = Blockchain::new(db, genesis_ts, genesis_data)?; - let consensus = ConsensusState::new(blockchain.clone(), genesis_ts, genesis_data)?; + let consensus = + ConsensusState::new(blockchain.clone(), bootstrap_ts, genesis_ts, genesis_data)?; let unconfirmed_txs = vec![]; diff --git a/src/contract/money/tests/harness.rs b/src/contract/money/tests/harness.rs index bf6a9682c..b89c67712 100644 --- a/src/contract/money/tests/harness.rs +++ b/src/contract/money/tests/harness.rs @@ -19,7 +19,9 @@ use std::collections::HashMap; use darkfi::{ consensus::{ - constants::{TESTNET_GENESIS_HASH_BYTES, TESTNET_GENESIS_TIMESTAMP}, + constants::{ + TESTNET_BOOTSTRAP_TIMESTAMP, TESTNET_GENESIS_HASH_BYTES, TESTNET_GENESIS_TIMESTAMP, + }, ValidatorState, ValidatorStatePtr, }, tx::Transaction, @@ -100,6 +102,7 @@ impl MoneyTestHarness { let faucet_state = ValidatorState::new( &faucet_sled_db, + *TESTNET_BOOTSTRAP_TIMESTAMP, *TESTNET_GENESIS_TIMESTAMP, *TESTNET_GENESIS_HASH_BYTES, faucet_wallet, @@ -110,6 +113,7 @@ impl MoneyTestHarness { let alice_state = ValidatorState::new( &alice_sled_db, + *TESTNET_BOOTSTRAP_TIMESTAMP, *TESTNET_GENESIS_TIMESTAMP, *TESTNET_GENESIS_HASH_BYTES, alice_wallet, @@ -120,6 +124,7 @@ impl MoneyTestHarness { let bob_state = ValidatorState::new( &bob_sled_db, + *TESTNET_BOOTSTRAP_TIMESTAMP, *TESTNET_GENESIS_TIMESTAMP, *TESTNET_GENESIS_HASH_BYTES, bob_wallet,