diff --git a/src/blockchain/block_store.rs b/src/blockchain/block_store.rs index 2e0907f94..b21f4957a 100644 --- a/src/blockchain/block_store.rs +++ b/src/blockchain/block_store.rs @@ -16,19 +16,15 @@ * along with this program. If not, see . */ -use std::io::Cursor; - use darkfi_sdk::{ blockchain::Slot, - crypto::{ecvrf::VrfProof, pasta_prelude::PrimeField, schnorr::Signature}, + crypto::schnorr::Signature, pasta::{group::ff::FromUniformBytes, pallas}, }; #[cfg(feature = "async-serial")] use darkfi_serial::async_trait; -use darkfi_serial::{ - deserialize, serialize, Decodable, Encodable, SerialDecodable, SerialEncodable, -}; +use darkfi_serial::{deserialize, serialize, Encodable, SerialDecodable, SerialEncodable}; use crate::{tx::Transaction, Error, Result}; @@ -147,46 +143,6 @@ impl BlockInfo { Ok(()) } - - /// Compute block's rank, assuming the block is valid. - pub fn rank(&self) -> Result { - // Genesis block has rank 0 - if self.header.height == 0 { - return Ok(0) - } - - // Extract VRF proof from the producer transaction - let tx = self.txs.last().unwrap(); - let data = &tx.calls[0].data; - let position = match self.header.version { - // PoW uses MoneyPoWRewardParamsV1 - 1 => 563, - // PoS uses ConsensusProposalParamsV1 - 2 => 490, - _ => return Err(Error::BlockVersionIsInvalid(self.header.version)), - }; - let mut decoder = Cursor::new(&data); - decoder.set_position(position); - let vrf_proof: VrfProof = Decodable::decode(&mut decoder)?; - - // Compute nonce u64 - let mut nonce = [0u8; 8]; - nonce.copy_from_slice(&self.header.nonce.to_repr()[..8]); - let nonce = u64::from_be_bytes(nonce); - - // 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); - - // Finally, compute the rank - let rank = nonce % vrf; - - Ok(rank) - } } /// [`Block`] sled tree diff --git a/src/validator/consensus.rs b/src/validator/consensus.rs index cd4cbf9b2..21180b6fe 100644 --- a/src/validator/consensus.rs +++ b/src/validator/consensus.rs @@ -29,7 +29,9 @@ use crate::{ blockchain::{BlockInfo, Blockchain, BlockchainOverlay, BlockchainOverlayPtr, Header}, tx::Transaction, util::time::{TimeKeeper, Timestamp}, - validator::{pid::slot_pid_output, pow::PoWModule, verify_block, verify_transactions}, + validator::{ + pid::slot_pid_output, pow::PoWModule, utils::block_rank, verify_block, verify_transactions, + }, Error, Result, }; @@ -632,7 +634,19 @@ impl Fork { let mut sum = 0; let proposals = self.overlay.lock().unwrap().get_blocks_by_hash(&self.proposals)?; for proposal in &proposals { - sum += proposal.rank()?; + // For block height > 3, retrieve their previous previous block + let previous_previous = if proposal.header.height > 3 { + let previous = &self + .overlay + .lock() + .unwrap() + .get_blocks_by_hash(&[proposal.header.previous])?[0]; + self.overlay.lock().unwrap().get_blocks_by_hash(&[previous.header.previous])?[0] + .clone() + } else { + proposal.clone() + }; + sum += block_rank(proposal, &previous_previous)?; } // Use fork(proposals) length as a multiplier to compute the actual fork rank diff --git a/src/validator/utils.rs b/src/validator/utils.rs index a7360c0fb..6478c3226 100644 --- a/src/validator/utils.rs +++ b/src/validator/utils.rs @@ -16,12 +16,23 @@ * along with this program. If not, see . */ -use darkfi_sdk::crypto::{PublicKey, CONSENSUS_CONTRACT_ID, DAO_CONTRACT_ID, MONEY_CONTRACT_ID}; -use darkfi_serial::serialize; +use std::io::Cursor; + +use darkfi_sdk::{ + crypto::{ + ecvrf::VrfProof, pasta_prelude::PrimeField, PublicKey, CONSENSUS_CONTRACT_ID, + DAO_CONTRACT_ID, MONEY_CONTRACT_ID, + }, + pasta::{group::ff::FromUniformBytes, pallas}, +}; +use darkfi_serial::{serialize, Decodable}; use log::info; use crate::{ - blockchain::BlockchainOverlayPtr, runtime::vm_runtime::Runtime, util::time::TimeKeeper, Result, + blockchain::{BlockInfo, BlockchainOverlayPtr}, + runtime::vm_runtime::Runtime, + util::time::TimeKeeper, + Error, Result, }; /// Deploy DarkFi native wasm contracts to provided blockchain overlay. @@ -86,3 +97,51 @@ pub fn deploy_native_contracts( Ok(()) } + +/// Compute a block's rank, assuming the its valid. +/// 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 fn block_rank(block: &BlockInfo, previous_previous: &BlockInfo) -> Result { + // Genesis block has rank 0 + if block.header.height == 0 { + return Ok(0) + } + + // Compute nonce u64 + let mut nonce = [0u8; 8]; + nonce.copy_from_slice(&block.header.nonce.to_repr()[..8]); + let nonce = u64::from_be_bytes(nonce); + + // First 2 block have rank equal to their nonce + if block.header.height < 3 { + return Ok(nonce) + } + + // Extract VRF proof from the previous previous producer transaction + let tx = previous_previous.txs.last().unwrap(); + let data = &tx.calls[0].data; + let position = match previous_previous.header.version { + // PoW uses MoneyPoWRewardParamsV1 + 1 => 563, + // PoS uses ConsensusProposalParamsV1 + 2 => 490, + _ => return Err(Error::BlockVersionIsInvalid(previous_previous.header.version)), + }; + let mut decoder = Cursor::new(&data); + decoder.set_position(position); + let vrf_proof: VrfProof = Decodable::decode(&mut decoder)?; + + // 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); + + // Finally, compute the rank + let rank = nonce % vrf; + + Ok(rank) +}