Skip to content

Commit

Permalink
node: support Slash structs
Browse files Browse the repository at this point in the history
- Change CallParams to use `Slash` array instead of missing generators
- Implement `operations::Error`
- Add `verify_faults` while verifying block header
  • Loading branch information
herr-seppia committed Jul 16, 2024
1 parent 74f60f7 commit 9376e99
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 32 deletions.
18 changes: 7 additions & 11 deletions node/src/chain/acceptor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use dusk_consensus::config::{MAX_STEP_TIMEOUT, MIN_STEP_TIMEOUT};
use dusk_consensus::user::provisioners::{ContextProvisioners, Provisioners};
use node_data::bls::PublicKey;
use node_data::ledger::{
self, to_str, Block, BlockWithLabel, Label, Seed, SpentTransaction,
self, to_str, Block, BlockWithLabel, Label, Seed, Slash, SpentTransaction,
};
use node_data::message::AsyncQueue;
use node_data::message::Payload;
Expand Down Expand Up @@ -299,13 +299,10 @@ impl<DB: database::DB, VM: vm::VMExecution, N: Network> Acceptor<N, DB, VM> {
let mut changed_provisioners = vec![reward, dusk_reward];

// Update provisioners if a slash has been applied
for bytes in blk.header().failed_iterations.to_missed_generators_bytes()
{
let slashed = bytes.0.try_into().map_err(|e| {
anyhow::anyhow!("Cannot deserialize bytes {e:?}")
})?;
changed_provisioners.push(ProvisionerChange::Slash(slashed));
}
let slashed = Slash::from_header(blk.header())?
.into_iter()
.map(|f| ProvisionerChange::Slash(f.provisioner));
changed_provisioners.extend(slashed);

// FIX_ME: This relies on the stake contract being called only by the
// transfer contract. We should change this once third-party contracts
Expand Down Expand Up @@ -482,9 +479,8 @@ impl<DB: database::DB, VM: vm::VMExecution, N: Network> Acceptor<N, DB, VM> {
header.height,
);

for slashed in header.failed_iterations.to_missed_generators_bytes()
{
info!("Slashed {}", slashed.to_base58());
for slashed in Slash::from_header(blk.header())? {
info!("Slashed {}", slashed.provisioner.to_base58());
slashed_count += 1;
}

Expand Down
26 changes: 7 additions & 19 deletions node/src/chain/consensus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ use async_trait::async_trait;
use dusk_consensus::commons::{ConsensusError, RoundUpdate, TimeoutSet};
use dusk_consensus::consensus::Consensus;
use dusk_consensus::operations::{
CallParams, Error, Operations, Output, VerificationOutput, VoterWithCredits,
self, CallParams, Error, Operations, Output, VerificationOutput,
VoterWithCredits,
};
use dusk_consensus::queue::MsgRegistry;
use dusk_consensus::user::provisioners::ContextProvisioners;
Expand Down Expand Up @@ -257,10 +258,7 @@ impl<DB: database::DB, VM: vm::VMExecution> Operations for Executor<DB, VM> {
validator
.execute_checks(candidate_header, disable_winning_att_check)
.await
.map_err(|err| {
error!("failed to verify header {}", err);
Error::Failed
})
.map_err(operations::Error::InvalidHeader)
}

async fn verify_state_transition(
Expand All @@ -272,12 +270,8 @@ impl<DB: database::DB, VM: vm::VMExecution> Operations for Executor<DB, VM> {

let vm = self.vm.read().await;

Ok(vm
.verify_state_transition(blk, Some(voters))
.map_err(|err| {
error!("failed to call VST {}", err);
Error::Failed
})?)
vm.verify_state_transition(blk, Some(voters))
.map_err(operations::Error::InvalidVST)
}

async fn execute_state_transition(
Expand All @@ -298,10 +292,7 @@ impl<DB: database::DB, VM: vm::VMExecution> Operations for Executor<DB, VM> {
)?;
Ok(ret)
})
.map_err(|err: anyhow::Error| {
error!("{err}");
Error::Failed
})?;
.map_err(Error::InvalidEST)?;
let _ = db.update(|m| {
for t in &discarded_txs {
let _ = m.delete_tx(t.id());
Expand Down Expand Up @@ -345,10 +336,7 @@ impl<DB: database::DB, VM: vm::VMExecution> Operations for Executor<DB, VM> {

t.op_write(db_key, bytes)
})
.map_err(|err: anyhow::Error| {
error!("{err}");
Error::Failed
})?;
.map_err(Error::MetricsUpdate)?;

Ok(())
}
Expand Down
43 changes: 41 additions & 2 deletions node/src/chain/header_validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@ use dusk_consensus::quorum::verifiers;
use dusk_consensus::quorum::verifiers::QuorumResult;
use dusk_consensus::user::committee::{Committee, CommitteeSet};
use dusk_consensus::user::provisioners::{ContextProvisioners, Provisioners};
use execution_core::stake::EPOCH;
use node_data::ledger::Signature;
use node_data::ledger::{to_str, Seed};
use node_data::ledger::{to_str, Header, Seed};
use node_data::message::payload::RatificationResult;
use node_data::message::ConsensusHeader;
use node_data::{ledger, StepName};
Expand Down Expand Up @@ -61,7 +62,7 @@ impl<'a, DB: database::DB> Validator<'a, DB> {
/// Returns the number of Previous Non-Attested Iterations (PNI)
pub async fn execute_checks(
&self,
candidate_block: &'_ ledger::Header,
candidate_block: &ledger::Header,
disable_winner_att_check: bool,
) -> anyhow::Result<(u8, Vec<VoterWithCredits>, Vec<VoterWithCredits>)>
{
Expand All @@ -75,6 +76,8 @@ impl<'a, DB: database::DB> Validator<'a, DB> {
self.verify_success_att(candidate_block).await?;
}

self.verify_faults(candidate_block).await?;

let pni = self.verify_failed_iterations(candidate_block).await?;
Ok((pni, prev_block_voters, candidate_block_voters))
}
Expand Down Expand Up @@ -276,6 +279,42 @@ impl<'a, DB: database::DB> Validator<'a, DB> {

Ok(voters)
}

/// Verify faults inside a block.
pub async fn verify_faults(
&self,
header: &ledger::Header,
) -> anyhow::Result<()> {
verify_faults(self.db.clone(), header).await
}
}

pub async fn verify_faults<DB: database::DB>(
db: Arc<RwLock<DB>>,
header: &Header,
) -> anyhow::Result<()> {
for f in &header.faults {
let fault_header = f.validate(header.height)?;
db.read().await.view(|db| {
let (prev_header, _) = db
.fetch_block_header(&fault_header.prev_block_hash)?
.ok_or(anyhow::anyhow!("Slashing a non accepted header"))?;
if prev_header.height != fault_header.round - 1 {
anyhow::bail!("Invalid height for fault");
}

// FIX_ME: Instead of fetching all store faults, check the fault id
// directly This needs the fault id to be changed into
// "HEIGHT|TYPE|PROV_KEY"
let stored_faults = db.fetch_faults(fault_header.round - EPOCH)?;
if stored_faults.iter().any(|other| f.same(other)) {
anyhow::bail!("Double fault detected");
}

Ok(())
})?;
}
Ok(())
}

pub async fn verify_block_att(
Expand Down

0 comments on commit 9376e99

Please sign in to comment.