Crate pathfinder_consensus

Crate pathfinder_consensus 

Source
Expand description

§Pathfinder Consensus

A Byzantine Fault Tolerant (BFT) consensus engine for Starknet nodes.

§Overview

This crate provides a consensus engine for Starknet nodes that wraps the Malachite implementation of the Tendermint BFT consensus algorithm. It’s designed to be generic over validator addresses and consensus values, making it suitable for Starknet’s consensus requirements.

§Core Concepts

§ValidatorAddress Trait

Your validator address type must implement the ValidatorAddress trait, which requires:

  • Sync + Send: Thread-safe and sendable across threads
  • Ord + Display + Debug + Default + Clone: Standard Rust traits for ordering, display, debugging, default values, and cloning
  • Into<Vec<u8>>: Convertible to bytes for serialization
  • Serialize + DeserializeOwned: Serde serialization support

§ValuePayload Trait

Your consensus value type must implement the ValuePayload trait, which requires:

  • Sync + Send: Thread-safe and sendable across threads
  • Ord + Display + Debug + Default + Clone: Standard Rust traits
  • Serialize + DeserializeOwned: Serde serialization support

§Consensus Engine

The main Consensus<V, A> struct is generic over:

  • V: Your consensus value type (must implement ValuePayload)
  • A: Your validator address type (must implement ValidatorAddress)

§Usage Example

use pathfinder_consensus::*;
use serde::{Deserialize, Serialize};

// Define your validator address type
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
struct MyAddress(String);

impl std::fmt::Display for MyAddress {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}", self.0)
    }
}

impl From<MyAddress> for Vec<u8> {
    fn from(addr: MyAddress) -> Self {
        addr.0.into_bytes()
    }
}

// Define your consensus value type
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
struct BlockData(String);

impl std::fmt::Display for BlockData {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}", self.0)
    }
}

// Custom proposer selector that uses weighted selection
#[derive(Clone)]
struct WeightedProposerSelector;

impl ProposerSelector<MyAddress> for WeightedProposerSelector {
    fn select_proposer<'a>(
        &self,
        validator_set: &'a ValidatorSet<MyAddress>,
        _height: u64,
        round: u32,
    ) -> &'a Validator<MyAddress> {
        // Simple weighted selection based on voting power
        let total_power: u64 = validator_set
            .validators
            .iter()
            .map(|v| v.voting_power)
            .sum();
        let selection = (round as u64) % total_power;

        let mut cumulative = 0;
        for validator in &validator_set.validators {
            cumulative += validator.voting_power;
            if selection < cumulative {
                return validator;
            }
        }

        // Fallback to first validator
        &validator_set.validators[0]
    }
}

#[tokio::main]
async fn main() {
    // Create configuration
    let my_address = MyAddress("validator_1".to_string());
    let config = Config::new(my_address.clone());

    // Create consensus engine with custom proposer selector
    let proposer_selector = WeightedProposerSelector;
    let mut consensus = Consensus::new(config).with_proposer_selector(proposer_selector);

    // Or use the default round-robin selector (no additional configuration needed)
    // let mut consensus = Consensus::new(config);

    // Start consensus at height 1
    let validator_set = ValidatorSet::new(vec![Validator::new(
        my_address.clone(),
        PublicKey::from_bytes([0; 32]),
    )
    .with_voting_power(10)]);

    consensus.handle_command(ConsensusCommand::StartHeight(1, validator_set));

    // Poll for events
    while let Some(event) = consensus.next_event().await {
        match event {
            ConsensusEvent::RequestProposal { height, round } => {
                println!("Need to propose at height {}, round {}", height, round);
            }
            ConsensusEvent::Decision { height, value } => {
                println!("Consensus reached at height {}: {:?}", height, value);
            }
            ConsensusEvent::Gossip(message) => {
                println!("Need to gossip: {:?}", message);
            }
            ConsensusEvent::Error(error) => {
                eprintln!("Consensus error: {}", error);
            }
        }
    }
}

§Commands and Events

The consensus engine operates on a command/event model:

  • Commands: Send commands to the consensus engine via handle_command()
  • Events: Poll for events from the consensus engine via next_event().await

§Crash Recovery

The consensus engine supports crash recovery through write-ahead logging:

// Recover from a previous crash
let validator_sets = Arc::new(StaticValidatorSetProvider::new(validator_set));
let mut consensus = Consensus::recover(config, validator_sets);

Structs§

Config
The configuration for the consensus engine.
Consensus
Pathfinder consensus engine
Proposal
A proposal for a block value in a consensus round.
Round
A round number (or None if the round is nil).
RoundRobinProposerSelector
A default proposer selector that uses round-robin selection.
SignedProposal
A fully validated, signed proposal ready to enter consensus.
SignedVote
A signed vote.
StaticValidatorSetProvider
A validator set provider that always returns the same validator set.
TimeoutValues
The timeout values for the consensus engine.
Validator
A validator in the consensus protocol.
ValidatorSet
A validator set represents a group of consensus participants.
Vote
A vote for a value in a consensus round.

Enums§

ConsensusCommand
Commands that the application can send into the consensus engine.
ConsensusEvent
Events that the consensus engine emits for the application to handle.
NetworkMessage
A message to be gossiped to peers.
VoteType
The type of vote.

Traits§

ProposerSelector
A trait for selecting the proposer for a given height and round.
ValidatorAddress
A trait for consensus validator addresses.
ValidatorSetProvider
A trait for retrieving the validator set at a specific blockchain height.
ValuePayload
A trait for consensus value payloads.

Type Aliases§

DefaultConsensus
A type alias for consensus with the default round-robin proposer selector.
PublicKey
A public key for the consensus protocol.
Signature
A cryptographic signature for consensus messages.
SigningKey
An Ed25519 signing key.
VotingPower
A validator’s voting power.