Kaynağa Gözat

consensus: Use BigUint for block ranking to obtain higher resolution

parazyd 2 yıl önce
ebeveyn
işleme
68c9bc8418

+ 2 - 3
doc/src/arch/consensus.md

@@ -72,9 +72,8 @@ First 2 blocks rank is equal to their nonce, since their previous previous block
 producer doesn't exist, or have a `VRF` attached to their reward transaction.
 producer doesn't exist, or have a `VRF` attached to their reward transaction.
 For rest blocks, the rank computes as following:
 For rest blocks, the rank computes as following:
 1. Grab the `VRF` proof from the reward transaction of the previous previous proposal
 1. Grab the `VRF` proof from the reward transaction of the previous previous proposal
-2. Generate a `pallas::Base` from the `blake3::Hash` bytes of the proof
-3. Generate a `u64` using the first 8 bytes from the `pallas::Base` of the proofs hash
-4. Compute the rank: `vrf_u64` % `nonce` (If `nonce` is 0, rank is equal to `vrf_u64`)
+2. Obtain a big-integer from the big endian output of the `VRF`
+3. Compute the rank: `vrf.output` % `nonce` (If `nonce` is 0, rank is equal to `vrf.output`)
 
 
 To calculate each fork rank, we simply sum all its block proposals ranks and multiply
 To calculate each fork rank, we simply sum all its block proposals ranks and multiply
 that with the forks length. We use the length multiplier to give a chance of higher
 that with the forks length. We use the length multiplier to give a chance of higher

+ 6 - 6
src/validator/consensus.rs

@@ -314,7 +314,7 @@ pub struct Fork {
     /// Valid pending transaction hashes
     /// Valid pending transaction hashes
     pub mempool: Vec<blake3::Hash>,
     pub mempool: Vec<blake3::Hash>,
     /// Current fork rank, cached for better performance
     /// Current fork rank, cached for better performance
-    pub rank: u64,
+    pub rank: BigUint,
 }
 }
 
 
 impl Fork {
 impl Fork {
@@ -322,7 +322,7 @@ impl Fork {
         let mempool =
         let mempool =
             blockchain.get_pending_txs()?.iter().map(|tx| blake3::hash(&serialize(tx))).collect();
             blockchain.get_pending_txs()?.iter().map(|tx| blake3::hash(&serialize(tx))).collect();
         let overlay = BlockchainOverlay::new(blockchain)?;
         let overlay = BlockchainOverlay::new(blockchain)?;
-        Ok(Self { overlay, module, proposals: vec![], mempool, rank: 0 })
+        Ok(Self { overlay, module, proposals: vec![], mempool, rank: BigUint::from(0u64) })
     }
     }
 
 
     /// Auxiliary function to append a proposal and recalculate current fork rank
     /// Auxiliary function to append a proposal and recalculate current fork rank
@@ -420,14 +420,14 @@ impl Fork {
     }
     }
 
 
     /// Auxiliarry function to compute fork's rank, assuming all proposals are valid.
     /// Auxiliarry function to compute fork's rank, assuming all proposals are valid.
-    pub async fn rank(&self) -> Result<u64> {
+    pub async fn rank(&self) -> Result<BigUint> {
         // If the fork is empty its rank is 0
         // If the fork is empty its rank is 0
         if self.proposals.is_empty() {
         if self.proposals.is_empty() {
-            return Ok(0)
+            return Ok(0u64.into())
         }
         }
 
 
         // Retrieve the sum of all fork proposals ranks
         // Retrieve the sum of all fork proposals ranks
-        let mut sum = 0;
+        let mut sum = BigUint::from(0_u64);
         let proposals = self.overlay.lock().unwrap().get_blocks_by_hash(&self.proposals)?;
         let proposals = self.overlay.lock().unwrap().get_blocks_by_hash(&self.proposals)?;
         for proposal in &proposals {
         for proposal in &proposals {
             // For block height < 3 we use the same proposal reference, since
             // For block height < 3 we use the same proposal reference, since
@@ -459,7 +459,7 @@ impl Fork {
         let module = self.module.clone();
         let module = self.module.clone();
         let proposals = self.proposals.clone();
         let proposals = self.proposals.clone();
         let mempool = self.mempool.clone();
         let mempool = self.mempool.clone();
-        let rank = self.rank;
+        let rank = self.rank.clone();
 
 
         Ok(Self { overlay, module, proposals, mempool, rank })
         Ok(Self { overlay, module, proposals, mempool, rank })
     }
     }

+ 14 - 22
src/validator/utils.rs

@@ -16,15 +16,12 @@
  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
  */
 
 
-use darkfi_sdk::{
-    crypto::{
-        ecvrf::VrfProof, pasta_prelude::PrimeField, DAO_CONTRACT_ID, DEPLOYOOOR_CONTRACT_ID,
-        MONEY_CONTRACT_ID,
-    },
-    pasta::{group::ff::FromUniformBytes, pallas},
+use darkfi_sdk::crypto::{
+    ecvrf::VrfProof, DAO_CONTRACT_ID, DEPLOYOOOR_CONTRACT_ID, MONEY_CONTRACT_ID,
 };
 };
 use darkfi_serial::AsyncDecodable;
 use darkfi_serial::AsyncDecodable;
 use log::info;
 use log::info;
+use num_bigint::BigUint;
 use smol::io::Cursor;
 use smol::io::Cursor;
 
 
 use crate::{
 use crate::{
@@ -103,10 +100,10 @@ pub async fn deploy_native_contracts(overlay: &BlockchainOverlayPtr) -> Result<(
 /// Genesis block has rank 0.
 /// Genesis block has rank 0.
 /// First 2 blocks rank is equal to their nonce, since their previous
 /// First 2 blocks rank is equal to their nonce, since their previous
 /// previous block producer doesn't exist or have a VRF.
 /// previous block producer doesn't exist or have a VRF.
-pub async fn block_rank(block: &BlockInfo, previous_previous: &BlockInfo) -> Result<u64> {
+pub async fn block_rank(block: &BlockInfo, previous_previous: &BlockInfo) -> Result<BigUint> {
     // Genesis block has rank 0
     // Genesis block has rank 0
     if block.header.height == 0 {
     if block.header.height == 0 {
-        return Ok(0)
+        return Ok(0u64.into())
     }
     }
 
 
     // Grab block nonce
     // Grab block nonce
@@ -114,7 +111,7 @@ pub async fn block_rank(block: &BlockInfo, previous_previous: &BlockInfo) -> Res
 
 
     // First 2 blocks have rank equal to their nonce
     // First 2 blocks have rank equal to their nonce
     if block.header.height < 3 {
     if block.header.height < 3 {
-        return Ok(nonce)
+        return Ok(nonce.into())
     }
     }
 
 
     // Extract VRF proof from the previous previous producer transaction
     // Extract VRF proof from the previous previous producer transaction
@@ -125,16 +122,11 @@ pub async fn block_rank(block: &BlockInfo, previous_previous: &BlockInfo) -> Res
     decoder.set_position(499);
     decoder.set_position(499);
     let vrf_proof: VrfProof = AsyncDecodable::decode_async(&mut decoder).await?;
     let vrf_proof: VrfProof = AsyncDecodable::decode_async(&mut decoder).await?;
 
 
-    // Compute VRF u64
-    let mut vrf = [0u8; 64];
-    vrf[..blake3::OUT_LEN].copy_from_slice(vrf_proof.hash_output().as_bytes());
-    let vrf_pallas = pallas::Base::from_uniform_bytes(&vrf);
-    let mut vrf = [0u8; 8];
-    vrf.copy_from_slice(&vrf_pallas.to_repr()[..8]);
-    let vrf = u64::from_be_bytes(vrf);
+    // Get the VRF output as big-endian
+    let vrf_output = BigUint::from_bytes_be(vrf_proof.hash_output().as_bytes());
 
 
     // Finally, compute the rank
     // Finally, compute the rank
-    let rank = if nonce != 0 { vrf % nonce } else { vrf };
+    let rank = if nonce != 0 { vrf_output % nonce } else { vrf_output };
 
 
     Ok(rank)
     Ok(rank)
 }
 }
@@ -206,24 +198,24 @@ pub fn best_forks_indexes(forks: &[Fork]) -> Result<Vec<usize>> {
     }
     }
 
 
     // Find the best ranked forks
     // Find the best ranked forks
-    let mut best = 0;
+    let mut best = BigUint::from(0u64);
     let mut indexes = vec![];
     let mut indexes = vec![];
     for (f_index, fork) in forks.iter().enumerate() {
     for (f_index, fork) in forks.iter().enumerate() {
-        let rank = fork.rank;
+        let rank = &fork.rank;
 
 
         // Fork ranks lower that current best
         // Fork ranks lower that current best
-        if rank < best {
+        if rank < &best {
             continue
             continue
         }
         }
 
 
         // Fork has same rank as current best
         // Fork has same rank as current best
-        if rank == best {
+        if rank == &best {
             indexes.push(f_index);
             indexes.push(f_index);
             continue
             continue
         }
         }
 
 
         // Fork ranks higher that current best
         // Fork ranks higher that current best
-        best = rank;
+        best = rank.clone();
         indexes = vec![f_index];
         indexes = vec![f_index];
     }
     }