Skip to content

Conversation

@s-h-ubham
Copy link
Contributor

Title: Fix Quorum Calculation Logic in HasQuorum Function


Summary

This PR fixes a consensus bug in the HasQuorum function where quorum calculation incorrectly depended on the number of signers instead of the validator set size. The faulty logic required 100% voting power whenever there were fewer than 4 signers, which caused unnecessary stalls in valid scenarios.


Background

The core IBFT library (consensus/ibft/validators.go) defines quorum based on validator set size (set.Len()), not the number of block signers. It provides two quorum calculation methods:

  • LegacyQuorumSize: 2F + 1 formula (where F = max faulty nodes)
  • OptimalQuorumSize: ceil(2/3 * N) formula

The buggy implementation in our code deviated from this by introducing a special case:

if valsCount < 4 {
    quorumSize = vs.totalVotingPower // ❌ Required 100% voting power
} else {
    quorumSize = getQuorumSize(...)
}

This caused valid blocks with sufficient voting power (e.g., 3 high-VP signers with 80% VP) to fail quorum checks when valsCount < 4.


Changes Implemented

  • Removed special case logic that enforced 100% voting power when signers < 4
  • Always use getQuorumSize(blockNumber, totalVotingPower) for quorum calculation
  • Ensured logic is now consistent with core IBFT consensus implementation
  • Simplified HasQuorum for better maintainability

Before (Buggy)

var quorumSize *big.Int
if valsCount < 4 {  
    quorumSize = vs.totalVotingPower  
} else {
    quorumSize = getQuorumSize(blockNumber, vs.totalVotingPower)  
}

After (Fixed)

quorumSize := getQuorumSize(blockNumber, vs.totalVotingPower)

Benefits

  • Bug Fix: Correctly passes quorum when sufficient voting power exists, even with fewer than 4 signers
  • Consistency: Matches core IBFT library’s quorum rules
  • Reliability: Prevents unnecessary chain stalls in larger validator sets
  • Simplicity: Removes redundant logic and reduces risk of future bugs

Testing

  • ✅ All unit tests pass (TestValidatorSet_HasQuorum verified)
  • ✅ Code compiles without errors
  • ✅ Manual testing confirms correct quorum behavior in edge cases

Impact

⚠️ Consensus Change — all validators must upgrade to avoid chain divergence.


@s-h-ubham s-h-ubham requested a review from R-Santev August 13, 2025 06:29
R-Santev and others added 5 commits September 18, 2025 12:55
* feat: improved bootnodes discovery by decoupling from genesis file

* fix: build issue ci/cd

* chore: refactor config format from YAML to JSON and renamed GenesisPath to GenesisFile in server configuration

* chore: consolidate bootnode config into network config and remove redundancies

* chore: skip self-connection in bootnodes setup to prevent self-dial and improve peer management

* chore: combined the default bootnodes and additional bootnodes in single file

* WIP: Implement peer persistence logic

* chore: add peer persistence and fallback to last_peers.json as bootnodes

* chore: runtime fallback to last known peers after all bootnode connection attempts fail

* fix failing tests and remove minimum bootnodes requirement

* Fix lint errors

* fix a minor issue

* turn of lint warning

* Updated testnet bootnodes

* Update genesis-testnet.json

---------

Co-authored-by: s-h-ubham <shubham.gupta@antiersolutions.com>
Co-authored-by: s-h-ubham <98087338+s-h-ubham@users.noreply.github.com>
* chore: Improve peer persistence and bootnode loading

* chore: fixed test cases errors
#130)

* chore: Resolves bootnode loading issues when bootnodes are defined at genesis root level instead of under params.bootnodes.

* chore: automatically generate a bootnode.json on first run when connecting
Updated bootnodes list with new IP addresses.
@s-h-ubham s-h-ubham merged commit 9167f0b into prod Oct 29, 2025
6 of 7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants