Skip to content

Commit

Permalink
consensus: generate committees when starting from loaded iteration
Browse files Browse the repository at this point in the history
- add generate_committee to IterationCtx
- move committee generation code from phase `run` function
- remove save_committee
- move get_sortition_config to IterationCtx
  • Loading branch information
fed-franz committed Aug 31, 2024
1 parent 573406d commit 4aac4dc
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 76 deletions.
37 changes: 37 additions & 0 deletions consensus/src/consensus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use crate::operations::Operations;
use crate::phase::Phase;

use node_data::message::{AsyncQueue, Message, Topics};
use node_data::StepName;

use crate::execution_ctx::ExecutionCtx;
use crate::proposal;
Expand Down Expand Up @@ -184,6 +185,35 @@ impl<T: Operations + 'static, D: Database + 'static> Consensus<T, D> {
ru.base_timeouts.clone(),
);

// TODO: load save iteration
let saved_iter = 0;

// If starting from `saved_iter`, we regenerate all committees
// in case they are needed to process past-iteration messages in
// Emergency Mode
if saved_iter != 0 {
while iter <= saved_iter {
iter_ctx.on_begin(iter);
iter_ctx.generate_committee(
StepName::Proposal,
provisioners.as_ref(),
ru.seed(),
);
iter_ctx.generate_committee(
StepName::Validation,
provisioners.as_ref(),
ru.seed(),
);
iter_ctx.generate_committee(
StepName::Ratification,
provisioners.as_ref(),
ru.seed(),
);
}

iter = saved_iter + 1;
}

loop {
Self::consensus_delay().await;

Expand All @@ -197,6 +227,13 @@ impl<T: Operations + 'static, D: Database + 'static> Consensus<T, D> {
// phase.
phase.reinitialize(msg, ru.round, iter).await;

// Generate step committee
iter_ctx.generate_committee(
step_name,
provisioners.as_ref(),
ru.seed(),
);

// Construct phase execution context
let ctx = ExecutionCtx::new(
&mut iter_ctx,
Expand Down
19 changes: 1 addition & 18 deletions consensus/src/execution_ctx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use crate::queue::MsgRegistry;
use crate::step_votes_reg::SafeAttestationInfoRegistry;
use crate::user::committee::Committee;
use crate::user::provisioners::Provisioners;
use crate::user::sortition;


use node_data::bls::PublicKeyBytes;
use node_data::ledger::Block;
Expand Down Expand Up @@ -106,10 +106,6 @@ impl<'a, T: Operations + 'static> ExecutionCtx<'a, T> {
committee.is_member(&self.round_update.pubkey_bls)
}

pub(crate) fn save_committee(&mut self, step: u8, committee: Committee) {
self.iter_ctx.committees.insert(step, committee);
}

pub(crate) fn get_current_committee(&self) -> Option<&Committee> {
self.iter_ctx.committees.get_committee(self.step())
}
Expand Down Expand Up @@ -456,19 +452,6 @@ impl<'a, T: Operations + 'static> ExecutionCtx<'a, T> {
None
}

pub fn get_sortition_config(
&self,
exclusion: Vec<PublicKeyBytes>,
) -> sortition::Config {
sortition::Config::new(
self.round_update.seed(),
self.round_update.round,
self.iteration,
self.step_name(),
exclusion,
)
}

/// Reports step elapsed time to the client
async fn report_elapsed_time(&mut self) {
let elapsed = self
Expand Down
90 changes: 89 additions & 1 deletion consensus/src/iteration_ctx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,18 @@
use crate::commons::{RoundUpdate, TimeoutSet};
use std::cmp;

use crate::config::{MAX_STEP_TIMEOUT, TIMEOUT_INCREASE};
use crate::config::{CONSENSUS_MAX_ITER, MAX_STEP_TIMEOUT, TIMEOUT_INCREASE};
use crate::msg_handler::HandleMsgOutput;
use crate::msg_handler::MsgHandler;

use crate::user::committee::Committee;
use crate::user::provisioners::Provisioners;
use crate::user::sortition;

use crate::{ratification, validation};
use node_data::bls::PublicKeyBytes;

use node_data::ledger::Seed;
use node_data::message::Message;
use std::collections::HashMap;
use std::ops::Add;
Expand Down Expand Up @@ -131,6 +134,91 @@ impl IterationCtx {
.expect("valid timeout per step")
}

fn get_sortition_config(
&self,
seed: Seed,
step_name: StepName,
exclusion: Vec<PublicKeyBytes>,
) -> sortition::Config {
sortition::Config::new(
seed, self.round, self.iter, step_name, exclusion,
)
}

pub(crate) fn generate_committee(
&mut self,
step_name: StepName,
provisioners: &Provisioners,
seed: Seed,
) {
let iteration = self.iter;
let step = step_name.to_step(iteration);

// Check if this committee has been already generated
if self.committees.get_committee(step).is_some() {
return;
}

// Fill up exclusion list
//
// We exclude the generators for the current iteration and the next one
// to avoid conflict of interests
let exclusion = match step_name {
StepName::Proposal => vec![],
_ => {
let mut exclusion_list = vec![];
// Exclude generator for current iteration
let cur_generator = self
.get_generator(iteration)
.expect("Proposal committee to be already generated");

exclusion_list.push(cur_generator);

// Exclude generator for next iteration
if iteration < CONSENSUS_MAX_ITER {
let next_generator =
self.get_generator(iteration + 1).expect(
"Next Proposal committee to be already generated",
);

exclusion_list.push(next_generator);
}

exclusion_list
}
};

// Generate the committee for the current step
// If the step is Proposal, the only extracted member is the generator
// For Validation and Ratification steps, extracted members are
// delegated to vote on the candidate block
let step_committee = Committee::new(
provisioners,
&self.get_sortition_config(seed, step_name, exclusion),
);

if let StepName::Proposal = step_name {
if iteration < CONSENSUS_MAX_ITER {
let mut cfg_next_iteration =
self.get_sortition_config(seed, step_name, vec![]);
cfg_next_iteration.step =
StepName::Proposal.to_step(iteration + 1);

let next_iteration_generator =
Committee::new(provisioners, &cfg_next_iteration);
self.committees
.insert(cfg_next_iteration.step, next_iteration_generator);
}
}

debug!(
event = "committee_generated",
members = format!("{}", &step_committee)
);

self.committees.insert(step, step_committee);
}

pub(crate) fn get_generator(&self, iter: u8) -> Option<PublicKeyBytes> {
let step = StepName::Proposal.to_step(iter);
self.committees
Expand Down
57 changes: 0 additions & 57 deletions consensus/src/phase.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,8 @@
// Copyright (c) DUSK NETWORK. All rights reserved.

use crate::commons::{ConsensusError, Database};
use crate::config::CONSENSUS_MAX_ITER;
use crate::execution_ctx::ExecutionCtx;
use crate::operations::Operations;
use crate::user::committee::Committee;
use crate::{proposal, ratification, validation};
use node_data::message::Message;
use node_data::StepName;
Expand Down Expand Up @@ -58,64 +56,9 @@ impl<T: Operations + 'static, D: Database + 'static> Phase<T, D> {
) -> Result<Message, ConsensusError> {
ctx.set_start_time();

let step_name = ctx.step_name();
let timeout = ctx.iter_ctx.get_timeout(ctx.step_name());
debug!(event = "execute_step", ?timeout);

let exclusion = match step_name {
StepName::Proposal => vec![],
_ => {
let mut exclusion_list = vec![];
let generator = ctx
.iter_ctx
.get_generator(ctx.iteration)
.expect("Proposal committee to be already generated");

exclusion_list.push(generator);

if ctx.iteration < CONSENSUS_MAX_ITER {
let next_generator =
ctx.iter_ctx.get_generator(ctx.iteration + 1).expect(
"Next Proposal committee to be already generated",
);

exclusion_list.push(next_generator);
}

exclusion_list
}
};

// Perform deterministic_sortition to generate committee of size=N.
// The extracted members are the provisioners eligible to vote on this
// particular round and step. In the context of Proposal phase,
// the extracted member is the one eligible to generate the candidate
// block.
let step_committee = Committee::new(
ctx.provisioners,
&ctx.get_sortition_config(exclusion),
);

if let StepName::Proposal = step_name {
if ctx.iteration < CONSENSUS_MAX_ITER {
let mut cfg_next_iteration = ctx.get_sortition_config(vec![]);
cfg_next_iteration.step =
StepName::Proposal.to_step(ctx.iteration + 1);

ctx.save_committee(
cfg_next_iteration.step,
Committee::new(ctx.provisioners, &cfg_next_iteration),
);
}
}

debug!(
event = "committee_generated",
members = format!("{}", &step_committee)
);

ctx.save_committee(ctx.step(), step_committee);

// Execute step
await_phase!(self, run(ctx))
}
Expand Down

0 comments on commit 4aac4dc

Please sign in to comment.