Skip to content

fix(network): seed fork filter from DB head and update on each canonical block#341

Draft
chee-chyuan wants to merge 1 commit into
developfrom
fix/fork-id-stale-head
Draft

fix(network): seed fork filter from DB head and update on each canonical block#341
chee-chyuan wants to merge 1 commit into
developfrom
fix/fork-id-stale-head

Conversation

@chee-chyuan
Copy link
Copy Markdown

Fixes #335

Root cause

BscNetworkBuilder was initialising the network's fork filter from a hardcoded block number baked into BscChainSpec::head() (block 40,000,000 on mainnet) rather than the actual canonical head read from the database.

The fork ID is a hash of which hardforks are active at a given block height. When the node advertises a fork ID computed from block 40M to peers who know it is actually at block ~95M, every peer handshake fails with fork id mismatch and the peer is disconnected. Once all peers are gone, block sync stalls entirely. A restart temporarily re-establishes connections until the same thing recurs.

A second related issue: ImportService never called network_handle.update_status() after importing blocks, so even if startup worked, the fork filter would go stale the moment a hardfork timestamp was crossed at runtime.

Fix

src/node/network/mod.rs

Replace ctx.chain_spec().head() (hardcoded) with ctx.head() (DB-sourced) when building the NetworkConfig. This is exactly what upstream reth does — ctx.head() is populated from the database by lookup_head() before BuilderContext is constructed, so the fork filter is seeded correctly from the first handshake.

src/node/network/block_import/service.rs

Call network_handle.update_status(head) after every successful update_forkchoice() in ImportService — both for incoming network blocks and locally mined blocks. This keeps the fork filter current as the chain advances and hardforks activate, mirroring the ChainEvent-driven update_status loop in upstream reth's engine launcher.

Testing

  • cargo check passes cleanly
  • Behaviour matches upstream reth's fork filter lifecycle: DB head at startup, live updates on every canonical block

…cal block

The network's fork filter was initialized from a hardcoded block number
baked into BscChainSpec::head() rather than the actual canonical head
from the database. This caused every peer handshake to fail with a fork
ID mismatch once the chain advanced past that hardcoded block, draining
all peers and stalling block sync until the node was restarted.

Two fixes:
- Use ctx.head() (DB-sourced) instead of ctx.chain_spec().head()
  (hardcoded) when building the NetworkConfig, aligning with how
  upstream reth initialises the fork filter.
- Call network_handle.update_status() after every successful
  update_forkchoice() in ImportService (both incoming and mined blocks),
  so the fork filter stays current as hardforks activate at runtime.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@hashdit-bot
Copy link
Copy Markdown

hashdit-bot Bot commented May 5, 2026

Pull Request Review

This PR fixes fork-ID desynchronization in the BSC network layer by initializing the network head from the database-backed canonical head (ctx.head()) instead of a hardcoded chainspec head. It also updates peer status/fork filter continuously by calling network_handle.update_status(...) after successful forkchoice updates for both imported network blocks and locally mined blocks. Additionally, it removes a manual forkid assignment, relying on the network config/fork filter lifecycle to stay consistent.

Sensitive Content

No sensitive content detected.

Security Issues

No serious security issues detected.


Generated by Hashdit Bot. This tool can absolutely NOT replace manual audits.

timestamp: header.timestamp,
difficulty: header.difficulty,
total_difficulty: td,
});
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

https://github.com/bnb-chain/reth/blob/develop/crates/node/builder/src/launch/engine.rs#L447

There is a update_status in the Reth engine, that is not work?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

oh good point, let me check

.ok()
.flatten()
.unwrap_or_default();
net.update_status(Head {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Ditto.

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.

2 participants