Crates.io | pathfinder-consensus |
lib.rs | pathfinder-consensus |
version | 0.20.0 |
created_at | 2025-08-18 10:21:20.514366+00 |
updated_at | 2025-08-26 11:26:31.182366+00 |
description | Pathfinder Consensus |
homepage | |
repository | |
max_upload_size | |
id | 1800231 |
size | 190,974 |
A Byzantine Fault Tolerant (BFT) consensus engine for Starknet nodes, built on top of the Malachite consensus engine.
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.
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)
}
}
#[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
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]))
]);
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);
}
}
}
}
Your validator address type must implement the ValidatorAddress
trait:
pub trait ValidatorAddress:
Sync + Send + Ord + Display + Debug + Default + Clone + Into<Vec<u8>> + Serialize + DeserializeOwned
{
}
Your consensus value type must implement the ValuePayload
trait:
pub trait ValuePayload:
Sync + Send + Ord + Display + Debug + Default + Clone + Serialize + DeserializeOwned
{
}
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
)The consensus engine operates on a command/event model:
handle_command()
next_event().await
The Config
struct allows you to customize:
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);