BFT consensus
Overview
This component requires explicit caller integration. Running multiple API nodes or setting BFT_ENABLED does not connect PBFT to MainChain/Sub-Chain automatically.
The exported BFT library component and its standalone demo use 3-phase PBFT. It needs n >= 3f + 1 nodes to tolerate f faulty or malicious nodes. The current MainChain and SubChain runtime paths do not instantiate BFT; callers use BFTConsensus.request() explicitly.
For PoA and PoF flows, see Consensus Mechanisms.
You need at least 4 nodes to tolerate 1 Byzantine failure (n=4, f=1: 3×1+1=4).
Flow diagram: 3-phase PBFT
sequenceDiagram
autonumber
participant C as Client
participant L as Primary
participant R1 as Replica 1
participant R2 as Replica 2
participant R3 as Replica 3
rect rgb(0, 0, 0, 0)
Note over L,R3: PHASE 1 — PRE-PREPARE
C->>L: request(operation)
L->>L: Hash full canonical request and record local PREPARE
L->>R1: PRE-PREPARE(view, seq, digest, request)
L->>R2: PRE-PREPARE(view, seq, digest, request)
L->>R3: PRE-PREPARE(view, seq, digest, request)
end
rect rgb(0, 0, 0, 0)
Note over L,R3: PHASE 2 — PREPARE
R1->>R1: Recompute digest and record local PREPARE
R2->>R2: Recompute digest and record local PREPARE
R3->>R3: Recompute digest and record local PREPARE
R1->>L: PREPARE(view, seq, digest)
R2->>L: PREPARE(view, seq, digest)
R3->>L: PREPARE(view, seq, digest)
Note over L,R3: Each node records its local COMMIT after 2f unique PREPARE votes
end
rect rgb(0, 0, 0, 0)
Note over L,R3: PHASE 3 — COMMIT
L->>R1: COMMIT(view, seq, digest)
R1->>L: COMMIT(view, seq, digest)
R2->>L: COMMIT(view, seq, digest)
Note over L,R3: Apply after 2f+1 unique COMMIT votes, including the local vote
R1->>R1: Apply event to the attached chain
end
The primary and replicas count their own signed phase vote once. A PRE-PREPARE is rejected if its request body does not match the signed digest. If an attached chain write raises an error or returns False, the node keeps the quorum messages and the same event in memory; a repeated valid COMMIT can retry the write. It marks the sequence committed only after the write succeeds.
Without an attached application chain, the component runs in protocol-only mode and records consensus status without writing an event, as in the standalone demo.
Request admission is earlier than commitment. Retry state remains in memory and does not guarantee exactly-once application after ambiguous writes or restarts. See BFT component for transport, configuration, replay and ZK limitations.
Flow diagram: view change (leader failure)
sequenceDiagram
autonumber
participant ledger as 🖥️ Validator 1
participant VM as 🔄 BFTViewChangeManager
participant NEW as 👑 New Leader
Note over ledger: Leader timeout detected (no PRE-PREPARE received)
ledger->>VM: initiate_view_change(new_view)
VM->>VM: Broadcast VIEW-CHANGE to all validators
VM->>VM: Collect and validate 2f+1 VIEW-CHANGE votes
VM->>NEW: Elect new leader: Validators[new_view % n]
NEW->>NEW: Broadcast NEW-VIEW message
NEW->>NEW: Activate the new view
Step-by-step breakdown
| Step | Description |
|---|---|
| PRE-PREPARE | Primary assigns a sequence number, hashes the complete canonical request, signs the digest, and broadcasts the request |
| PREPARE | Each node recomputes the digest and records its own PREPARE once. Each node moves to COMMIT after 2f unique PREPARE votes, including its own |
| COMMIT | Each prepared node records and broadcasts its own COMMIT once. A node applies the event after 2f + 1 unique COMMIT votes, including its own |
| View Change | If the leader is silent past the timeout, the manager collects 2f + 1 signed VIEW-CHANGE votes before accepting the new view |
Consensus comparison
| Algorithm | Mechanism | Fault Tolerance | Use Case |
|---|---|---|---|
| PoA | Identity-based, authority signs | Validator reputation | Private / internal networks |
| PoF | Rotating leader height % n; ordinary validation checks its signature |
Distributed trust | Consortium / multi-org |
| BFT | 3-phase PBFT library component | Up to f Byzantine nodes in 3f+1 |
Explicit callers and the standalone demo |
Error handling
| Condition | Behavior |
|---|---|
| Leader timeout | View Change triggered; the new primary is all_nodes[new_view % n] |
| Validator sends invalid digest | Vote discarded, not counted toward quorum |
| Reachable signed COMMIT quorum | Application requires 2f + 1 distinct votes for the same request |
| Too few COMMIT votes | The request remains unapplied until enough valid votes arrive |
| Attached chain write fails | Keep the current commit quorum and retry the same event when a valid COMMIT is repeated |
Key classes and methods
| Step | Class / Method | File |
|---|---|---|
| Request and PRE-PREPARE | BFTConsensus.request() |
consensus/bft/consensus.py |
| PRE-PREPARE validation and local PREPARE | BFTConsensusEngine.handle_pre_prepare() |
consensus/bft/engine.py |
| PREPARE quorum and local COMMIT | BFTConsensusEngine.handle_prepare() |
consensus/bft/engine.py |
| COMMIT quorum and event apply | BFTConsensusEngine.process_commit_quorum() |
consensus/bft/engine.py |
| View Change | BFTViewChangeManager.initiate_view_change() |
consensus/bft/view_change.py |
| Transport | BFTMessageDispatcher.broadcast_msg() |
consensus/bft/dispatcher.py |
Related
- Consensus Mechanisms: PoA and PoF details
- Event Submission: MainChain and SubChain submission flow
- Error Mitigation: handles leader failure recovery at system level