Pathfinder Consensus
A Byzantine Fault Tolerant (BFT) consensus engine for Starknet nodes, built on top of the Malachite consensus engine.

Overview
Pathfinder Consensus provides a robust 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.
Quick Start
use pathfinder_consensus::*;
use serde::{Deserialize, Serialize};
#[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()
}
}
#[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)
}
}
#[tokio::main]
async fn main() {
let my_address = MyAddress("validator_1".to_string());
let config = Config::new(my_address.clone());
let mut consensus = Consensus::new(config);
let validator_set = ValidatorSet::new(vec![
Validator::new(my_address.clone(), PublicKey::from_bytes([0; 32]))
]);
consensus.handle_command(ConsensusCommand::StartHeight(1, validator_set));
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);
}
}
}
}
Core Concepts
ValidatorAddress Trait
Your validator address type must implement the ValidatorAddress trait:
pub trait ValidatorAddress:
Sync + Send + Ord + Display + Debug + Default + Clone + Into<Vec<u8>> + Serialize + DeserializeOwned
{
}
ValuePayload Trait
Your consensus value type must implement the ValuePayload trait:
pub trait ValuePayload:
Sync + Send + Ord + Display + Debug + Default + Clone + Serialize + DeserializeOwned
{
}
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)
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
Configuration
The Config struct allows you to customize:
- History Depth: How many completed heights to keep in memory
- WAL Directory: Where to store write-ahead logs for crash recovery
- Timeouts: Customize consensus round timeouts
Crash Recovery
The consensus engine supports crash recovery through write-ahead logging:
let validator_sets = Arc::new(StaticValidatorSetProvider::new(validator_set));
let mut consensus = Consensus::recover(config, validator_sets);