bp_selector.rs
Overview
This file defines the ProducerSelector struct and related functionality for selecting a block producer (BP) node from a set of block keepers (BlockKeeperSet). The selection is deterministic and based on a seed derived from a block identifier, ensuring a reproducible shuffled order of block keeper nodes. The main purpose of ProducerSelector is to identify which node is the current producer and to calculate relative positions of nodes within the shuffled order, supporting consensus or leader election mechanisms.
Types and Imports
BlockGap is an alias for a thread-safe atomic counter wrapped in an Arc, used elsewhere in the system but not directly in this file.
The file uses dependencies for randomization (
rand), serialization (serde), and utility macros (derive_getters,TypedBuilder).It relies on external types:
BlockKeeperSet,NodeIdentifier, andBlockIdentifierfrom other modules in the system, which represent:BlockKeeperSet: the collection of nodes eligible to produce blocks.NodeIdentifier: a unique identifier for a node.BlockIdentifier: an identifier for a block, able to generate a seed for randomization.
ProducerSelector Struct
pub struct ProducerSelector {
rng_seed_block_id: BlockIdentifier,
index: usize,
}
Fields
rng_seed_block_id: TheBlockIdentifierused to seed the random number generator for shuffling the block keeper nodes.index: The offset index into the shuffled list of block keeper nodes representing the current block producer.
Derives and Traits
Clone,Debug,Serialize,Deserialize,Eq,PartialEqTypedBuilderfor builder-pattern instantiation.Gettersto generate getter methods for fields.
Implementation Details and Methods
get_producer_node_id
pub fn get_producer_node_id(&self, bk_set: &BlockKeeperSet) -> anyhow::Result<NodeIdentifier>
Purpose: Returns the node ID of the block producer at the current
indexwithin the shuffledBlockKeeperSet.Parameters:
bk_set: Reference to the currentBlockKeeperSet.
Returns: Result wrapping the
NodeIdentifierof the selected block producer or an error ifindexis out of bounds.Process:
Collects and clones node IDs from
bk_set.Uses the
rng_seed_block_idto seed a small RNG.Shuffles the node list deterministically.
Selects the node at
index.
Example:
let producer_selector = ProducerSelector { rng_seed_block_id: some_block_id, index: 2 };
let producer_node = producer_selector.get_producer_node_id(&bk_set)?;
println!("Current producer node is {:?}", producer_node);
is_node_bp
pub fn is_node_bp(&self, bk_set: &BlockKeeperSet, node_id: &NodeIdentifier) -> anyhow::Result<bool>
Purpose: Checks if a given node is the current block producer.
Parameters:
bk_set: Reference to theBlockKeeperSet.node_id: The node to verify.
Returns:
Ok(true)if the node is the producer, otherwiseOk(false). Propagates errors fromget_producer_node_id.Usage: Useful for nodes to check their producer status.
check_whether_this_node_is_bp_based_on_bk_set_and_index_offset
pub fn check_whether_this_node_is_bp_based_on_bk_set_and_index_offset(
&self,
bk_set: &BlockKeeperSet,
node_id: &NodeIdentifier,
offset: usize,
) -> bool
Purpose: Determines if a node is the BP at a given offset relative to the current producer index.
Parameters:
bk_set: TheBlockKeeperSet.node_id: The node to check.offset: The offset index to compare against.
Returns:
trueif the node's distance from the BP equals the offset modulo the size ofbk_set.Details: Uses
get_distance_from_bpinternally to find the node’s relative position.This method supports scenarios where nodes need to evaluate their position in a rotating producer schedule.
get_distance_from_bp
pub fn get_distance_from_bp(&self, bk_set: &BlockKeeperSet, node_id: &NodeIdentifier) -> Option<usize>
Purpose: Computes the distance of a given node's position from the current producer index in the shuffled list.
Parameters:
bk_set:BlockKeeperSetreference.node_id: Node identifier.
Returns:
Some(distance)if the node is in the set, otherwiseNone.Algorithm:
Collect and shuffle node IDs using the RNG seeded by
rng_seed_block_id.Locate the position of
node_id.Calculate distance considering wrap-around in the circular list.
Example:
if let Some(distance) = producer_selector.get_distance_from_bp(&bk_set, &my_node_id) {
println!("Distance from producer is {}", distance);
}
move_index
pub fn move_index(self, diff: usize, bk_set_size: usize) -> Self
Purpose: Creates a new
ProducerSelectorwith theindexmoved forward bydiffmodulo the size of the block keeper set.Parameters:
diff: The shift amount.bk_set_size: Size of theBlockKeeperSet.
Returns: New
ProducerSelectorwith updated index.Usage: Used to rotate the producer index, e.g., to move to the next producer in the schedule.
Interaction with Other Modules
Utilizes
BlockKeeperSetto get the collection of nodes eligible for block production.Uses
BlockIdentifierto seed the random number generator, ensuring deterministic shuffling.Works with
NodeIdentifierto identify specific nodes.The deterministic shuffling based on block IDs supports consensus or leader election logic elsewhere in the system.
Important Implementation Details
The shuffling uses
SmallRngseeded from the block ID's RNG seed, ensuring reproducible random order.The index is validated against the size of the block keeper set to prevent out-of-bounds errors.
Distance calculations consider wrap-around in the circular list of nodes.
The design allows rotation and querying of producer positions in a round-robin or randomized schedule.
Error handling is done using
anyhow::Resultfor robust error propagation.
Tests Summary
Verify the correctness of distance calculation for all nodes.
Check proper rotation of the producer index via
move_index.Confirm that node BP status checks behave correctly.
Validate behavior when the producer index is out of range after node removal.
Mermaid Diagram: Class Structure of ProducerSelector
classDiagram
class ProducerSelector {
-rng_seed_block_id: BlockIdentifier
-index: usize
+get_producer_node_id()
+is_node_bp()
+check_whether_this_node_is_bp_based_on_bk_set_and_index_offset()
+get_distance_from_bp()
+move_index()
}
This diagram illustrates the core data and methods encapsulated within the ProducerSelector class, showing its responsibilities for producer selection and position calculations.