Skip to content

feat: show binary trie (EIP-8347) migration progress on the execution clients page - #918

Open
qu0b wants to merge 1 commit into
masterfrom
qu0b/pbt-migration-progress
Open

qu0b wants to merge 1 commit into
masterfrom
qu0b/pbt-migration-progress

Conversation

@qu0b

@qu0b qu0b commented Oct 22, 2026

Copy link
Copy Markdown
Member

Summary

Adds an optional "PBT migration" column to /clients/execution. It tracks the binary trie (EIP-8347, partitioned binary trie) migration on each execution client by polling debug_migrationProgress. We use it to follow the live MPT → PBT migration on glamsterdam-pbt-1.

PBT migration column on glamsterdam-pbt-1

  • Opt-in: executionapi.pbtMigrationProgress (env EXECUTIONAPI_PBT_MIGRATION_PROGRESS), off by default, so other networks make no extra RPC calls.
  • Polling: every 30 s per execution client. Clients without the method are backed off to 5 min.
  • Decoding: one decoder covers the response shapes clients return:
    • Geth and Besu (Phase / Binary / Merkle);
    • Nethermind's lowercase variant;
    • cursors as numbers or hex;
    • Erigon's mode / shadowStopped fields.
  • The column shows:
    • a phase badge (running / importing / failed);
    • the binary cursor and its lag behind the EL head;
    • the shadow root, with a copy button;
    • any migration error;
    • Erigon's dual-tree mode, with a "shadow stopped" warning;
    • a tooltip with the raw response.

Changes

  • clients/execution/rpc/pbtmigration.go: RPC call and response decoding, with tests.
  • clients/execution/client.go, clientlogic.go: polling loop and cached state.
  • handlers/clients_el.go, types/models/clients_el.go, templates/clients/clients_el.html: page model and column.
  • types/config.go, config/default.config.yml, services/chainservice.go: config flag.

Testing

  • go test covers RPC decoding against the response shapes seen on glamsterdam-pbt-1 (Geth, Besu, Nethermind), and a template test that renders the page with the column on and off. go vet and gofmt are clean.
  • Deployed on glamsterdam-pbt-1 from this branch (image ethpandaops/dora:pbt-migration-progress). All nine ELs report correctly: Geth and Nethermind importing, Besu running with the binary tree idle, Erigon hex. https://dora.glamsterdam-pbt-1.ethpandaops.io/clients/execution
  • Erigon's dual-tree (hex+bin) shape is still unconfirmed; the Erigon nodes haven't attached yet.

🤖 Generated with Claude Code

https://claude.ai/code/session_01AMJqwsDmWUNeAJFHUvTTee

… clients page

Add executionapi.pbtMigrationProgress (default off). When enabled, every
execution client polls debug_migrationProgress every 30s (every 5 min if the
method is not available) and /clients/execution gains a "PBT migration"
column: phase, binary cursor and its lag behind the execution head, shadow
root and errors, plus erigon's dual-commitment mode / shadow-stopped flag.

geth/besu (Phase/Binary/Cursor/ShadowRoot) and nethermind (lowercase keys)
decode into one struct since encoding/json matches names case-insensitively;
cursors accept numbers or hex strings via LenientUint64.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AMJqwsDmWUNeAJFHUvTTee

@redpandabot redpandabot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Summary

Adds an opt-in PBT (EIP-8347) migration column to the execution clients page, with background polling of debug_migrationProgress, a lenient decoder for the differing client response shapes, and a template column. The implementation is clean: lock discipline is correct, the polling loop runs on the existing single client goroutine, the cursor-lag math compares against the real EL head block number, and column/colspan counts stay consistent. One real gap: the 5-minute backoff for clients lacking the method only triggers when the error contains "not found", which misses geth's actual -32601 message.

Issues

  • 🟡 clients/execution/clientlogic.go:163 — backoff misses geth's method-not-found error message — see the thread on that line

Reviewed @ 01452ae7
"Premature abstraction is worse than premature optimization." — Sandi Metz, paraphrased

func (client *Client) pbtPollTimeout() time.Duration {
interval := 30 * time.Second
client.pbtMutex.RLock()
if client.pbtError != nil && strings.Contains(strings.ToLower(client.pbtError.Error()), "not found") {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 backoff misses geth's method-not-found error message

The 5-minute backoff matches errors containing "not found", but geth's -32601 message is "the method debug_migrationProgress does not exist/is not available" (verified in ethereum/go-ethereum rpc/errors.go), so geth-style clients are re-polled every 30 s forever instead of being backed off as intended. Consider matching "does not exist"/"is not available" too, or keying on the -32601 code.

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.

1 participant