Просмотр исходного кода

consensus: Use BigUint for block ranking to obtain higher resolution

parazyd 2 лет назад
Родитель
Сommit
68c9bc8418
3 измененных файлов с 22 добавлено и 31 удалено
  1. 2 3
      doc/src/arch/consensus.md
  2. 6 6
      src/validator/consensus.rs
  3. 14 22
      src/validator/utils.rs

+ 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.
 For rest blocks, the rank computes as following:
 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
 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
     pub mempool: Vec<blake3::Hash>,
     /// Current fork rank, cached for better performance
-    pub rank: u64,
+    pub rank: BigUint,
 }
 
 impl Fork {
@@ -322,7 +322,7 @@ impl Fork {
         let mempool =
             blockchain.get_pending_txs()?.iter().map(|tx| blake3::hash(&serialize(tx))).collect();
         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
@@ -420,14 +420,14 @@ impl Fork {
     }
 
     /// 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 self.proposals.is_empty() {
-            return Ok(0)
+            return Ok(0u64.into())
         }
 
         // 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)?;
         for proposal in &proposals {
             // For block height < 3 we use the same proposal reference, since
@@ -459,7 +459,7 @@ impl Fork {
         let module = self.module.clone();
         let proposals = self.proposals.clone();
         let mempool = self.mempool.clone();
-        let rank = self.rank;
+        let rank = self.rank.clone();
 
         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/>.
  */
 
-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 log::info;
+use num_bigint::BigUint;
 use smol::io::Cursor;
 
 use crate::{
@@ -103,10 +100,10 @@ pub async fn deploy_native_contracts(overlay: &BlockchainOverlayPtr) -> Result<(
 /// Genesis block has rank 0.
 /// First 2 blocks rank is equal to their nonce, since their previous
 /// 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
     if block.header.height == 0 {
-        return Ok(0)
+        return Ok(0u64.into())
     }
 
     // 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
     if block.header.height < 3 {
-        return Ok(nonce)
+        return Ok(nonce.into())
     }
 
     // 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);
     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
-    let rank = if nonce != 0 { vrf % nonce } else { vrf };
+    let rank = if nonce != 0 { vrf_output % nonce } else { vrf_output };
 
     Ok(rank)
 }
@@ -206,24 +198,24 @@ pub fn best_forks_indexes(forks: &[Fork]) -> Result<Vec<usize>> {
     }
 
     // Find the best ranked forks
-    let mut best = 0;
+    let mut best = BigUint::from(0u64);
     let mut indexes = vec![];
     for (f_index, fork) in forks.iter().enumerate() {
-        let rank = fork.rank;
+        let rank = &fork.rank;
 
         // Fork ranks lower that current best
-        if rank < best {
+        if rank < &best {
             continue
         }
 
         // Fork has same rank as current best
-        if rank == best {
+        if rank == &best {
             indexes.push(f_index);
             continue
         }
 
         // Fork ranks higher that current best
-        best = rank;
+        best = rank.clone();
         indexes = vec![f_index];
     }