mod.rs
Overview
This file implements the core logic for the ChainPulse component, which orchestrates the periodic processing and evaluation of blockchain state updates related to block attestations and candidate blocks within a specific thread of a blockchain network. The ChainPulse structure encapsulates two main submodules: pulse_attestations and pulse_candidates, which handle attestation management and candidate block processing, respectively.
The file defines configuration settings via the ChainPulseSettings builder, allowing for fine-grained control over timing, retries, and block gap parameters crucial for consensus and block finalization workflows.
Detailed Explanation of Components
ChainPulseSettings Struct
A typed builder struct that configures parameters required to instantiate a ChainPulse object. This struct includes:
node_id (
NodeIdentifier): Unique identifier for the node running this pulse.thread_identifier (
ThreadIdentifier): Identifier for the blockchain thread this pulse operates on.direct_send_tx (
NetDirectSender<NodeIdentifier, NetworkMessage>): Channel sender for direct network messages.broadcast_send_tx (NetBroadcastSender): Channel sender for broadcast network messages.
trigger_attestation_resend_by_time (
Option<Duration>): Optional duration to trigger attestation resending based on elapsed time.trigger_attestation_resend_by_chain_length (
Option<usize>): Optional chain length threshold to trigger attestation resending.retry_request_missing_block_timeout (
Duration): Timeout for retrying requests for missing blocks.resend_timeout_blocks_stuck (
Duration): Timeout to detect and resend stuck blocks.resend_timeout_blocks_stuck_extra_offset_per_candidate (
Duration): Additional resend offset applied per candidate block.missing_blocks_were_requested (
Arc<AtomicBool>): Shared atomic flag indicating if missing blocks have been requested.trigger_increase_block_gap (
Option<Duration>): Optional duration to trigger increase of block gap.finalization_stopped_time_trigger (
Duration): Time trigger to detect if finalization has stopped.finalization_has_not_started_time_trigger (
Duration): Time trigger to detect if finalization has not started.block_gap (
BlockGap): Configuration related to block gap management.last_finalized_block (
Option<BlockState>): Optionally holds the last finalized block state at initialization.
Usage Example
let chain_pulse = ChainPulse::builder()
.node_id(my_node_id)
.thread_identifier(my_thread_id)
.direct_send_tx(my_direct_sender)
.broadcast_send_tx(my_broadcast_sender)
.retry_request_missing_block_timeout(Duration::from_secs(30))
.resend_timeout_blocks_stuck(Duration::from_secs(60))
.resend_timeout_blocks_stuck_extra_offset_per_candidate(Duration::from_secs(10))
.missing_blocks_were_requested(Arc::new(AtomicBool::new(false)))
.finalization_stopped_time_trigger(Duration::from_secs(120))
.finalization_has_not_started_time_trigger(Duration::from_secs(300))
.block_gap(my_block_gap)
.build();
ChainPulse Struct
The main struct managing the chain pulse process. It contains:
attestations (
pulse_attestations::PulseAttestations): Manages attestation-related logic including resending and time-based triggers.candidates (
pulse_candidates::PulseCandidateBlocks): Manages candidate block selection, broadcasting, and resend logic.last_finalized_block (
Option<BlockState>): Tracks the last finalized block to detect and act on new finalization events.
impl From<ChainPulseSettings> for ChainPulse
This conversion consumes ChainPulseSettings and initializes the attestations and candidates submodules accordingly by passing relevant configuration parameters.
impl ChainPulse
fn builder() -> ChainPulseBuilder
Returns a builder instance (ChainPulseSettings::builder()) for constructing a ChainPulse object with custom settings.
fn pulse(&mut self, last_finalized_block: &BlockState) -> anyhow::Result<()>
Triggers a pulse operation based on the new finalized block. The method performs:
Validation that the new finalized block sequence number (
block_seq_no) is strictly greater than the previously stored finalized block.Calls
pulse()on bothattestationsandcandidatessubmodules:attestations.pulse(last_finalized_block)processes attestation-related updates.candidates.pulse(next_seq_no)processes candidate block updates based on the next expected sequence number.
Updates the stored
last_finalized_block.
Parameters:
last_finalized_block: Reference to the current finalized block state.
Returns:
Ok(())if pulse operations succeed.Errif validation or submodule pulses fail.
Usage Example:
chain_pulse.pulse(&new_finalized_block)?;
fn evaluate(&mut self, candidates: &UnfinalizedBlocksSnapshot, block_state_repository: &BlockStateRepository, block_repository: &RepositoryImpl) -> anyhow::Result<()>
Evaluates the current state of unfinalized blocks and updates pulse submodules accordingly:
Calls
evaluate()on bothattestationsandcandidatespassing appropriate repositories and metrics.Ensures both evaluations have a chance to run even if one fails, returning an error if any evaluation fails.
Parameters:
candidates: Snapshot of unfinalized blocks to be evaluated.block_state_repository: Repository for block state queries.block_repository: Repository implementation for block data and metrics.
Returns:
Ok(())if evaluation succeeds.Errif any evaluation fails.
Usage Example:
chain_pulse.evaluate(&unfinalized_snapshot, &block_state_repo, &block_repo)?;
Implementation Details and Algorithms
The file uses a builder pattern (
TypedBuilder) for ergonomic and safe construction of theChainPulseconfiguration.Atomic synchronization (
Arc<AtomicBool>) is used to track whether missing blocks have been requested, enabling thread-safe shared state across asynchronous tasks or threads.The pulse mechanism ensures monotonic progression by enforcing the finalized block's sequence number to increase strictly, preventing regressions or duplicates.
Resending logic and triggers in submodules (
pulse_attestationsandpulse_candidates) are based on timers and chain state changes, such as elapsed time, chain length, or finalization status.Evaluation integrates metrics from
block_repositoryto inform decisions about candidate blocks and attestation validity.
Interaction with Other System Components
Network Channels: Utilizes
NetDirectSenderandNetBroadcastSenderfor network communication, sending direct and broadcast messages respectively.Node Identification: Uses
NodeIdentifierandThreadIdentifierto scope operations within specific node and thread contexts.Repositories: Interacts with
BlockStateRepositoryandRepositoryImplto query and manipulate blockchain state and metrics.Pulse Submodules: Delegates detailed logic to
pulse_attestationsandpulse_candidatesmodules, which encapsulate specialized workflows.Unfinalized Blocks Snapshot: Consumes snapshots of unfinalized blocks (
UnfinalizedBlocksSnapshot) to evaluate ongoing candidate blocks.Block States: Maintains and compares
BlockStateobjects to track finalization progress.
Mermaid Diagram
classDiagram
class ChainPulseSettings {
- node_id: NodeIdentifier
- thread_identifier: ThreadIdentifier
- direct_send_tx: NetDirectSender
- broadcast_send_tx: NetBroadcastSender
- trigger_attestation_resend_by_time: Option<Duration>
- trigger_attestation_resend_by_chain_length: Option<usize>
- retry_request_missing_block_timeout: Duration
- resend_timeout_blocks_stuck: Duration
- resend_timeout_blocks_stuck_extra_offset_per_candidate: Duration
- missing_blocks_were_requested: Arc<AtomicBool>
- trigger_increase_block_gap: Option<Duration>
- finalization_stopped_time_trigger: Duration
- finalization_has_not_started_time_trigger: Duration
- block_gap: BlockGap
- last_finalized_block: Option<BlockState>
+ build()
}
class ChainPulse {
- attestations: PulseAttestations
- candidates: PulseCandidateBlocks
- last_finalized_block: Option<BlockState>
+ builder()
+ pulse()
+ evaluate()
}
ChainPulseSettings --> ChainPulse : from(settings)
ChainPulse *-- PulseAttestations : contains
ChainPulse *-- PulseCandidateBlocks : contains
This diagram illustrates the primary data structures, their key fields, and the relationships between ChainPulseSettings, ChainPulse, and its submodules. The builder pattern constructs ChainPulse from ChainPulseSettings, while ChainPulse composes PulseAttestations and PulseCandidateBlocks components.