validator/consensus: use blocks previous previous VRF for ranking

This commit is contained in:
aggstam
2023-10-06 18:15:17 +03:00
parent c847febc51
commit 0331a02f53
3 changed files with 80 additions and 51 deletions

View File

@@ -16,19 +16,15 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
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<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

View File

@@ -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

View File

@@ -16,12 +16,23 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
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<u64> {
// 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)
}