mirror of
https://github.com/darkrenaissance/darkfi.git
synced 2026-04-28 03:00:18 -04:00
validator/consensus: fork/block ranking implemented
This commit is contained in:
@@ -16,15 +16,19 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
use std::io::Cursor;
|
||||
|
||||
use darkfi_sdk::{
|
||||
blockchain::Slot,
|
||||
crypto::schnorr::Signature,
|
||||
crypto::{ecvrf::VrfProof, pasta_prelude::PrimeField, schnorr::Signature},
|
||||
pasta::{group::ff::FromUniformBytes, pallas},
|
||||
};
|
||||
#[cfg(feature = "async-serial")]
|
||||
use darkfi_serial::async_trait;
|
||||
|
||||
use darkfi_serial::{deserialize, serialize, Encodable, SerialDecodable, SerialEncodable};
|
||||
use darkfi_serial::{
|
||||
deserialize, serialize, Decodable, Encodable, SerialDecodable, SerialEncodable,
|
||||
};
|
||||
|
||||
use crate::{tx::Transaction, Error, Result};
|
||||
|
||||
@@ -143,6 +147,46 @@ impl BlockInfo {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Compute block's rank, assuming the block is valid.
|
||||
pub fn rank(&self) -> Result<u64> {
|
||||
// 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
|
||||
|
||||
@@ -279,6 +279,9 @@ pub enum Error {
|
||||
#[error("State transition failed")]
|
||||
StateTransitionError,
|
||||
|
||||
#[error("No forks exist")]
|
||||
ForksNotFound,
|
||||
|
||||
#[error("Check if proposal extends any existing fork chains failed")]
|
||||
ExtendedChainIndexNotFound,
|
||||
|
||||
|
||||
@@ -286,6 +286,29 @@ impl Consensus {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Auxiliary function to find current best ranked fork.
|
||||
pub fn best_fork_index(&self) -> Result<usize> {
|
||||
// Check if node has any forks
|
||||
if self.forks.is_empty() {
|
||||
return Err(Error::ForksNotFound)
|
||||
}
|
||||
|
||||
// Find the best ranked fork
|
||||
let mut best = 0;
|
||||
let mut index = 0;
|
||||
for (f_index, fork) in self.forks.iter().enumerate() {
|
||||
let rank = fork.rank()?;
|
||||
if rank <= best {
|
||||
continue
|
||||
}
|
||||
|
||||
best = rank;
|
||||
index = f_index;
|
||||
}
|
||||
|
||||
Ok(index)
|
||||
}
|
||||
|
||||
/// Given a proposal, find the index of the fork chain it extends, along with the specific
|
||||
/// extended proposal index.
|
||||
fn find_extended_fork_index(&self, proposal: &Proposal) -> Result<(usize, usize)> {
|
||||
@@ -598,6 +621,26 @@ impl Fork {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Auxiliarry function to compute fork's rank, assuming all proposals are valid.
|
||||
pub fn rank(&self) -> Result<u64> {
|
||||
// If the fork is empty its rank is 0
|
||||
if self.proposals.is_empty() {
|
||||
return Ok(0)
|
||||
}
|
||||
|
||||
// Retrieve the sum of all fork proposals ranks
|
||||
let mut sum = 0;
|
||||
let proposals = self.overlay.lock().unwrap().get_blocks_by_hash(&self.proposals)?;
|
||||
for proposal in &proposals {
|
||||
sum += proposal.rank()?;
|
||||
}
|
||||
|
||||
// Use fork(proposals) length as a multiplier to compute the actual fork rank
|
||||
let rank = proposals.len() as u64 * sum;
|
||||
|
||||
Ok(rank)
|
||||
}
|
||||
|
||||
/// Auxiliary function to create a full clone using BlockchainOverlay::full_clone.
|
||||
/// Changes to this copy don't affect original fork overlay records, since underlying
|
||||
/// overlay pointer have been updated to the cloned one.
|
||||
|
||||
Reference in New Issue
Block a user