فهرست منبع

consensus: introduce staking coins initial distribution logic

aggstam 3 سال پیش
والد
کامیت
267fb82e56

+ 16 - 8
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<smol::Executor<'_>>) -> 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<smol::Executor<'_>>) -> Result<()> {
         bootstrap_ts,
         genesis_ts,
         genesis_data,
+        initial_distribution,
         wallet.clone(),
         faucet_pubkeys,
         args.consensus,

+ 16 - 8
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<smol::Executor<'_>>) -> 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<smol::Executor<'_>>) -> Result<()> {
         bootstrap_ts,
         genesis_ts,
         genesis_data,
+        initial_distribution,
         wallet.clone(),
         faucet_pubkeys,
         false,

+ 20 - 14
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;

+ 25 - 18
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<Self> {
         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

+ 8 - 2
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<PublicKey>,
         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![];
 

+ 2 - 0
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,

+ 4 - 0
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,