Skip to content

Commit

Permalink
feat(data_structures): sample V2_0 superblock committee from validators
Browse files Browse the repository at this point in the history
  • Loading branch information
aesedepece committed Dec 26, 2024
1 parent 672bacc commit 0ebb227
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 42 deletions.
43 changes: 21 additions & 22 deletions data_structures/src/superblock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -424,16 +424,20 @@ impl SuperBlockState {
self.ars_current_identities = new_identities;
}

/// Produces a `SuperBlock` that includes the blocks in `block_headers` if there is at least one of them.
/// `ars_identities` will be used to validate all the superblock votes received for the
/// next superblock. The votes for the current superblock must be validated using them
/// to calculate the superblock_signing_committee.
/// Produces a `SuperBlock` that includes the blocks in `block_headers` if there is at least
/// one of them.
///
/// `census` will be used to validate all the superblock votes received for the next superblock.
///
/// The votes for the current superblock must be validated using them to calculate
/// `superblock_signing_committee`.
///
/// The ordered bn256 keys will be merkelized and appended to the superblock
#[allow(clippy::cast_possible_truncation, clippy::too_many_arguments)]
pub fn build_superblock(
&mut self,
block_headers: &[BlockHeader],
ars_identities: Census,
census: Census,
signing_committee_size: u32,
superblock_index: u32,
last_block_in_previous_superblock: Hash,
Expand All @@ -442,28 +446,23 @@ impl SuperBlockState {
block_epoch: Epoch,
) -> SuperBlock {
let protocol_version = ProtocolVersion::from_epoch(block_epoch);
let key_leaves = hash_key_leaves(&ars_identities.get_rep_ordered_bn256_list(alt_keys));
let key_leaves = hash_key_leaves(&census.get_rep_ordered_bn256_list(alt_keys));

self.update_ars_identities(ars_identities);
self.update_ars_identities(census);

// Before updating the superblock_beacon, calculate the signing committee
let signing_committee = if let Some(ref sb) = sync_superblock {
calculate_superblock_signing_committee(
self.ars_previous_identities.clone(),
sb.signing_committee_length,
superblock_index,
self.current_superblock_beacon.hash_prev_block,
block_epoch,
)
let signing_committee_size = if let Some(ref sb) = sync_superblock {
sb.signing_committee_length
} else {
calculate_superblock_signing_committee(
self.ars_previous_identities.clone(),
signing_committee_size,
superblock_index,
self.current_superblock_beacon.hash_prev_block,
block_epoch,
)
signing_committee_size
};
let signing_committee = calculate_superblock_signing_committee(
self.ars_previous_identities.clone(),
signing_committee_size,
superblock_index,
self.current_superblock_beacon.hash_prev_block,
block_epoch,
);

// Override superblock signing committee during each of the different emergency periods
let emergency_committee =
Expand Down
54 changes: 34 additions & 20 deletions node/src/actors/chain_manager/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ use witnet_data_structures::{
radon_report::{RadonReport, ReportContext},
register_protocol_version,
staking::prelude::*,
superblock::{Census, AddSuperBlockVote, SuperBlockConsensus},
superblock::{AddSuperBlockVote, Census, SuperBlockConsensus},
transaction::{RevealTransaction, TallyTransaction, Transaction},
types::{
visitor::{StatefulVisitor, Visitor},
Expand Down Expand Up @@ -2022,27 +2022,41 @@ impl ChainManager {
let reputation_engine = act.chain_state.reputation_engine.as_ref().unwrap();
let last_superblock_signed_by_bootstrap = last_superblock_signed_by_bootstrap(&chain_info.consensus_constants);

let ars_members =
// Before reaching the epoch activity_period + collateral_age the bootstrap committee signs the superblock
// collateral_age is measured in blocks instead of epochs, but this only means that the period in which
// the bootstrap committee signs is at least epoch activity_period + collateral_age
if let Some(ars_members) = in_emergency_period(superblock_index, get_environment()) {
// Bootstrap committee
ars_members
} else if superblock_index >= last_superblock_signed_by_bootstrap {
// The base census is used during bootstrapping of the network and during emergency
// periods.
let base_census = if let Some(ars_members) = in_emergency_period(superblock_index, get_environment()) {
// Bootstrap committee
Some(ars_members)
} else if superblock_index < last_superblock_signed_by_bootstrap {
Some(chain_info
.consensus_constants
.bootstrapping_committee
.iter()
.map(|add| add.parse().expect("Malformed bootstrapping committee"))
.collect())
} else {
None
};

// Different protocol versions sample the superblock signing committees from census
// that are built off different chain data:
// - In V1_X protocols, the census was sourced from the ARS. Namely, it contains
// all identities with non-zero reputation, ordered by decreasing reputation.
// - In V2_x protocols, the census is instead sourced from the stakes tracker.
// Namely, it contains the two top quartiles of the most powerful validators,
// ordered by power.
// Exceptionally, if a base census has been constructed above, all of this logic is
// skipped, and the base census is used.
let census = Census::new(base_census.unwrap_or(
if ProtocolVersion::from_epoch(block_epoch) < ProtocolVersion::V2_0 {
reputation_engine.get_rep_ordered_ars_list()
} else {
chain_info
.consensus_constants
.bootstrapping_committee
.iter()
.map(|add| add.parse().expect("Malformed bootstrapping committee"))
.collect()
};
let all_validators = act.chain_state.stakes.by_rank(Capability::Mining, block_epoch);
let half_count = act.chain_state.stakes.validators_count() / 2;
let top_validators = all_validators.map(|(StakeKey { validator, .. }, _)| validator).take(half_count).collect();

// Get the list of members of the ARS with reputation greater than 0
// the list itself is ordered by decreasing reputation
let ars_identities = Census::new(ars_members);
top_validators
}));

// After the second hard fork, the superblock committee size must be at least 50
let min_committee_size = if after_second_hard_fork(block_epoch, get_environment()) {
Expand All @@ -2066,7 +2080,7 @@ impl ChainManager {

let superblock = act.chain_state.superblock_state.build_superblock(
&block_headers,
ars_identities,
census,
committee_size,
superblock_index,
last_hash,
Expand Down

0 comments on commit 0ebb227

Please sign in to comment.