diff --git a/bin/darkfid/src/main.rs b/bin/darkfid/src/main.rs index c750be5d0..b923fe538 100644 --- a/bin/darkfid/src/main.rs +++ b/bin/darkfid/src/main.rs @@ -30,7 +30,8 @@ use darkfi::{ consensus::{ constants::{ MAINNET_BOOTSTRAP_TIMESTAMP, MAINNET_GENESIS_HASH_BYTES, MAINNET_GENESIS_TIMESTAMP, - TESTNET_BOOTSTRAP_TIMESTAMP, TESTNET_GENESIS_HASH_BYTES, TESTNET_GENESIS_TIMESTAMP, + MAINNET_INITIAL_DISTRIBUTION, TESTNET_BOOTSTRAP_TIMESTAMP, TESTNET_GENESIS_HASH_BYTES, + TESTNET_GENESIS_TIMESTAMP, TESTNET_INITIAL_DISTRIBUTION, }, proto::{ProtocolProposal, ProtocolSync, ProtocolSyncConsensus, ProtocolTx}, task::{block_sync_task, proposal_task}, @@ -298,13 +299,19 @@ async fn realmain(args: Args, ex: Arc>) -> Result<()> { let sled_db = sled::open(&db_path)?; // Initialize validator state - 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) - } + let (bootstrap_ts, genesis_ts, genesis_data, initial_distribution) = match args.chain.as_str() { + "mainnet" => ( + *MAINNET_BOOTSTRAP_TIMESTAMP, + *MAINNET_GENESIS_TIMESTAMP, + *MAINNET_GENESIS_HASH_BYTES, + *MAINNET_INITIAL_DISTRIBUTION, + ), + "testnet" => ( + *TESTNET_BOOTSTRAP_TIMESTAMP, + *TESTNET_GENESIS_TIMESTAMP, + *TESTNET_GENESIS_HASH_BYTES, + *TESTNET_INITIAL_DISTRIBUTION, + ), x => { error!("Unsupported chain `{}`", x); return Err(Error::UnsupportedChain) @@ -330,6 +337,7 @@ async fn realmain(args: Args, ex: Arc>) -> Result<()> { bootstrap_ts, genesis_ts, genesis_data, + initial_distribution, wallet.clone(), faucet_pubkeys, args.consensus, diff --git a/bin/faucetd/src/main.rs b/bin/faucetd/src/main.rs index 9a0e2c894..2bb416296 100644 --- a/bin/faucetd/src/main.rs +++ b/bin/faucetd/src/main.rs @@ -56,7 +56,8 @@ use darkfi::{ consensus::{ constants::{ MAINNET_BOOTSTRAP_TIMESTAMP, MAINNET_GENESIS_HASH_BYTES, MAINNET_GENESIS_TIMESTAMP, - TESTNET_BOOTSTRAP_TIMESTAMP, TESTNET_GENESIS_HASH_BYTES, TESTNET_GENESIS_TIMESTAMP, + MAINNET_INITIAL_DISTRIBUTION, TESTNET_BOOTSTRAP_TIMESTAMP, TESTNET_GENESIS_HASH_BYTES, + TESTNET_GENESIS_TIMESTAMP, TESTNET_INITIAL_DISTRIBUTION, }, proto::{ProtocolSync, ProtocolTx}, task::block_sync_task, @@ -528,13 +529,19 @@ async fn realmain(args: Args, ex: Arc>) -> Result<()> { let sled_db = sled::open(&db_path)?; // Initialize validator state - 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) - } + let (bootstrap_ts, genesis_ts, genesis_data, initial_distribution) = match args.chain.as_str() { + "mainnet" => ( + *MAINNET_BOOTSTRAP_TIMESTAMP, + *MAINNET_GENESIS_TIMESTAMP, + *MAINNET_GENESIS_HASH_BYTES, + *MAINNET_INITIAL_DISTRIBUTION, + ), + "testnet" => ( + *TESTNET_BOOTSTRAP_TIMESTAMP, + *TESTNET_GENESIS_TIMESTAMP, + *TESTNET_GENESIS_HASH_BYTES, + *TESTNET_INITIAL_DISTRIBUTION, + ), x => { error!("Unsupported chain `{}`", x); return Err(Error::UnsupportedChain) @@ -560,6 +567,7 @@ async fn realmain(args: Args, ex: Arc>) -> Result<()> { bootstrap_ts, genesis_ts, genesis_data, + initial_distribution, wallet.clone(), faucet_pubkeys, false, diff --git a/src/consensus/constants.rs b/src/consensus/constants.rs index f79cb946f..02d0a73e2 100644 --- a/src/consensus/constants.rs +++ b/src/consensus/constants.rs @@ -32,6 +32,9 @@ lazy_static! { /// Bootstrap timestamp for the mainnet chain pub static ref MAINNET_BOOTSTRAP_TIMESTAMP: Timestamp = Timestamp(1650887115); + /// Total sum of initial staking coins for the mainnet chain + pub static ref MAINNET_INITIAL_DISTRIBUTION: u64 = 1000; + /// Genesis hash for the testnet chain pub static ref TESTNET_GENESIS_HASH_BYTES: blake3::Hash = blake3::hash(b"darkfi_testnet"); @@ -41,22 +44,25 @@ lazy_static! { /// Bootstrap timestamp for the testnet chain pub static ref TESTNET_BOOTSTRAP_TIMESTAMP: Timestamp = Timestamp(1671546600); + /// Total sum of initial staking coins for the testnet chain + pub static ref TESTNET_INITIAL_DISTRIBUTION: u64 = 1000; + // Commonly used Float10 - pub static ref FLOAT10_ZERO: Float10 = Float10::from_str_native("0").unwrap().with_precision(RADIX_BITS).value(); - pub static ref FLOAT10_ONE: Float10 = Float10::from_str_native("1").unwrap().with_precision(RADIX_BITS).value(); - pub static ref FLOAT10_TWO: Float10 = Float10::from_str_native("2").unwrap().with_precision(RADIX_BITS).value(); - pub static ref FLOAT10_THREE: Float10 = Float10::from_str_native("3").unwrap().with_precision(RADIX_BITS).value(); - pub static ref FLOAT10_FIVE: Float10 = Float10::from_str_native("5").unwrap().with_precision(RADIX_BITS).value(); - pub static ref FLOAT10_NINE: Float10 = Float10::from_str_native("9").unwrap().with_precision(RADIX_BITS).value(); - pub static ref FLOAT10_TEN: Float10 = Float10::from_str_native("10").unwrap().with_precision(RADIX_BITS).value(); + pub static ref FLOAT10_ZERO: Float10 = Float10::from_str_native("0").unwrap().with_precision(RADIX_BITS).value(); + pub static ref FLOAT10_ONE: Float10 = Float10::from_str_native("1").unwrap().with_precision(RADIX_BITS).value(); + pub static ref FLOAT10_TWO: Float10 = Float10::from_str_native("2").unwrap().with_precision(RADIX_BITS).value(); + pub static ref FLOAT10_THREE: Float10 = Float10::from_str_native("3").unwrap().with_precision(RADIX_BITS).value(); + pub static ref FLOAT10_FIVE: Float10 = Float10::from_str_native("5").unwrap().with_precision(RADIX_BITS).value(); + pub static ref FLOAT10_NINE: Float10 = Float10::from_str_native("9").unwrap().with_precision(RADIX_BITS).value(); + pub static ref FLOAT10_TEN: Float10 = Float10::from_str_native("10").unwrap().with_precision(RADIX_BITS).value(); // Consensus parameters - pub static ref DT: Float10 = Float10::from_str_native("0.1").unwrap().with_precision(RADIX_BITS).value(); - pub static ref TI: Float10 = FLOAT10_ONE.clone(); - pub static ref TD: Float10 = FLOAT10_ONE.clone(); - pub static ref KP: Float10 = Float10::from_str_native("0.1").unwrap().with_precision(RADIX_BITS).value(); - pub static ref KI: Float10 = Float10::from_str_native("0.03").unwrap().with_precision(RADIX_BITS).value(); - pub static ref KD: Float10 = FLOAT10_ONE.clone(); + pub static ref DT: Float10 = Float10::from_str_native("0.1").unwrap().with_precision(RADIX_BITS).value(); + pub static ref TI: Float10 = FLOAT10_ONE.clone(); + pub static ref TD: Float10 = FLOAT10_ONE.clone(); + pub static ref KP: Float10 = Float10::from_str_native("0.1").unwrap().with_precision(RADIX_BITS).value(); + pub static ref KI: Float10 = Float10::from_str_native("0.03").unwrap().with_precision(RADIX_BITS).value(); + pub static ref KD: Float10 = FLOAT10_ONE.clone(); pub static ref PID_OUT_STEP: Float10 = Float10::from_str_native("0.1").unwrap().with_precision(RADIX_BITS).value(); pub static ref MAX_DER: Float10 = Float10::from_str_native("0.1").unwrap().with_precision(RADIX_BITS).value(); pub static ref MIN_DER: Float10 = Float10::from_str_native("-0.1").unwrap().with_precision(RADIX_BITS).value(); @@ -113,4 +119,4 @@ pub const PI_MU_Y_INDEX: usize = 8; pub const PI_MU_RHO_INDEX: usize = 10; pub const PI_SIGMA1_INDEX: usize = 12; pub const PI_SIGMA2_INDEX: usize = 13; -pub const GENESIS_TOTAL_STAKE: i64 = 1; +pub const GENESIS_TOTAL_STAKE: u64 = 1; diff --git a/src/consensus/state.rs b/src/consensus/state.rs index 35458f778..dc7a5b6eb 100644 --- a/src/consensus/state.rs +++ b/src/consensus/state.rs @@ -48,6 +48,8 @@ pub struct ConsensusState { pub genesis_ts: Timestamp, /// Genesis block hash pub genesis_block: blake3::Hash, + /// Total sum of initial staking coins + pub initial_distribution: u64, /// Slot the network was bootstrapped pub bootstrap_slot: u64, /// Participating start slot @@ -83,6 +85,7 @@ impl ConsensusState { bootstrap_ts: Timestamp, genesis_ts: Timestamp, genesis_data: blake3::Hash, + initial_distribution: u64, ) -> Result { let genesis_block = Block::genesis_block(genesis_ts, genesis_data).blockhash(); Ok(Self { @@ -90,6 +93,7 @@ impl ConsensusState { bootstrap_ts, genesis_ts, genesis_block, + initial_distribution, bootstrap_slot: 0, participating: None, proposing: false, @@ -229,18 +233,10 @@ impl ConsensusState { Ok(true) } - /// return 2-term target approximation sigma coefficients. + /// Return 2-term target approximation sigma coefficients. pub fn sigmas(&mut self) -> (pallas::Base, pallas::Base) { let f = self.win_inv_prob_with_full_stake(); - - // Generate sigmas - let mut total_stake = self.total_stake(); // Only used for fine-tuning - // at genesis epoch first slot, of absolute index 0, - // the total stake would be 0, to avoid division by zero, - // we asume total stake at first division is GENESIS_TOTAL_STAKE. - if total_stake == 0 { - total_stake = constants::GENESIS_TOTAL_STAKE; - } + let total_stake = self.total_stake(); info!("sigmas(): f: {}", f); info!("sigmas(): stake: {}", total_stake); let one = constants::FLOAT10_ONE.clone(); @@ -284,10 +280,13 @@ impl ConsensusState { // The wallet has specific tables for consensus coins. // TODO: TESTNET: Token ID still has to be enforced properly in the consensus. - // Temporarily, we compete with zero stake + // Temporarily, we compete with fixed stake. + // This stake should be based on how many nodes we want to run, and they all + // must sum to initial distribution total coins. + let stake = self.initial_distribution; let coin = LeadCoin::new( eta, - rand::thread_rng().gen_range(0..1000), + stake, slot, epoch_secrets.secret_keys[0].inner(), epoch_secrets.merkle_roots[0], @@ -301,9 +300,9 @@ impl ConsensusState { Ok(coins) } - /// leadership reward, assuming constant reward + /// Leadership reward, assuming constant reward /// TODO (res) implement reward mechanism with accord to DRK,DARK token-economics - fn reward() -> u64 { + fn reward(&self) -> u64 { constants::REWARD } @@ -341,11 +340,19 @@ impl ConsensusState { current_slot - blocks - self.get_current_offset(current_slot) - max_fork_length } - /// total stake - /// assuming constant Reward. - fn total_stake(&mut self) -> i64 { + /// Network total stake, assuming constant reward. + /// Only used for fine-tuning. At genesis epoch first slot, of absolute index 0, + /// if no stake was distributed, the total stake would be 0. + /// To avoid division by zero, we asume total stake at first division is GENESIS_TOTAL_STAKE(1). + fn total_stake(&mut self) -> u64 { let current_slot = self.current_slot(); - ((current_slot - self.overall_empty_slots(current_slot)) * Self::reward()) as i64 + let rewarded_slots = current_slot - self.overall_empty_slots(current_slot); + let rewards = rewarded_slots * self.reward(); + let total_stake = rewards + self.initial_distribution; + if total_stake == 0 { + return constants::GENESIS_TOTAL_STAKE + } + total_stake } /// Calculate how many leaders existed in previous slot and appends diff --git a/src/consensus/validator.rs b/src/consensus/validator.rs index 26d9fe5ba..8f25c1f9f 100644 --- a/src/consensus/validator.rs +++ b/src/consensus/validator.rs @@ -93,6 +93,7 @@ impl ValidatorState { bootstrap_ts: Timestamp, genesis_ts: Timestamp, genesis_data: blake3::Hash, + initial_distribution: u64, wallet: WalletPtr, faucet_pubkeys: Vec, enable_participation: bool, @@ -122,8 +123,13 @@ impl ValidatorState { }; let blockchain = Blockchain::new(db, genesis_ts, genesis_data)?; - let consensus = - ConsensusState::new(blockchain.clone(), bootstrap_ts, genesis_ts, genesis_data)?; + let consensus = ConsensusState::new( + blockchain.clone(), + bootstrap_ts, + genesis_ts, + genesis_data, + initial_distribution, + )?; let unconfirmed_txs = vec![]; diff --git a/src/contract/dao/tests/harness.rs b/src/contract/dao/tests/harness.rs index 847161420..d15fac031 100644 --- a/src/contract/dao/tests/harness.rs +++ b/src/contract/dao/tests/harness.rs @@ -21,6 +21,7 @@ use darkfi::{ consensus::{ constants::{ TESTNET_BOOTSTRAP_TIMESTAMP, TESTNET_GENESIS_HASH_BYTES, TESTNET_GENESIS_TIMESTAMP, + TESTNET_INITIAL_DISTRIBUTION, }, ValidatorState, ValidatorStatePtr, }, @@ -86,6 +87,7 @@ impl DaoTestHarness { *TESTNET_BOOTSTRAP_TIMESTAMP, *TESTNET_GENESIS_TIMESTAMP, *TESTNET_GENESIS_HASH_BYTES, + *TESTNET_INITIAL_DISTRIBUTION, alice_wallet, vec![], false, diff --git a/src/contract/money/tests/harness.rs b/src/contract/money/tests/harness.rs index b89c67712..ec32eb3e0 100644 --- a/src/contract/money/tests/harness.rs +++ b/src/contract/money/tests/harness.rs @@ -21,6 +21,7 @@ use darkfi::{ consensus::{ constants::{ TESTNET_BOOTSTRAP_TIMESTAMP, TESTNET_GENESIS_HASH_BYTES, TESTNET_GENESIS_TIMESTAMP, + TESTNET_INITIAL_DISTRIBUTION, }, ValidatorState, ValidatorStatePtr, }, @@ -105,6 +106,7 @@ impl MoneyTestHarness { *TESTNET_BOOTSTRAP_TIMESTAMP, *TESTNET_GENESIS_TIMESTAMP, *TESTNET_GENESIS_HASH_BYTES, + *TESTNET_INITIAL_DISTRIBUTION, faucet_wallet, faucet_pubkeys.clone(), false, @@ -116,6 +118,7 @@ impl MoneyTestHarness { *TESTNET_BOOTSTRAP_TIMESTAMP, *TESTNET_GENESIS_TIMESTAMP, *TESTNET_GENESIS_HASH_BYTES, + *TESTNET_INITIAL_DISTRIBUTION, alice_wallet, faucet_pubkeys.clone(), false, @@ -127,6 +130,7 @@ impl MoneyTestHarness { *TESTNET_BOOTSTRAP_TIMESTAMP, *TESTNET_GENESIS_TIMESTAMP, *TESTNET_GENESIS_HASH_BYTES, + *TESTNET_INITIAL_DISTRIBUTION, bob_wallet, faucet_pubkeys.clone(), false,