mirror of
https://github.com/darkrenaissance/darkfi.git
synced 2026-04-28 03:00:18 -04:00
validator: current slot generation added
This commit is contained in:
@@ -260,4 +260,12 @@ impl SlotStoreOverlay {
|
||||
|
||||
Ok(ret)
|
||||
}
|
||||
|
||||
/// Fetch the last slot from the overlay, based on the `Ord`
|
||||
/// implementation for `Vec<u8>`.
|
||||
pub fn get_last(&self) -> Result<Slot> {
|
||||
let found = self.0.lock().unwrap().last(SLED_SLOT_TREE)?.unwrap();
|
||||
let slot = deserialize(&found.1)?;
|
||||
Ok(slot)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -172,8 +172,7 @@ impl ProtocolSync {
|
||||
let lock = self.state.read().await;
|
||||
let current = lock.consensus.time_keeper.current_slot();
|
||||
let participating = lock.consensus.participating;
|
||||
if participating.is_some() {
|
||||
let slot = participating.unwrap();
|
||||
if let Some(slot) = participating {
|
||||
if current >= slot {
|
||||
debug!(
|
||||
target: "consensus::protocol_sync::handle_receive_block()",
|
||||
@@ -308,8 +307,7 @@ impl ProtocolSync {
|
||||
let lock = self.state.read().await;
|
||||
let current = lock.consensus.time_keeper.current_slot();
|
||||
let participating = lock.consensus.participating;
|
||||
if participating.is_some() {
|
||||
let slot = participating.unwrap();
|
||||
if let Some(slot) = participating {
|
||||
if current >= slot {
|
||||
debug!(
|
||||
target: "consensus::protocol_sync::handle_receive_slot()",
|
||||
|
||||
@@ -260,6 +260,9 @@ pub enum Error {
|
||||
#[error("Proposal contains missmatched hashes")]
|
||||
ProposalHashesMissmatchError,
|
||||
|
||||
#[error("Proposal contains unknown slots")]
|
||||
ProposalContainsUnknownSlots,
|
||||
|
||||
#[error("Proposal contains missmatched headers")]
|
||||
ProposalHeadersMissmatchError,
|
||||
|
||||
|
||||
@@ -16,13 +16,14 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
use darkfi_sdk::blockchain::{PidOutput, PreviousSlot, Slot};
|
||||
use darkfi_serial::{SerialDecodable, SerialEncodable};
|
||||
use log::{error, warn};
|
||||
|
||||
use crate::{
|
||||
blockchain::{BlockInfo, Blockchain, BlockchainOverlay, BlockchainOverlayPtr},
|
||||
util::time::TimeKeeper,
|
||||
validator::verify_block,
|
||||
validator::{consensus::pid::slot_pid_output, verify_block},
|
||||
Error, Result,
|
||||
};
|
||||
|
||||
@@ -64,6 +65,45 @@ impl Consensus {
|
||||
}
|
||||
}
|
||||
|
||||
/// Generate current hot/live slot for all current forks.
|
||||
pub fn generate_slot(&mut self) -> Result<()> {
|
||||
// Grab current slot id
|
||||
let id = self.time_keeper.current_slot();
|
||||
|
||||
// If no forks exist, create a new one as a basis to extend
|
||||
if self.forks.is_empty() {
|
||||
self.forks.push(Fork::new(&self.blockchain)?);
|
||||
}
|
||||
|
||||
// Grab previous slot information
|
||||
let (producers, last_hashes, second_to_last_hashes) = self.previous_slot_info(id - 1)?;
|
||||
|
||||
for fork in self.forks.iter_mut() {
|
||||
fork.generate_slot(id, producers, &last_hashes, &second_to_last_hashes)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Retrieve previous slot producers, last proposal hashes,
|
||||
/// and their second to last hashes, from all current forks.
|
||||
fn previous_slot_info(&self, slot: u64) -> Result<(u64, Vec<blake3::Hash>, Vec<blake3::Hash>)> {
|
||||
let mut producers = 0;
|
||||
let mut last_hashes = vec![];
|
||||
let mut second_to_last_hashes = vec![];
|
||||
|
||||
for fork in &self.forks {
|
||||
let last_proposal = fork.last_proposal()?;
|
||||
if last_proposal.block.header.slot == slot {
|
||||
producers += 1;
|
||||
}
|
||||
last_hashes.push(last_proposal.hash);
|
||||
second_to_last_hashes.push(last_proposal.block.header.previous);
|
||||
}
|
||||
|
||||
Ok((producers, last_hashes, second_to_last_hashes))
|
||||
}
|
||||
|
||||
/// Given a proposal, the node verifys it and finds which fork it extends.
|
||||
/// If the proposal extends the canonical blockchain, a new fork chain is created.
|
||||
/// A proposal is considered valid when the following rules apply:
|
||||
@@ -71,7 +111,9 @@ impl Consensus {
|
||||
/// 2. Proposal refers to current slot
|
||||
/// 3. Proposal hash matches the actual block one
|
||||
/// 4. Block transactions don't exceed set limit
|
||||
/// 5. Block is valid
|
||||
/// 5. If proposal extends a known fork, verify block slots
|
||||
/// correspond to the fork hot/live ones
|
||||
/// 6. Block is valid
|
||||
/// Additional validity rules can be applied.
|
||||
pub async fn append_proposal(&mut self, proposal: &Proposal) -> Result<()> {
|
||||
// Generate a time keeper for current slot
|
||||
@@ -115,13 +157,28 @@ impl Consensus {
|
||||
// Check if proposal extends any existing forks
|
||||
let (mut fork, index) = self.find_extended_fork(proposal).await?;
|
||||
|
||||
// Verify block slots correspond to the forks' hot/live ones (5)
|
||||
if !fork.slots.is_empty() && fork.slots != proposal.block.slots {
|
||||
return Err(Error::ProposalContainsUnknownSlots)
|
||||
}
|
||||
|
||||
// Insert last block slot so transactions can be validated against.
|
||||
// Rest (empty) slots will be inserted along with the block.
|
||||
// Since this fork uses an overlay clone, original overlay is not affected.
|
||||
fork.overlay.lock().unwrap().slots.insert(&[proposal
|
||||
.block
|
||||
.slots
|
||||
.last()
|
||||
.unwrap()
|
||||
.clone()])?;
|
||||
|
||||
// Grab overlay last block
|
||||
let previous = fork.overlay.lock().unwrap().last_block()?;
|
||||
|
||||
// Retrieve expected reward
|
||||
let expected_reward = next_block_reward();
|
||||
|
||||
// Verify proposal block (5)
|
||||
// Verify proposal block (6)
|
||||
if verify_block(
|
||||
&fork.overlay,
|
||||
&time_keeper,
|
||||
@@ -141,6 +198,7 @@ impl Consensus {
|
||||
// If a fork index was found, replace forks with the mutated one,
|
||||
// otherwise push the new fork.
|
||||
fork.proposals.push(proposal.hash);
|
||||
fork.slots = vec![];
|
||||
match index {
|
||||
Some(i) => {
|
||||
self.forks[i] = fork;
|
||||
@@ -273,6 +331,8 @@ pub struct Fork {
|
||||
pub overlay: BlockchainOverlayPtr,
|
||||
/// Fork proposal hashes sequence
|
||||
pub proposals: Vec<blake3::Hash>,
|
||||
/// Hot/live slots
|
||||
pub slots: Vec<Slot>,
|
||||
/// Valid pending transaction hashes
|
||||
pub mempool: Vec<blake3::Hash>,
|
||||
}
|
||||
@@ -280,7 +340,57 @@ pub struct Fork {
|
||||
impl Fork {
|
||||
pub fn new(blockchain: &Blockchain) -> Result<Self> {
|
||||
let overlay = BlockchainOverlay::new(blockchain)?;
|
||||
Ok(Self { overlay, proposals: vec![], mempool: vec![] })
|
||||
Ok(Self { overlay, proposals: vec![], slots: vec![], mempool: vec![] })
|
||||
}
|
||||
|
||||
/// Auxiliary function to retrieve last proposal
|
||||
pub fn last_proposal(&self) -> Result<Proposal> {
|
||||
let block = if self.proposals.is_empty() {
|
||||
self.overlay.lock().unwrap().last_block()?
|
||||
} else {
|
||||
self.overlay.lock().unwrap().get_blocks_by_hash(&[*self.proposals.last().unwrap()])?[0]
|
||||
.clone()
|
||||
};
|
||||
|
||||
Ok(Proposal::new(block))
|
||||
}
|
||||
|
||||
/// Generate current hot/live slot
|
||||
pub fn generate_slot(
|
||||
&mut self,
|
||||
id: u64,
|
||||
producers: u64,
|
||||
last_hashes: &[blake3::Hash],
|
||||
second_to_last_hashes: &[blake3::Hash],
|
||||
) -> Result<()> {
|
||||
// Grab last known fork slot
|
||||
let previous_slot = if self.slots.is_empty() {
|
||||
self.overlay.lock().unwrap().slots.get_last()?
|
||||
} else {
|
||||
self.slots.last().unwrap().clone()
|
||||
};
|
||||
|
||||
// Generate previous slot information
|
||||
let previous = PreviousSlot::new(
|
||||
producers,
|
||||
last_hashes.to_vec(),
|
||||
second_to_last_hashes.to_vec(),
|
||||
previous_slot.pid.error,
|
||||
);
|
||||
|
||||
// Generate PID controller output
|
||||
let (f, error, sigma1, sigma2) = slot_pid_output(&previous_slot, producers);
|
||||
let pid = PidOutput::new(f, error, sigma1, sigma2);
|
||||
|
||||
// Each slot starts as an empty slot(not reward) when generated, carrying
|
||||
// last eta
|
||||
let last_eta = previous_slot.last_eta;
|
||||
let total_tokens = previous_slot.total_tokens + previous_slot.reward;
|
||||
let reward = 0;
|
||||
let slot = Slot::new(id, previous, pid, last_eta, total_tokens, reward);
|
||||
self.slots.push(slot);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Auxiliary function to create a full clone using BlockchainOverlay::full_clone.
|
||||
@@ -289,9 +399,10 @@ impl Fork {
|
||||
pub fn full_clone(&self) -> Result<Self> {
|
||||
let overlay = self.overlay.lock().unwrap().full_clone()?;
|
||||
let proposals = self.proposals.clone();
|
||||
let slots = self.slots.clone();
|
||||
let mempool = self.mempool.clone();
|
||||
|
||||
Ok(Self { overlay, proposals, mempool })
|
||||
Ok(Self { overlay, proposals, slots, mempool })
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user