Consensus
The consensus
policy sends the same request to multiple upstreams and returns the result only when enough of them agree. This ensures data consistency and detects misbehaving nodes.
Consensus can only be configured at network level since it requires multiple upstreams to compare results.
Configuration
projects:
- id: main
networks:
- architecture: evm
evm:
chainId: 42161
failsafe:
- matchMethod: "*" # Define different consensus thresholds for different methods
matchFinality: ["finalized", "unknown"] # Read more in Failsafe docs -> Finality states
consensus:
requiredParticipants: 4
agreementThreshold: 2
disputeBehavior: preferBlockHeadLeader
lowParticipantsBehavior: acceptMostCommonValidResult
punishMisbehavior:
disputeThreshold: 10
disputeWindow: 10m
sitOutPenalty: 30m
Participation options
requiredParticipants
Number of upstreams to query in each consensus round. The policy selects the first N healthy upstreams based on their scores.
agreementThreshold
Minimum number of identical responses needed to reach consensus. For example, with requiredParticipants: 3
and agreementThreshold: 2
, at least 2 upstreams must return the same result.
Response comparison is done using canonical JSON-RPC response hashing, which normalizes responses before comparison.
Behavior options
disputeBehavior
Determines what to do when upstreams disagree (consensus not reached):
-
returnError
: Returns a consensus dispute error to the client. Use this for critical operations where inconsistency is unacceptable. -
acceptMostCommonValidResult
: Returns the most common valid response among all participants, even if it doesn't meet the threshold. Good for operations where some inconsistency is tolerable. -
preferBlockHeadLeader
: Returns the response from the upstream with the highest block number, falling back to most common if no block info is available. Ideal for recent data queries where the most up-to-date node is preferred. -
onlyBlockHeadLeader
: Only returns the response from the highest block upstream, errors if unavailable. Use when you strictly need the latest chain state.
lowParticipantsBehavior
Handles cases when fewer than requiredParticipants
healthy upstreams are available:
-
returnError
: Fails the request when not enough upstreams are healthy. -
acceptMostCommonValidResult
: Proceeds with any available upstreams and returns the most common result. -
preferBlockHeadLeader
: Uses the highest block upstream if available, otherwise returns the most common valid result, ensuring requests succeed during partial outages. -
onlyBlockHeadLeader
: Only proceeds if the block head leader is among healthy upstreams, and use the block head leader's response.
Block Head Leader: The upstream reporting the highest block number. This is determined by each upstream's state poller and ensures you're getting data from the most synchronized node.
Misbehavior tracking
punishMisbehavior
Temporarily removes upstreams that consistently disagree with the consensus:
disputeThreshold
: Number of disputes before punishment (e.g., 3 strikes)disputeWindow
: Time window for counting disputes (e.g., 10m)sitOutPenalty
: How long the upstream is cordoned (e.g., 30m)
Chain reorganizations
During reorgs, nodes may temporarily disagree on recent blocks. Using preferBlockHeadLeader
helps resolve disputes by using the response from most up-to-date upstream.
Performance
Consensus increases costs and latency since it waits for multiple responses. Use it selectively for critical workloads and specific methods rather than all requests.