Skip to content

core/forkid: include polygon-specific forks in wire forkid#2237

Merged
kamuikatsurgi merged 2 commits into
developfrom
leo/forkid-fix
May 26, 2026
Merged

core/forkid: include polygon-specific forks in wire forkid#2237
kamuikatsurgi merged 2 commits into
developfrom
leo/forkid-fix

Conversation

@leovct
Copy link
Copy Markdown
Member

@leovct leovct commented May 21, 2026

NewID computes the eth p2p handshake forkid by calling gatherForks (lowercase), which uses reflection over the outer ChainConfig struct and is blind to the polygon-specific block fields nested under config.Bor (RioBlock, MadhugiriBlock, DandeliBlock, LisovoBlock, LisovoProBlock, GiuglianoBlock, ChicagoBlock). The polygon-aware GatherForks (uppercase) was added in #2063 to expose fork data via the new bor_forks RPC, but the wire path was never updated to use it.

As a result, bor's wire forkid does not include any polygon-specific fork activation in its checksum. On chains where polygon forks activate at non-zero blocks (devnets, testnets, mainnet post-fork), bor's wire forkid is inconsistent with what the bor_forks RPC reports for the same node.

This was latent until erigon v3.6.0 started including the new polygon forks (see p2p/forkid/forkid.go), Lisovo, LisovoPro, Giugliano and Chicago in its own GatherForks. erigon's wire forkid now correctly hashes those blocks while bor's still does not, causing the eth handshake to fail with fork ID rejected: local incompatible or needs update on any deployment combining bor v2.8.0 with erigon v3.6.0 on a chain where those forks activate above block 0.

Written by claude

NewID computes the eth p2p handshake forkid by calling gatherForks
(lowercase), which uses reflection over the outer ChainConfig struct
and is blind to the polygon-specific block fields nested under
config.Bor (RioBlock, MadhugiriBlock, DandeliBlock, LisovoBlock,
LisovoProBlock, GiuglianoBlock, ChicagoBlock). The polygon-aware
GatherForks (uppercase) was added in #2063 to expose fork data via
the new bor_forks RPC, but the wire path was never updated to use it.

As a result, bor's wire forkid does not include any polygon-specific
fork activation in its checksum. On chains where polygon forks
activate at non-zero blocks (devnets, testnets, mainnet post-fork),
bor's wire forkid is inconsistent with what the bor_forks RPC reports
for the same node.

This was latent until erigon v3.6.0 started including the new
polygon forks (Lisovo, LisovoPro, Giugliano, Chicago) in its own
GatherForks. erigon's wire forkid now correctly hashes those blocks
while bor's still does not, causing the eth handshake to fail with
'fork ID rejected: local incompatible or needs update' on any
deployment combining bor v2.8.0 with erigon v3.6.0 on a chain where
those forks activate above block 0.

Switch NewID to call GatherForks so the wire forkid includes the
polygon-specific forks and matches what bor_forks RPC reports.
Copilot AI review requested due to automatic review settings May 21, 2026 13:50
Copy link
Copy Markdown

@claude claude Bot left a comment

Choose a reason for hiding this comment

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

Claude Code Review

This repository is configured for manual code reviews. Comment @claude review to trigger a review and subscribe this PR to future pushes, or @claude review once for a one-time review.

Tip: disable this comment in your organization's Code Review settings.

Copy link
Copy Markdown
Contributor

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 updates the EIP-2124 wire forkid computation so that Bor’s p2p handshake fork checksum includes Polygon/Bor-specific fork activation blocks (matching what bor_forks reports), preventing handshake incompatibilities with clients that already include those forks (e.g., newer Erigon).

Changes:

  • Switch core/forkid.NewID to use the Polygon-aware GatherForks (instead of the reflection-based gatherForks) when computing the wire forkid.

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

Comment thread core/forkid/forkid.go
@claude
Copy link
Copy Markdown

claude Bot commented May 21, 2026

Code Review

Bug: newFilter still calls gatherForks (lowercase) — wire handshake will break

Severity: Critical — P2P connectivity failure on all Polygon networks

NewID (line 81) was correctly updated to call GatherForks (Polygon-aware), but newFilter at line 142 still calls gatherForks (Ethereum-only). newFilter is used by NewFilter and NewStaticFilter, which validate remote peer fork IDs during the ETH/68 and ETH/69 P2P handshakes and peer discovery.

After this PR, a node will advertise a fork ID that includes Polygon forks (via NewID calling GatherForks), but its validation filter will compute checksums without those forks (via newFilter calling gatherForks). The CRC32 checksum sequences will diverge at the first passed Polygon-specific fork, causing the filter to return ErrLocalIncompatibleOrStale. Two upgraded Bor nodes would fail to handshake with each other — a complete P2P connectivity failure on any Polygon network where at least one Bor-specific fork has activated.

Fix: Line 142 should also be updated:

- forksByBlock, forksByTime = gatherForks(config, genesis.Time())
+ forksByBlock, forksByTime = GatherForks(config, genesis.Time())

kamuikatsurgi
kamuikatsurgi previously approved these changes May 21, 2026
newFilter (used by NewFilter / NewStaticFilter) builds the local table
of valid fork checksums that the inbound eth handshake validator
matches incoming peers against. It was calling lowercase gatherForks,
which is the same polygon-blind reflection-only path the previous
commit fixed in NewID.

Without this, a patched bor (with the fixed NewID) would emit a forkid
that includes the polygon-specific forks, but its own inbound filter
would compute the local sums[] table without them. Incoming peer
forkids would never match the table by exact rule #1 of EIP-2124 and
would only be accepted via the rule #3 "remote is a superset"
forgiveness path. The validator's accept/reject behaviour would be
correct by accident rather than by design, and any nuance that depends
on rule #1 (matching local fork state) would be wrong.

Switch newFilter to GatherForks so the validator's sums[] table is
symmetric with what NewID emits. After this, the eth handshake's
forkid check is end-to-end polygon-aware on bor.
@sonarqubecloud
Copy link
Copy Markdown

@leovct leovct requested a review from kamuikatsurgi May 21, 2026 14:09
@claude
Copy link
Copy Markdown

claude Bot commented May 21, 2026

Code review

No issues found. Checked for bugs and CLAUDE.md compliance.

@codecov
Copy link
Copy Markdown

codecov Bot commented May 21, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 52.70%. Comparing base (2cb8015) to head (cbb52c6).
⚠️ Report is 36 commits behind head on develop.

Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff             @@
##           develop    #2237      +/-   ##
===========================================
+ Coverage    52.66%   52.70%   +0.03%     
===========================================
  Files          885      885              
  Lines       156759   156752       -7     
===========================================
+ Hits         82562    82613      +51     
+ Misses       68982    68868     -114     
- Partials      5215     5271      +56     
Files with missing lines Coverage Δ
core/forkid/forkid.go 76.69% <100.00%> (ø)

... and 45 files with indirect coverage changes

Files with missing lines Coverage Δ
core/forkid/forkid.go 76.69% <100.00%> (ø)

... and 45 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@kamuikatsurgi kamuikatsurgi merged commit 5dc5adb into develop May 26, 2026
25 of 26 checks passed
@leovct leovct deleted the leo/forkid-fix branch May 26, 2026 07:13
lucca30 added a commit that referenced this pull request May 27, 2026
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.

4 participants