Forráskód Böngészése

[consensus] reorg is_lead, and sigmas

mohab metwally 3 éve
szülő
commit
4bdae4989f
3 módosított fájl, 84 hozzáadás és 56 törlés
  1. 28 15
      src/consensus/leadcoin.rs
  2. 3 1
      src/consensus/metadata.rs
  3. 53 40
      src/consensus/state.rs

+ 28 - 15
src/consensus/leadcoin.rs

@@ -39,6 +39,7 @@ use crate::{
     Error, Result,
     Error, Result,
 };
 };
 use darkfi_serial::{Decodable, Encodable, SerialDecodable, SerialEncodable};
 use darkfi_serial::{Decodable, Encodable, SerialDecodable, SerialEncodable};
+use log::info;
 
 
 pub const MERKLE_DEPTH_LEADCOIN: usize = 32;
 pub const MERKLE_DEPTH_LEADCOIN: usize = 32;
 pub const MERKLE_DEPTH: u8 = 32;
 pub const MERKLE_DEPTH: u8 = 32;
@@ -92,12 +93,6 @@ pub struct LeadCoin {
     pub y_mu: pallas::Base,
     pub y_mu: pallas::Base,
     /// Leader election nonce derived from eta at onset of epoch
     /// Leader election nonce derived from eta at onset of epoch
     pub rho_mu: pallas::Base,
     pub rho_mu: pallas::Base,
-    /// First coefficient in 1-term T (target function) approximation.
-    /// NOTE: sigma1 and sigma2 are not the capital sigma from the paper, but
-    /// the whole coefficient multiplied with absolute stake.
-    pub sigma1: pallas::Base,
-    /// Second coefficient in 2-term T (target function) approximation.
-    pub sigma2: pallas::Base,
     /// Coin's secret key
     /// Coin's secret key
     pub secret_key: SecretKey,
     pub secret_key: SecretKey,
 }
 }
@@ -107,10 +102,6 @@ impl LeadCoin {
     pub fn new(
     pub fn new(
         // emulation of global random oracle output from previous epoch randomness.
         // emulation of global random oracle output from previous epoch randomness.
         eta: pallas::Base,
         eta: pallas::Base,
-        // First coefficient in 1-term T (target function) approximation.
-        sigma1: pallas::Base,
-        // Second coefficient in 2-term T (target function) approximation.
-        sigma2: pallas::Base,
         // Stake value
         // Stake value
         value: u64,
         value: u64,
         // Slot index in the epoch
         // Slot index in the epoch
@@ -211,8 +202,6 @@ impl LeadCoin {
             coin2_blind,
             coin2_blind,
             y_mu,
             y_mu,
             rho_mu,
             rho_mu,
-            sigma1,
-            sigma2,
             secret_key,
             secret_key,
         }
         }
     }
     }
@@ -302,6 +291,27 @@ impl LeadCoin {
         rho
         rho
     }
     }
 
 
+    pub fn is_leader(&self, sigma1: pallas::Base, sigma2: pallas::Base) -> bool {
+        let y_exp = [self.coin1_sk_root.inner(), self.nonce];
+        let y_exp_hash = poseidon_hash(y_exp);
+        let y_coords = pedersen_commitment_base(y_exp_hash, mod_r_p(self.y_mu))
+            .to_affine()
+            .coordinates()
+            .unwrap();
+
+        let y_coords = [*y_coords.x(), *y_coords.y()];
+        let y = poseidon_hash(y_coords);
+
+        let value = pallas::Base::from(self.value);
+        let target = sigma1 * value + sigma2 * value * value;
+
+        info!("Consensus::is_leader(): y = {:?}", y);
+        info!("Consensus::is_leader(): T = {:?}", target);
+
+        let first_winning = y < target;
+        first_winning
+    }
+
     /// calculated derived coin commitment
     /// calculated derived coin commitment
     pub fn derived_commitment(&self, blind: pallas::Scalar) -> pallas::Point {
     pub fn derived_commitment(&self, blind: pallas::Scalar) -> pallas::Point {
         let pk = self.pk();
         let pk = self.pk();
@@ -334,7 +344,10 @@ impl LeadCoin {
     }
     }
 
 
     /// Try to create a ZK proof of consensus leadership
     /// Try to create a ZK proof of consensus leadership
-    pub fn create_lead_proof(&self, pk: &ProvingKey) -> Result<Proof> {
+    pub fn create_lead_proof(&self,
+                             sigma1: pallas::Base,
+                             sigma2: pallas::Base,
+                             pk: &ProvingKey) -> Result<Proof> {
         let bincode = include_bytes!("../../proof/lead.zk.bin");
         let bincode = include_bytes!("../../proof/lead.zk.bin");
         let zkbin = ZkBinary::decode(bincode)?;
         let zkbin = ZkBinary::decode(bincode)?;
         let witnesses = vec![
         let witnesses = vec![
@@ -351,8 +364,8 @@ impl LeadCoin {
             Witness::Scalar(Value::known(self.coin2_blind)),
             Witness::Scalar(Value::known(self.coin2_blind)),
             Witness::Scalar(Value::known(mod_r_p(self.rho_mu))),
             Witness::Scalar(Value::known(mod_r_p(self.rho_mu))),
             Witness::Scalar(Value::known(mod_r_p(self.y_mu))),
             Witness::Scalar(Value::known(mod_r_p(self.y_mu))),
-            Witness::Base(Value::known(self.sigma1)),
-            Witness::Base(Value::known(self.sigma2)),
+            Witness::Base(Value::known(sigma1)),
+            Witness::Base(Value::known(sigma2)),
         ];
         ];
         let circuit = ZkCircuit::new(witnesses, zkbin.clone());
         let circuit = ZkCircuit::new(witnesses, zkbin.clone());
         Ok(Proof::create(pk, &[circuit], &self.public_inputs(), &mut OsRng)?)
         Ok(Proof::create(pk, &[circuit], &self.public_inputs(), &mut OsRng)?)

+ 3 - 1
src/consensus/metadata.rs

@@ -76,10 +76,12 @@ pub struct LeadProof {
 }
 }
 
 
 impl LeadProof {
 impl LeadProof {
+    /*
     pub fn new(pk: &ProvingKey, coin: LeadCoin) -> Self {
     pub fn new(pk: &ProvingKey, coin: LeadCoin) -> Self {
         let proof = coin.create_lead_proof(pk).unwrap();
         let proof = coin.create_lead_proof(pk).unwrap();
         Self { proof }
         Self { proof }
-    }
+}
+    */
 
 
     pub fn verify(&self, vk: &VerifyingKey, public_inputs: &[pallas::Base]) -> Result<()> {
     pub fn verify(&self, vk: &VerifyingKey, public_inputs: &[pallas::Base]) -> Result<()> {
         if let Err(e) = self.proof.verify(vk, public_inputs) {
         if let Err(e) = self.proof.verify(vk, public_inputs) {

+ 53 - 40
src/consensus/state.rs

@@ -134,6 +134,12 @@ pub struct ValidatorState {
     pub participating: Option<u64>,
     pub participating: Option<u64>,
     /// Wallet interface
     /// Wallet interface
     pub wallet: WalletPtr,
     pub wallet: WalletPtr,
+    /// nullifiers
+    pub nullifiers: Vec<pallas::Base>,
+    /// spent coins
+    pub spent: Vec<pallas::Base>,
+    /// lead coins
+    pub lead: Vec<pallas::Base>,
 }
 }
 
 
 impl ValidatorState {
 impl ValidatorState {
@@ -204,6 +210,9 @@ impl ValidatorState {
             unconfirmed_txs,
             unconfirmed_txs,
             participating,
             participating,
             wallet,
             wallet,
+            nullifiers: vec![],
+            spent: vec![],
+            lead: vec![],
         }));
         }));
 
 
         Ok(state)
         Ok(state)
@@ -330,21 +339,15 @@ impl ValidatorState {
         Ok(true)
         Ok(true)
     }
     }
 
 
-    /// Generate epoch-competing coins
-    async fn create_epoch_coins(
-        &self,
-        eta: pallas::Base,
-        epoch: u64,
-        slot: u64,
-    ) -> Result<Vec<Vec<LeadCoin>>> {
-        info!("Consensus: Creating coins for epoch: {}", epoch);
-
-        // Retrieve previous epoch-competing coins' frequency
-        let frequency = Self::get_frequency().with_precision(RADIX_BITS).value();
-        info!("Consensus: Previous epoch frequency: {}", frequency);
+    /// return 2-term target approximation sigma coefficients.
+    /// `epoch: absolute epoch index
+    /// `slot: relative slot index
+    fn sigmas(&self, epoch: u64, slot: u64) -> (pallas::Base, pallas::Base) {
+        let f = Self::leadership_probability_with_all_stake().with_precision(RADIX_BITS).value();
+        info!("Consensus: f: {}", f);
 
 
         // Generate sigmas
         // Generate sigmas
-        let total_stake = Self::total_stake(epoch, slot); // Only used for fine-tuning
+        let total_stake = Self::total_stake_plus(epoch, slot); // Only used for fine-tuning
 
 
         let one = Float10::from_str_native("1").unwrap().with_precision(RADIX_BITS).value();
         let one = Float10::from_str_native("1").unwrap().with_precision(RADIX_BITS).value();
         let two = Float10::from_str_native("2").unwrap().with_precision(RADIX_BITS).value();
         let two = Float10::from_str_native("2").unwrap().with_precision(RADIX_BITS).value();
@@ -352,7 +355,7 @@ impl ValidatorState {
         let total_sigma =
         let total_sigma =
             Float10::try_from(total_stake).unwrap().with_precision(RADIX_BITS).value();
             Float10::try_from(total_stake).unwrap().with_precision(RADIX_BITS).value();
 
 
-        let x = one - frequency;
+        let x = one - f;
         let c = x.ln();
         let c = x.ln();
 
 
         let sigma1_fbig = c.clone() / total_sigma.clone() * field_p.clone();
         let sigma1_fbig = c.clone() / total_sigma.clone() * field_p.clone();
@@ -360,7 +363,19 @@ impl ValidatorState {
 
 
         let sigma2_fbig = (c / total_sigma).powf(two.clone()) * (field_p / two);
         let sigma2_fbig = (c / total_sigma).powf(two.clone()) * (field_p / two);
         let sigma2 = fbig2base(sigma2_fbig);
         let sigma2 = fbig2base(sigma2_fbig);
+        (sigma1, sigma2)
+
+    }
 
 
+    /// Generate epoch-competing coins
+    async fn create_epoch_coins(
+        &self,
+        eta: pallas::Base,
+        epoch: u64,
+        slot: u64,
+    ) -> Result<Vec<Vec<LeadCoin>>> {
+        info!("Consensus: Creating coins for epoch: {}", epoch);
+        let (sigma1, sigma2) = self.sigmas(epoch, slot);
         self.create_coins(eta, sigma1, sigma2).await
         self.create_coins(eta, sigma1, sigma2).await
     }
     }
 
 
@@ -393,8 +408,6 @@ impl ValidatorState {
         for i in 0..EPOCH_LENGTH {
         for i in 0..EPOCH_LENGTH {
             let coin = LeadCoin::new(
             let coin = LeadCoin::new(
                 eta,
                 eta,
-                sigma1,
-                sigma2,
                 LOTTERY_HEAD_START, // TODO: TESTNET: Why is this constant being used?
                 LOTTERY_HEAD_START, // TODO: TESTNET: Why is this constant being used?
                 i as u64,
                 i as u64,
                 epoch_secrets.secret_keys[i].inner(),
                 epoch_secrets.secret_keys[i].inner(),
@@ -412,14 +425,26 @@ impl ValidatorState {
         Ok(coins)
         Ok(coins)
     }
     }
 
 
-    fn total_stake(epoch: u64, slot: u64) -> u64 {
-        // TODO: Fix this
-        // (epoch * EPOCH_LENGTH + slot + 1) * REWARD
-        REWARD
+    /// leadership reward, assuming constant reward
+    /// TODO (res) implement reward mechanism with accord to DRK,DARK token-economics
+    fn reward() -> u64 {
+       REWARD
+    }
+
+    ///TODO: impl total empty slots count.
+    fn empty_slots_count() -> u64 {
+        0
+    }
+
+    /// total stake plus one.
+    /// assuming constant Reward.
+    fn total_stake_plus(epoch: u64, slot: u64) -> u64 {
+        (epoch * EPOCH_LENGTH as u64 + slot + 1 - Self::empty_slots_count()) * Self::reward()
     }
     }
 
 
-    fn get_frequency() -> Float10 {
-        // TODO: Actually retrieve frequency of coins from the previous epoch.
+    /// leadership probability having all the stake.
+    /// dynamically auto-tune f
+    fn leadership_probability_with_all_stake() -> Float10 {
         let one = Float10::from_str_native("1").unwrap().with_precision(RADIX_BITS).value();
         let one = Float10::from_str_native("1").unwrap().with_precision(RADIX_BITS).value();
         let two = Float10::from_str_native("2").unwrap().with_precision(RADIX_BITS).value();
         let two = Float10::from_str_native("2").unwrap().with_precision(RADIX_BITS).value();
         one / two
         one / two
@@ -434,6 +459,8 @@ impl ValidatorState {
     pub fn is_slot_leader(&self) -> (bool, usize) {
     pub fn is_slot_leader(&self) -> (bool, usize) {
         // Slot relative index
         // Slot relative index
         let slot = self.relative_slot(self.current_slot());
         let slot = self.relative_slot(self.current_slot());
+        let epoch = self.current_epoch();
+        let (sigma1, sigma2) = self.sigmas(slot, epoch);
         // Stakeholder's epoch coins
         // Stakeholder's epoch coins
         let coins = &self.consensus.coins;
         let coins = &self.consensus.coins;
 
 
@@ -447,23 +474,7 @@ impl ValidatorState {
         let mut highest_stake_idx = 0;
         let mut highest_stake_idx = 0;
 
 
         for (winning_idx, coin) in competing_coins.iter().enumerate() {
         for (winning_idx, coin) in competing_coins.iter().enumerate() {
-            let y_exp = [coin.coin1_sk_root.inner(), coin.nonce];
-            let y_exp_hash = poseidon_hash(y_exp);
-            let y_coords = pedersen_commitment_base(y_exp_hash, mod_r_p(coin.y_mu))
-                .to_affine()
-                .coordinates()
-                .unwrap();
-
-            let y_coords = [*y_coords.x(), *y_coords.y()];
-            let y = poseidon_hash(y_coords);
-
-            let value = pallas::Base::from(coin.value);
-            let target = coin.sigma1 * value + coin.sigma2 * value * value;
-
-            info!("Consensus::is_leader(): y = {:?}", y);
-            info!("Consensus::is_leader(): T = {:?}", target);
-
-            let first_winning = y < target;
+            let first_winning = coin.is_leader(sigma1, sigma2);
             if first_winning && !won {
             if first_winning && !won {
                 highest_stake_idx = winning_idx;
                 highest_stake_idx = winning_idx;
             }
             }
@@ -483,6 +494,8 @@ impl ValidatorState {
     /// chain the node is holding.
     /// chain the node is holding.
     pub fn propose(&mut self, idx: usize) -> Result<Option<BlockProposal>> {
     pub fn propose(&mut self, idx: usize) -> Result<Option<BlockProposal>> {
         let slot = self.current_slot();
         let slot = self.current_slot();
+        let epoch = self.current_epoch();
+        let (sigma1, sigma2) = self.sigmas(slot, epoch);
         let (prev_hash, index) = self.longest_chain_last_hash().unwrap();
         let (prev_hash, index) = self.longest_chain_last_hash().unwrap();
         let unproposed_txs = self.unproposed_txs(index);
         let unproposed_txs = self.unproposed_txs(index);
 
 
@@ -503,7 +516,7 @@ impl ValidatorState {
         // Generating leader proof
         // Generating leader proof
         let relative_slot = self.relative_slot(slot) as usize;
         let relative_slot = self.relative_slot(slot) as usize;
         let coin = self.consensus.coins[relative_slot][idx];
         let coin = self.consensus.coins[relative_slot][idx];
-        let proof = coin.create_lead_proof(&self.lead_proving_key)?;
+        let proof = coin.create_lead_proof(sigma1, sigma2, &self.lead_proving_key)?;
 
 
         // Signing using coin
         // Signing using coin
         let secret_key = coin.secret_key;
         let secret_key = coin.secret_key;