blockchain/Block: refactored in preparation for mining integration

This commit is contained in:
aggstam
2023-09-19 00:11:20 +03:00
parent 7ee02b6f7d
commit e5081d55ce
13 changed files with 176 additions and 136 deletions

View File

@@ -165,7 +165,7 @@ impl Harness {
previous: &BlockInfo,
slots_count: usize,
) -> Result<BlockInfo> {
let previous_hash = previous.blockhash();
let previous_hash = previous.hash()?;
// Generate empty slots
let mut slots = Vec::with_capacity(slots_count);
@@ -200,17 +200,17 @@ impl Harness {
previous.header.epoch,
slots.last().unwrap().id,
timestamp,
previous.header.root,
previous.header.nonce,
);
// Generate block
let block = BlockInfo::new(
header,
vec![Transaction::default()],
previous.signature,
previous.eta,
slots,
);
// Generate the block
let mut block = BlockInfo::new_empty(header, slots);
// Add transactions to the block
block.append_txs(vec![Transaction::default()])?;
// Attach signature
block.signature = previous.signature;
Ok(block)
}

View File

@@ -19,12 +19,12 @@
use darkfi_sdk::{
blockchain::Slot,
crypto::schnorr::Signature,
pasta::{group::ff::Field, pallas},
pasta::{group::ff::FromUniformBytes, pallas},
};
#[cfg(feature = "async-serial")]
use darkfi_serial::async_trait;
use darkfi_serial::{deserialize, serialize, SerialDecodable, SerialEncodable};
use darkfi_serial::{deserialize, serialize, Encodable, SerialDecodable, SerialEncodable};
use crate::{tx::Transaction, Error, Result};
@@ -33,7 +33,7 @@ use super::{parse_record, parse_u64_key_record, Header, SledDbOverlayPtr};
/// Block version number
pub const BLOCK_VERSION: u8 = 1;
/// This struct represents a tuple of the form (`header`, `txs`, `signature`, `eta`).
/// This struct represents a tuple of the form (`header`, `txs`, `signature`).
/// The header and transactions are stored as hashes, serving as pointers to the actual data
/// in the sled database.
/// NOTE: This struct fields are considered final, as it represents a blockchain block.
@@ -45,23 +45,18 @@ pub struct Block {
pub txs: Vec<blake3::Hash>,
/// Block producer signature
pub signature: Signature,
/// Block producer ETA
pub eta: pallas::Base,
}
impl Block {
pub fn new(
header: blake3::Hash,
txs: Vec<blake3::Hash>,
signature: Signature,
eta: pallas::Base,
) -> Self {
Self { header, txs, signature, eta }
pub fn new(header: blake3::Hash, txs: Vec<blake3::Hash>, signature: Signature) -> Self {
Self { header, txs, signature }
}
/// Calculate the block hash
pub fn blockhash(&self) -> blake3::Hash {
blake3::hash(&serialize(self))
/// Compute the block's blockchain hash
pub fn hash(&self) -> Result<blake3::Hash> {
let mut hasher = blake3::Hasher::new();
self.encode(&mut hasher)?;
Ok(hasher.finalize())
}
}
@@ -77,8 +72,6 @@ pub struct BlockInfo {
pub txs: Vec<Transaction>,
/// Block producer signature
pub signature: Signature,
/// Block producer ETA
pub eta: pallas::Base,
/// Slots payload
pub slots: Vec<Slot>,
}
@@ -90,7 +83,6 @@ impl Default for BlockInfo {
header: Header::default(),
txs: vec![Transaction::default()],
signature: Signature::dummy(),
eta: pallas::Base::ZERO,
slots: vec![Slot::default()],
}
}
@@ -101,28 +93,66 @@ impl BlockInfo {
header: Header,
txs: Vec<Transaction>,
signature: Signature,
eta: pallas::Base,
slots: Vec<Slot>,
) -> Self {
Self { header, txs, signature, eta, slots }
Self { header, txs, signature, slots }
}
/// Calculate the block hash
pub fn blockhash(&self) -> blake3::Hash {
/// Generate an empty block for provided Header
/// and slots vector. Transactions and the producer
/// signature must be added after.
pub fn new_empty(header: Header, slots: Vec<Slot>) -> Self {
let txs = vec![];
let signature = Signature::dummy();
Self { header, txs, signature, slots }
}
/// Compute the block's blockchain hash
pub fn hash(&self) -> Result<blake3::Hash> {
let block: Block = self.clone().into();
block.blockhash()
block.hash()
}
/// Compute the block's hash used for mining
pub fn mining_hash(&self) -> Result<blake3::Hash> {
let mut hasher = blake3::Hasher::new();
let mut len: usize = 0;
len += self.header.encode(&mut hasher)?;
len += self.header.tree.root(0).unwrap().encode(&mut hasher)?;
len += self.txs.len().encode(&mut hasher)?;
len.encode(&mut hasher)?;
Ok(hasher.finalize())
}
/// Append a transaction to the block. Also adds it to the Merkle tree.
pub fn append_tx(&mut self, tx: Transaction) -> Result<()> {
let mut buf = [0u8; 64];
buf[..blake3::OUT_LEN].copy_from_slice(tx.hash()?.as_bytes());
let leaf = pallas::Base::from_uniform_bytes(&buf);
self.header.tree.append(leaf.into());
self.txs.push(tx);
Ok(())
}
/// Append a vector of transactions to the block. Also adds them to the
/// Merkle tree.
pub fn append_txs(&mut self, txs: Vec<Transaction>) -> Result<()> {
for tx in txs {
self.append_tx(tx)?;
}
Ok(())
}
}
impl From<BlockInfo> for Block {
fn from(block_info: BlockInfo) -> Self {
let txs = block_info.txs.iter().map(|x| blake3::hash(&serialize(x))).collect();
Self {
header: block_info.header.headerhash().unwrap(),
txs,
signature: block_info.signature,
eta: block_info.eta,
}
Self { header: block_info.header.hash().unwrap(), txs, signature: block_info.signature }
}
}

View File

@@ -16,7 +16,10 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
use darkfi_sdk::crypto::{MerkleNode, MerkleTree};
use darkfi_sdk::{
crypto::MerkleTree,
pasta::{group::ff::Field, pallas},
};
#[cfg(feature = "async-serial")]
use darkfi_serial::async_trait;
@@ -26,37 +29,42 @@ use crate::{util::time::Timestamp, Error, Result};
use super::{block_store::BLOCK_VERSION, parse_record, SledDbOverlayPtr};
/// This struct represents a tuple of the form (version, previous, epoch, slot, timestamp, merkle_root).
/// This struct represents a tuple of the form (version, previous, epoch, height, timestamp, nonce, merkle_root).
#[derive(Debug, Clone, PartialEq, Eq, SerialEncodable, SerialDecodable)]
pub struct Header {
/// Block version
pub version: u8,
/// Previous block hash
pub previous: blake3::Hash,
/// Epoch
/// Epoch number
pub epoch: u64,
/// Slot UID
pub slot: u64,
/// Block/Slot height
pub height: u64,
/// Block creation timestamp
pub timestamp: Timestamp,
/// Root of the transaction hashes merkle tree
pub root: MerkleNode,
/// The block's nonce.
/// In PoW, this value changes arbitrarily with mining.
/// In PoS, we can use this value as our block producer ETA.
pub nonce: pallas::Base,
/// Merkle tree of the transactions contained in this block
pub tree: MerkleTree,
}
impl Header {
pub fn new(
previous: blake3::Hash,
epoch: u64,
slot: u64,
height: u64,
timestamp: Timestamp,
root: MerkleNode,
nonce: pallas::Base,
) -> Self {
let version = BLOCK_VERSION;
Self { version, previous, epoch, slot, timestamp, root }
let tree = MerkleTree::new(1);
Self { version, previous, epoch, height, timestamp, nonce, tree }
}
/// Calculate the header hash
pub fn headerhash(&self) -> Result<blake3::Hash> {
/// Compute the header's hash
pub fn hash(&self) -> Result<blake3::Hash> {
let mut hasher = blake3::Hasher::new();
self.encode(&mut hasher)?;
Ok(hasher.finalize())
@@ -71,7 +79,7 @@ impl Default for Header {
0,
0,
Timestamp::current_time(),
MerkleTree::new(100).root(0).unwrap(),
pallas::Base::ZERO,
)
}
}

View File

@@ -134,7 +134,8 @@ impl Blockchain {
batches.push(bocks_batch);
// Store block order
let blocks_order_batch = self.order.insert_batch(&[block.header.slot], &block_hash_vec)?;
let blocks_order_batch =
self.order.insert_batch(&[block.header.height], &block_hash_vec)?;
trees.push(self.order.0.clone());
batches.push(blocks_order_batch);
@@ -160,7 +161,7 @@ impl Blockchain {
/// Check if the given [`BlockInfo`] is in the database and all trees.
pub fn has_block(&self, block: &BlockInfo) -> Result<bool> {
let blockhash = match self.order.get(&[block.header.slot], true) {
let blockhash = match self.order.get(&[block.header.height], true) {
Ok(v) => v[0].unwrap(),
Err(_) => return Ok(false),
};
@@ -191,7 +192,7 @@ impl Blockchain {
}
// Check provided info produces the same hash
Ok(blockhash == block.blockhash())
Ok(blockhash == block.hash()?)
}
/// Retrieve [`BlockInfo`]s by given hashes. Fails if any of them is not found.
@@ -218,13 +219,13 @@ impl Blockchain {
// Retrieve extra stuff based on block version
let mut block_slots = vec![];
if header.version > 0 {
let slots = self.blocks_slots.get(&[block.blockhash()], true)?;
let slots = self.blocks_slots.get(&[block.hash()?], true)?;
let slots = slots[0].clone().unwrap();
let slots = self.slots.get(&slots, true)?;
block_slots = slots.iter().map(|x| x.clone().unwrap()).collect();
}
let info = BlockInfo::new(header, txs, block.signature, block.eta, block_slots);
let info = BlockInfo::new(header, txs, block.signature, block_slots);
ret.push(info);
}
@@ -488,7 +489,7 @@ impl BlockchainOverlay {
let block_hash_vec = [block_hash];
// Store block order
self.order.insert(&[block.header.slot], &block_hash_vec)?;
self.order.insert(&[block.header.height], &block_hash_vec)?;
// Store extra stuff based on block version
if block.header.version > 0 {
@@ -505,7 +506,7 @@ impl BlockchainOverlay {
/// Check if the given [`BlockInfo`] is in the database and all trees.
pub fn has_block(&self, block: &BlockInfo) -> Result<bool> {
let blockhash = match self.order.get(&[block.header.slot], true) {
let blockhash = match self.order.get(&[block.header.height], true) {
Ok(v) => v[0].unwrap(),
Err(_) => return Ok(false),
};
@@ -536,7 +537,7 @@ impl BlockchainOverlay {
}
// Check provided info produces the same hash
Ok(blockhash == block.blockhash())
Ok(blockhash == block.hash()?)
}
/// Retrieve [`BlockInfo`]s by given hashes. Fails if any of them is not found.
@@ -563,13 +564,13 @@ impl BlockchainOverlay {
// Retrieve extra stuff based on block version
let mut block_slots = vec![];
if header.version > 0 {
let slots = self.blocks_slots.get(&[block.blockhash()], true)?;
let slots = self.blocks_slots.get(&[block.hash()?], true)?;
let slots = slots[0].clone().unwrap();
let slots = self.slots.get(&slots, true)?;
block_slots = slots.iter().map(|x| x.clone().unwrap()).collect();
}
let info = BlockInfo::new(header, txs, block.signature, block.eta, block_slots);
let info = BlockInfo::new(header, txs, block.signature, block_slots);
ret.push(info);
}

View File

@@ -789,7 +789,7 @@ impl ValidatorState {
// TODO: FIXME: The state transitions have already been written, they have to be in memory
// until this point.
info!(target: "consensus::validator", "Applying state transition for finalized block");
match self.verify_transactions(&proposal.txs, proposal.header.slot, true).await {
match self.verify_transactions(&proposal.txs, proposal.header.height, true).await {
Ok(erroneous_txs) => {
if !erroneous_txs.is_empty() {
error!(target: "consensus::validator", "Finalized block contains erroneous transactions");
@@ -871,7 +871,7 @@ impl ValidatorState {
info!(target: "consensus::validator", "receive_blocks(): Starting state transition validations");
for block in blocks {
match self.verify_transactions(&block.txs, block.header.slot, true).await {
match self.verify_transactions(&block.txs, block.header.height, true).await {
Ok(erroneous_txs) => {
if !erroneous_txs.is_empty() {
error!(target: "consensus::validator", "receive_blocks(): Block contains erroneous transactions");
@@ -894,8 +894,8 @@ impl ValidatorState {
/// Validate and append to canonical state received finalized block.
/// Returns boolean flag indicating already existing block.
pub async fn receive_finalized_block(&mut self, block: BlockInfo) -> Result<bool> {
if block.header.slot > self.consensus.time_keeper.current_slot() {
warn!(target: "consensus::validator", "receive_finalized_block(): Ignoring future block: {}", block.header.slot);
if block.header.height > self.consensus.time_keeper.current_slot() {
warn!(target: "consensus::validator", "receive_finalized_block(): Ignoring future block: {}", block.header.height);
return Ok(false)
}
match self.blockchain.has_block(&block) {
@@ -934,8 +934,8 @@ impl ValidatorState {
pub async fn receive_sync_blocks(&mut self, blocks: &[BlockInfo]) -> Result<()> {
let mut new_blocks = vec![];
for block in blocks {
if block.header.slot > self.consensus.time_keeper.current_slot() {
warn!(target: "consensus::validator", "receive_sync_blocks(): Ignoring future block: {}", block.header.slot);
if block.header.height > self.consensus.time_keeper.current_slot() {
warn!(target: "consensus::validator", "receive_sync_blocks(): Ignoring future block: {}", block.header.height);
continue
}
match self.blockchain.has_block(block) {

View File

@@ -61,7 +61,7 @@ fn consensus_contract_stake_unstake() -> Result<()> {
// Now Alice can stake her owncoin
let alice_staked_oc =
th.execute_stake(&HOLDERS, &Holder::Alice, current_slot, &alice_oc, 21).await?;
th.execute_stake(&HOLDERS, &Holder::Alice, current_slot, &alice_oc, 28).await?;
// We progress after grace period
current_slot += (calculate_grace_period() * EPOCH_LENGTH) + EPOCH_LENGTH;
@@ -98,7 +98,7 @@ fn consensus_contract_stake_unstake() -> Result<()> {
// Now Alice can stake her unstaked owncoin again to try some mallicious cases
let alice_staked_oc = th
.execute_stake(&HOLDERS, &Holder::Alice, current_slot, &alice_unstaked_oc, 121)
.execute_stake(&HOLDERS, &Holder::Alice, current_slot, &alice_unstaked_oc, 92)
.await?;
// Alice tries to stake her coin again
@@ -106,7 +106,7 @@ fn consensus_contract_stake_unstake() -> Result<()> {
info!(target: "consensus", "[Malicious] Checking staking coin again");
info!(target: "consensus", "[Malicious] ===========================");
let (stake_tx, _, _) = th
.stake(&Holder::Alice, current_slot, &alice_unstaked_oc, pallas::Base::from(121))
.stake(&Holder::Alice, current_slot, &alice_unstaked_oc, pallas::Base::from(92))
.await?;
th.execute_erroneous_txs(
TxAction::ConsensusStake,
@@ -188,7 +188,7 @@ fn consensus_contract_stake_unstake() -> Result<()> {
// Now Alice can stake her unstaked owncoin again
let alice_staked_oc = th
.execute_stake(&HOLDERS, &Holder::Alice, current_slot, &alice_unstaked_oc, 181)
.execute_stake(&HOLDERS, &Holder::Alice, current_slot, &alice_unstaked_oc, 77)
.await?;
// We progress after grace period

View File

@@ -62,7 +62,7 @@ impl TestHarness {
pallas::Scalar::random(&mut OsRng),
pallas::Base::random(&mut OsRng),
pallas::Scalar::random(&mut OsRng),
pallas::Base::from(4),
pallas::Base::from(41),
)?;
let (genesis_stake_params, genesis_stake_proofs) =

View File

@@ -273,7 +273,7 @@ impl TestHarness {
holders,
proving_keys,
tx_action_benchmarks,
genesis_block: genesis_block.blockhash(),
genesis_block: genesis_block.hash()?,
})
}

View File

@@ -18,7 +18,7 @@
use darkfi_sdk::{
blockchain::{expected_reward, PidOutput, PreviousSlot, Slot},
crypto::{schnorr::SchnorrSecret, MerkleNode, MerkleTree, SecretKey},
crypto::{schnorr::SchnorrSecret, SecretKey},
pasta::{group::ff::PrimeField, pallas},
};
use darkfi_serial::{async_trait, serialize, SerialDecodable, SerialEncodable};
@@ -94,7 +94,7 @@ impl Consensus {
for fork in &self.forks {
let last_proposal = fork.last_proposal()?;
if last_proposal.block.header.slot == slot {
if last_proposal.block.header.height == slot {
producers += 1;
}
last_hashes.push(last_proposal.hash);
@@ -132,16 +132,6 @@ impl Consensus {
let mut unproposed_txs = fork.unproposed_txs(&self.blockchain, &time_keeper).await?;
unproposed_txs.push(proposal_tx);
// Calculate transactions tree root
let mut tree = MerkleTree::new(100);
// The following is pretty weird, so something better should be done.
for tx in &unproposed_txs {
let mut hash = [0_u8; 32];
hash[0..31].copy_from_slice(&blake3::hash(&serialize(tx)).as_bytes()[0..31]);
tree.append(MerkleNode::from(pallas::Base::from_repr(hash).unwrap()));
}
let root = tree.root(0).unwrap();
// Grab forks' last block proposal(previous)
let previous = fork.last_proposal()?;
@@ -149,23 +139,25 @@ impl Consensus {
let slot = fork.slots.last().unwrap();
// TODO: verify if header timestamp should be blockchain or system timestamp
let header = Header::new(
previous.block.blockhash(),
previous.block.hash()?,
time_keeper.slot_epoch(slot.id),
slot.id,
Timestamp::current_time(),
root,
slot.last_eta,
);
// Generate the block
let mut block = BlockInfo::new_empty(header, fork.slots.clone());
// Add transactions to the block
block.append_txs(unproposed_txs)?;
// TODO: sign more stuff?
// Sign block header using provided secret key
let signature = secret_key.sign(&mut OsRng, &header.headerhash()?.as_bytes()[..]);
block.signature = secret_key.sign(&mut OsRng, &block.header.hash()?.as_bytes()[..]);
// Generate the block and its proposal
let block =
BlockInfo::new(header, unproposed_txs, signature, slot.last_eta, fork.slots.clone());
let proposal = Proposal::new(block);
Ok(proposal)
// Generate the block proposal from the block
Proposal::new(block)
}
/// Given a proposal, the node verifys it and finds which fork it extends.
@@ -193,12 +185,12 @@ impl Consensus {
let hdr = &proposal.block.header;
// Ignore proposal if not for current slot (2)
if hdr.slot != time_keeper.verifying_slot {
if hdr.height != time_keeper.verifying_slot {
return Err(Error::ProposalNotForCurrentSlotError)
}
// Check if proposal hash matches actual one (3)
let proposal_hash = proposal.block.blockhash();
let proposal_hash = proposal.block.hash()?;
if proposal.hash != proposal_hash {
warn!(
target: "validator::consensus::append_proposal", "Received proposal contains mismatched hashes: {} - {}",
@@ -302,7 +294,7 @@ impl Consensus {
// Check if we extend canonical
let (last_slot, last_block) = self.blockchain.last()?;
if proposal.block.header.previous != last_block ||
proposal.block.header.slot <= last_slot
proposal.block.header.height <= last_slot
{
return Err(Error::ExtendedChainIndexNotFound)
}
@@ -333,7 +325,7 @@ impl Consensus {
// Validate and insert each block
for block in blocks {
// Use block slot in time keeper
time_keeper.verifying_slot = block.header.slot;
time_keeper.verifying_slot = block.header.height;
// Retrieve expected reward
let expected_reward = expected_reward(time_keeper.verifying_slot);
@@ -352,7 +344,7 @@ impl Consensus {
{
error!(target: "validator::consensus::find_extended_fork_overlay", "Erroneous block found in set");
fork.overlay.lock().unwrap().overlay.lock().unwrap().purge_new_trees()?;
return Err(Error::BlockIsInvalid(block.blockhash().to_string()))
return Err(Error::BlockIsInvalid(block.hash()?.to_string()))
};
// Use last inserted block as next iteration previous
@@ -432,9 +424,9 @@ pub struct Proposal {
}
impl Proposal {
pub fn new(block: BlockInfo) -> Self {
let hash = block.blockhash();
Self { hash, block }
pub fn new(block: BlockInfo) -> Result<Self> {
let hash = block.hash()?;
Ok(Self { hash, block })
}
}
@@ -477,7 +469,7 @@ impl Fork {
.clone()
};
Ok(Proposal::new(block))
Proposal::new(block)
}
/// Utility function to extract leader selection lottery randomness(eta),
@@ -485,7 +477,7 @@ impl Fork {
fn get_last_eta(&self) -> Result<pallas::Base> {
// Retrieve last block(or proposal) hash
let hash = if self.proposals.is_empty() {
self.overlay.lock().unwrap().last_block()?.blockhash()
self.overlay.lock().unwrap().last_block()?.hash()?
} else {
*self.proposals.last().unwrap()
};

View File

@@ -260,7 +260,7 @@ impl Validator {
/// The node retrieves a block and tries to add it if it doesn't
/// already exists.
pub async fn append_block(&mut self, block: &BlockInfo) -> Result<()> {
let block_hash = block.blockhash().to_string();
let block_hash = block.hash()?.to_string();
// Check if block already exists
if self.blockchain.has_block(block)? {
@@ -301,8 +301,8 @@ impl Validator {
// Validate and insert each block
for block in blocks {
// Use block slot in time keeper
time_keeper.verifying_slot = block.header.slot;
// Use block height in time keeper
time_keeper.verifying_slot = block.header.height;
// Retrieve expected reward
let expected_reward = expected_reward(time_keeper.verifying_slot);
@@ -321,7 +321,7 @@ impl Validator {
{
error!(target: "validator::add_blocks", "Erroneous block found in set");
overlay.lock().unwrap().overlay.lock().unwrap().purge_new_trees()?;
return Err(Error::BlockIsInvalid(block.blockhash().to_string()))
return Err(Error::BlockIsInvalid(block.hash()?.to_string()))
};
// Store block transactions
@@ -477,8 +477,8 @@ impl Validator {
// Validate and insert each block
for block in &blocks[1..] {
// Use block slot in time keeper
time_keeper.verifying_slot = block.header.slot;
// Use block height in time keeper
time_keeper.verifying_slot = block.header.height;
// Retrieve expected reward
let expected_reward = expected_reward(time_keeper.verifying_slot);
@@ -497,7 +497,7 @@ impl Validator {
{
error!(target: "validator::validate_blockchain", "Erroneous block found in set");
overlay.lock().unwrap().overlay.lock().unwrap().purge_new_trees()?;
return Err(Error::BlockIsInvalid(block.blockhash().to_string()))
return Err(Error::BlockIsInvalid(block.hash()?.to_string()))
};
// Use last inserted block as next iteration previous

View File

@@ -35,8 +35,8 @@ use crate::{
/// 5. Slot is the same as the slots vector last slot id
/// Additional validity rules can be applied.
pub fn validate_block(block: &BlockInfo, previous: &BlockInfo, expected_reward: u64) -> Result<()> {
let error = Err(Error::BlockIsInvalid(block.blockhash().to_string()));
let previous_hash = previous.blockhash();
let error = Err(Error::BlockIsInvalid(block.hash()?.to_string()));
let previous_hash = previous.hash()?;
// Check previous hash (1)
if block.header.previous != previous_hash {
@@ -48,8 +48,8 @@ pub fn validate_block(block: &BlockInfo, previous: &BlockInfo, expected_reward:
return error
}
// Check slots are incremental (3)
if block.header.slot <= previous.header.slot {
// Check heights are incremental (3)
if block.header.height <= previous.header.height {
return error
}
@@ -73,7 +73,7 @@ pub fn validate_block(block: &BlockInfo, previous: &BlockInfo, expected_reward:
previous_slot,
&previous_hash,
&previous.header.previous,
&previous.eta,
&previous.header.nonce,
0,
)?;
previous_slot = slot;
@@ -85,12 +85,12 @@ pub fn validate_block(block: &BlockInfo, previous: &BlockInfo, expected_reward:
previous_slot,
&previous_hash,
&previous.header.previous,
&previous.eta,
&previous.header.nonce,
expected_reward,
)?;
// Check block slot is the last slot id (5)
if block.slots.last().unwrap().id != block.header.slot {
// Check block height is the last slot id (5)
if block.slots.last().unwrap().id != block.header.height {
return error
}
}
@@ -172,7 +172,7 @@ pub fn validate_blockchain(blockchain: &Blockchain) -> Result<()> {
let blocks = blockchain.order.get_all()?;
for (index, block) in blocks[1..].iter().enumerate() {
let full_blocks = blockchain.get_blocks_by_hash(&[blocks[index].1, block.1])?;
let expected_reward = expected_reward(full_blocks[1].header.slot);
let expected_reward = expected_reward(full_blocks[1].header.height);
validate_block(&full_blocks[1], &full_blocks[0], expected_reward)?;
}

View File

@@ -43,7 +43,7 @@ pub async fn verify_genesis_block(
block: &BlockInfo,
genesis_txs_total: u64,
) -> Result<()> {
let block_hash = block.blockhash().to_string();
let block_hash = block.hash()?.to_string();
debug!(target: "validator::verification::verify_genesis_block", "Validating genesis block {}", block_hash);
// Check if block already exists
@@ -51,8 +51,8 @@ pub async fn verify_genesis_block(
return Err(Error::BlockAlreadyExists(block_hash))
}
// Block slot must be the same as the time keeper verifying slot
if block.header.slot != time_keeper.verifying_slot {
// Block height must be the same as the time keeper verifying slot
if block.header.height != time_keeper.verifying_slot {
return Err(Error::VerifyingSlotMissmatch())
}
@@ -115,7 +115,7 @@ pub async fn verify_block(
expected_reward: u64,
testing_mode: bool,
) -> Result<()> {
let block_hash = block.blockhash().to_string();
let block_hash = block.hash()?.to_string();
debug!(target: "validator::verification::verify_block", "Validating block {}", block_hash);
// Check if block already exists
@@ -123,8 +123,8 @@ pub async fn verify_block(
return Err(Error::BlockAlreadyExists(block_hash))
}
// Block slot must be the same as the time keeper verifying slot
if block.header.slot != time_keeper.verifying_slot {
// Block height must be the same as the time keeper verifying slot
if block.header.height != time_keeper.verifying_slot {
return Err(Error::VerifyingSlotMissmatch())
}

View File

@@ -55,8 +55,8 @@ impl Harness {
Ok(())
}
fn generate_next_block(&self, previous: &BlockInfo) -> BlockInfo {
let previous_hash = previous.blockhash();
fn generate_next_block(&self, previous: &BlockInfo) -> Result<BlockInfo> {
let previous_hash = previous.hash()?;
// Generate slot
let previous_slot = previous.slots.last().unwrap();
@@ -80,9 +80,18 @@ impl Harness {
// Generate header
let header =
Header::new(previous_hash, previous.header.epoch, id, timestamp, previous.header.root);
Header::new(previous_hash, previous.header.epoch, id, timestamp, previous.header.nonce);
BlockInfo::new(header, previous.txs.clone(), previous.signature, previous.eta, vec![slot])
// Generate the block
let mut block = BlockInfo::new_empty(header, vec![slot]);
// Add transactions to the block
block.append_txs(previous.txs.clone())?;
// Attach signature
block.signature = previous.signature;
Ok(block)
}
fn add_blocks(&self, blocks: &[BlockInfo]) -> Result<()> {
@@ -105,13 +114,13 @@ impl Harness {
for block in blocks {
// Check if block already exists
if lock.has_block(block)? {
return Err(Error::BlockAlreadyExists(block.blockhash().to_string()))
return Err(Error::BlockAlreadyExists(block.hash()?.to_string()))
}
// This will be true for every insert, apart from genesis
if let Some(p) = previous {
// Retrieve expected reward
let expected_reward = expected_reward(block.header.slot);
let expected_reward = expected_reward(block.header.height);
// Validate block
validate_block(block, &p, expected_reward)?;
@@ -146,13 +155,13 @@ fn blockchain_add_blocks() -> Result<()> {
let genesis_block = BlockInfo::default();
blocks.push(genesis_block.clone());
let block = th.generate_next_block(&genesis_block);
let block = th.generate_next_block(&genesis_block)?;
blocks.push(block.clone());
let block = th.generate_next_block(&block);
let block = th.generate_next_block(&block)?;
blocks.push(block.clone());
let block = th.generate_next_block(&block);
let block = th.generate_next_block(&block)?;
blocks.push(block.clone());
th.add_blocks(&blocks)?;