Skip to content

Deterministic state sync#145

Open
marcello33 wants to merge 15 commits intorelease/3.2-developfrom
mardizzone/POS-3441_deterministic-ss
Open

Deterministic state sync#145
marcello33 wants to merge 15 commits intorelease/3.2-developfrom
mardizzone/POS-3441_deterministic-ss

Conversation

@marcello33
Copy link
Copy Markdown

@marcello33 marcello33 commented Mar 31, 2026

Summary

Implements the erigon side of deterministic state syncs for Polygon PoS.

Post-fork, the bridge service switches from time-based event window queries to the combined FetchStateSyncEventsByTime endpoint that resolves the Heimdall height internally and returns events in a single call. This ensures deterministic state-sync replay for both tip sync and historical sync.

Changes

  • Fork gating: Added DeterministicStateSyncBlock to BorConfig with IsDeterministicStateSync() check
  • Bridge service (service.go): ProcessNewBlocks branches on fork activation. Uses the combined endpoint, validates contiguous event IDs matching bor's validateEventRecord behavior (process sequential events, stop at first gap). Persists deterministic event payloads to kv.BorEvents alongside the block mapping to ensure execution reads consistent data. On errors, logs and skips instead of crashing (matching bor's pre-fork resilience).
  • HTTP client (client_http.go): New FetchStateSyncEventsByTime endpoint plus FetchBlockHeightByTime and FetchStateSyncEventsAtHeight for backward compatibility, all with runtime version detection
  • Fork ID: Included in GatherForks() for peer compatibility
  • Test infrastructure: Added -update flag for golden file regeneration in TestEthConfig

Key design decisions

  • Persist deterministic payloads: The bridge service maps blockNum → endId, but event bodies are read from kv.BorEvents during execution. The scraper populates kv.BorEvents via the old non-deterministic endpoint. Without persisting the deterministic response, execution reads stale scraper data → receipt mismatch. Fix: write events from the deterministic response to kv.BorEvents atomically with the mapping.
  • Contiguous prefix: Matches bor's validateEventRecord exactly — first event must be startId, events must be sequential, stop at first gap. Does not accept gaps or skip ahead.
  • Error resilience: Fetch failures log and break (0 state syncs for that block), matching bor. No fatal errors from the deterministic path.

Activation

  • deterministicStateSyncBlock: null (disabled) on all networks until HF is scheduled
  • Requires corresponding Heimdall-v2 changes (heimdall-v2#572) deployed first and heimdall HF to trigger first.

Cross-repository changes

Testing

  • Unit tests: deterministic path, error handling, non-contiguous events, wrong first event ID
  • Golden file tests pass (with -update flag for regeneration)
  • Kurtosis devnet chaos testing: many rounds of 2-vs-2 partition, self-heal recovery, zero receipt mismatches, state roots match bor.

@marcello33
Copy link
Copy Markdown
Author

@claude review

Copy link
Copy Markdown

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

Adds a new Bor fork point to enable “deterministic state sync” behavior, switching bridge event-range resolution to Heimdall V2 height-based queries after the configured activation block.

Changes:

  • Introduces deterministicStateSyncBlock to Bor config/chainspecs and wires it through chain config + fork ID gathering.
  • Extends the bridge Heimdall client/service to resolve a deterministic end event ID via block-height-by-time + state-syncs-at-height.
  • Adds bridge unit tests covering the deterministic path and key error/validation cases.

Reviewed changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
polygon/chain/chainspecs/bor-devnet.json Enables deterministic state sync fork on bor-devnet at block 500.
polygon/bridge/service.go Implements deterministic event range resolution and adds waitForScraperByEventId.
polygon/bridge/service_test.go Adds tests for deterministic state sync behavior and error handling.
polygon/bridge/event_record.go Adds Heimdall V2 response type for block height-by-time.
polygon/bridge/client.go Extends bridge client interface with deterministic state sync endpoints.
polygon/bridge/client_mock.go Regenerates mocks for the extended client interface.
polygon/bridge/client_idle.go Adds explicit errors for deterministic-only methods on IdleClient.
polygon/bridge/client_http.go Implements Heimdall V2 HTTP calls for height lookup and at-height event fetching.
polygon/bor/borcfg/bor_config.go Adds deterministic fork config field + accessors.
p2p/forkid/forkid.go Includes Giugliano + deterministic state sync blocks in fork ID inputs.
p2p/forkid/forkid_test.go Updates expected fork IDs for Polygon specs given added forks.
execution/chain/chain_config.go Extends BorConfig interface + prints deterministic fork in config string.

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

@marcello33 marcello33 requested a review from a team April 2, 2026 06:15
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