Skip to content

Conversation

@gzliudan
Copy link
Collaborator

@gzliudan gzliudan commented Jan 7, 2026

Proposed changes

Ref:

Types of changes

What types of changes does your code introduce to XDC network?
Put an in the boxes that apply

  • Bugfix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation Update (if none of the other choices apply)
  • Regular KTLO or any of the maintaince work. e.g code style
  • CICD Improvement

Impacted Components

Which part of the codebase this PR will touch base on,

Put an in the boxes that apply

  • Consensus
  • Account
  • Network
  • Geth
  • Smart Contract
  • External components
  • Not sure (Please specify below)

Checklist

Put an in the boxes once you have confirmed below actions (or provide reasons on not doing so) that

  • This PR has sufficient test coverage (unit/integration test) OR I have provided reason in the PR description for not having test coverage
  • Provide an end-to-end test plan in the PR description on how to manually test it on the devnet/testnet.
  • Tested the backwards compatibility.
  • Tested with XDC nodes running this version co-exist with those running the previous version.
  • Relevant documentation has been updated as part of this PR
  • N/A

Copilot AI review requested due to automatic review settings January 7, 2026 00:21
@coderabbitai
Copy link

coderabbitai bot commented Jan 7, 2026

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes a V2 comparison issue in XDPoS configuration validation. The main fix removes the comparison of configIndex (which are internal keys for AllConfigs maps) that was causing false mismatches after upgrades. The changes also refactor the equality functions to provide better debugging through detailed log warnings for each field mismatch.

Key Changes:

  • Removed configIndex comparison from V2Equal function to fix upgrade compatibility issue
  • Added detailed logging for each field comparison to aid debugging
  • Refactored nil-checking logic in all three equality functions
  • Modified SwitchEpoch comparison to skip checks when either value is 0

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

params/config.go Outdated
return true
}
if a.SwitchEpoch != b.SwitchEpoch || !configNumEqual(a.SwitchBlock, b.SwitchBlock) || !slices.Equal(a.configIndex, b.configIndex) {
if a.SwitchEpoch != b.SwitchEpoch && a.SwitchEpoch != 0 && b.SwitchEpoch != 0 {
Copy link

Copilot AI Jan 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The SwitchEpoch comparison logic has a special case where if either SwitchEpoch is 0, the comparison is skipped. However, this creates an asymmetric equality check. For example, if a.SwitchEpoch=0 and b.SwitchEpoch=100, they would be considered equal, but if a.SwitchEpoch=100 and b.SwitchEpoch=200, they would not be equal. This breaks the reflexive property of equality and could lead to unexpected behavior.

Suggested change
if a.SwitchEpoch != b.SwitchEpoch && a.SwitchEpoch != 0 && b.SwitchEpoch != 0 {
if a.SwitchEpoch != b.SwitchEpoch {

Copilot uses AI. Check for mistakes.
Comment on lines 634 to 651
func V2ConfigEqual(a, b *V2Config) bool {
if a == nil || b == nil {
return a == b
if a != b {
log.Warn("[V2ConfigEqual] One of the configs is nil", "a", a, "b", b)
return false
}
return true
}
return a.MaxMasternodes == b.MaxMasternodes && a.SwitchRound == b.SwitchRound && a.CertThreshold == b.CertThreshold
if a.MaxMasternodes != b.MaxMasternodes {
log.Warn("[V2ConfigEqual] MaxMasternodes mismatch", "a.MaxMasternodes", a.MaxMasternodes, "b.MaxMasternodes", b.MaxMasternodes)
return false
}
if a.SwitchRound != b.SwitchRound {
log.Warn("[V2ConfigEqual] SwitchRound mismatch", "a.SwitchRound", a.SwitchRound, "b.SwitchRound", b.SwitchRound)
return false
}
if a.CertThreshold != b.CertThreshold {
log.Warn("[V2ConfigEqual] CertThreshold mismatch", "a.CertThreshold", a.CertThreshold, "b.CertThreshold", b.CertThreshold)
return false
}
return true
}
Copy link

Copilot AI Jan 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The V2ConfigEqual function is incomplete. It only compares MaxMasternodes, SwitchRound, and CertThreshold, but the V2Config struct has many more fields that should be compared including MaxProtectorNodes, MaxObverserNodes, MinePeriod, TimeoutSyncThreshold, TimeoutPeriod, MasternodeReward, ProtectorReward, ObserverReward, MinimumMinerBlockPerEpoch, LimitPenaltyEpoch, MinimumSigningTx, and ExpTimeoutConfig. This could lead to configurations being considered equal when they are actually different.

Copilot uses AI. Check for mistakes.
Comment on lines +623 to 625
// Only check configs in both of AllConfigs
for k1, cfg1 := range a.AllConfigs {
if cfg2, ok := b.AllConfigs[k1]; ok {
if !V2ConfigEqual(cfg1, cfg2) {
return false
}
}
Copy link

Copilot AI Jan 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The V2Equal function only checks configs that exist in both AllConfigs maps (intersection). This means if one config has additional entries that the other doesn't have, they will still be considered equal. This asymmetric comparison could lead to incorrect equality results. Consider whether configs should be considered equal if they have different sets of keys in AllConfigs.

Suggested change
// Only check configs in both of AllConfigs
for k1, cfg1 := range a.AllConfigs {
if cfg2, ok := b.AllConfigs[k1]; ok {
if !V2ConfigEqual(cfg1, cfg2) {
return false
}
}
// Ensure AllConfigs have the same number of entries
if len(a.AllConfigs) != len(b.AllConfigs) {
log.Warn("[V2Equal] AllConfigs length mismatch", "len(a.AllConfigs)", len(a.AllConfigs), "len(b.AllConfigs)", len(b.AllConfigs))
return false
}
// Ensure every config in a.AllConfigs exists in b.AllConfigs and is equal
for k1, cfg1 := range a.AllConfigs {
cfg2, ok := b.AllConfigs[k1]
if !ok {
log.Warn("[V2Equal] Missing config in b.AllConfigs", "key", k1)
return false
}
if !V2ConfigEqual(cfg1, cfg2) {
return false
}

Copilot uses AI. Check for mistakes.
@AnilChinchawale AnilChinchawale merged commit 0c9fc2b into XinFinOrg:dev-upgrade Jan 16, 2026
13 checks passed
@gzliudan gzliudan deleted the fix-v2-compare branch January 16, 2026 10:23
@gzliudan gzliudan mentioned this pull request Jan 16, 2026
19 tasks
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.

5 participants