mirror of
https://github.com/darkrenaissance/darkfi.git
synced 2026-01-08 22:28:12 -05:00
blockchain/Block: refactored in preparation for mining integration
This commit is contained in:
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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 }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) =
|
||||
|
||||
@@ -273,7 +273,7 @@ impl TestHarness {
|
||||
holders,
|
||||
proving_keys,
|
||||
tx_action_benchmarks,
|
||||
genesis_block: genesis_block.blockhash(),
|
||||
genesis_block: genesis_block.hash()?,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -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()
|
||||
};
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)?;
|
||||
}
|
||||
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
|
||||
|
||||
@@ -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)?;
|
||||
|
||||
Reference in New Issue
Block a user