EIP-8347 - Offline State Migration to the PBT

Created 2026-07-23
Status Draft
Category Core
Type Standards Track
Authors
Requires

Abstract

This EIP specifies an offline migration of Ethereum's state from the hexary Merkle Patricia Trie (MPT) to the Partitioned Binary Tree (PBT) defined in EIP-8297.

The full state at a finalized anchor block ANCHOR_BLOCK is converted off the consensus-critical path and distributed as a byte-canonical, verifiable PBT snapshot. That snapshot is caught up to the chain tip by replaying Block-Level Access Lists (BALs) (EIP-7928), and made canonical at a single EL+CL hard fork PBT_ACTIVATION_FORK, with both trees maintained through a transition window until that fork is finalized.

This proposal defines ANCHOR_BLOCK, PBT_ACTIVATION_FORK, the PBT snapshot artifact, the dual-check verification procedure, and the shadow-root observability concept.

Motivation

Upgrading Ethereum's state trie, such as the move to the PBT in EIP-8297, means migrating live mainnet state to a new commitment without splitting the chain. There are two broad ways to do it. The online overlay family (EIP-7748, EIP-7612) converts the state inside consensus while the chain keeps running. This EIP takes the offline path. It converts the state off the consensus-critical path and swaps the commitment at a single fork PBT_ACTIVATION_FORK.

Both paths can be made correct. The choice is a trade between two sets of costs. Going offline buys three things:

In exchange it pays two costs:

The classic downsides of going offline are distribution trust and catch-up correctness. Both are removed by the dual-check verification and BAL-replay defined below. The trade is worked through in Why offline conversion instead of the online overlay.

Specification

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174.

Parameters

Symbol Meaning Value
ANCHOR_BLOCK Anchor block whose state is converted; MUST be finalized and is identified by block hash TBD, selected during the mainnet window (post-rehearsal)
PBT_ACTIVATION_FORK The EL+CL hard fork at which the PBT becomes the canonical state commitment. This EIP names it but does not schedule it Set by the hard fork meta EIP that includes this proposal, after the shadow-commitment period
REANCHOR_CADENCE Re-anchoring cadence for late joiners, in blocks 50400 (~1 week at 12s slots)

Process overview

The sections below define the pieces of the migration: the preimages, the converter, the PBT snapshot artifact, the dual-check verification, BAL-replay, and the shadow commitment. This section shows how they fit into one lifecycle, which carries the network from an MPT-committed state to a PBT-committed state without conversion ever touching the consensus-critical path. Consensus runs on the MPT through every pre-swap phase; the commitment does not change until PBT_ACTIVATION_FORK.

The migration proceeds in five phases:

  1. Conversion (off-chain). A finalized block is designated as ANCHOR_BLOCK. Conversion produces two artifacts in two steps:
  2. Extract the preimages. The MPT is hash-keyed, so re-deriving its paths needs the raw account addresses and storage-slot keys. Keccak cannot be inverted, so the set comes from a client's retained preimages, from EIP-7928 BALs, or from chain replay, never from the hashed paths themselves.
  3. Generate the PBT snapshot. The converter reads the state committed by ANCHOR_BLOCK's stateRoot, together with the preimages, derives PBT keys per EIP-8297, and produces the PBT snapshot: a byte-canonical artifact holding the converted PBT.

Both steps are pure functions of the state committed by ANCHOR_BLOCK's stateRoot, so independent producers MUST emit bit-identical output, and both happen entirely off consensus.

  1. Distribution and verification. The PBT snapshot and preimages are published off-chain. Any node obtains them, either by downloading or by self-converting, and MUST run the dual-check verification: rebuild the PBT and confirm the claimed root (internal consistency), then re-hash the leaves under the MPT schema, using the preimages, and confirm they reproduce ANCHOR_BLOCK's stateRoot (consensus anchoring). This lets a node reject a corrupted or malicious artifact without trusting the distributor, and no release-anchored value is required.

  2. Catch-up. ANCHOR_BLOCK lags the chain tip, and keeps lagging as new blocks are produced. A node brings its verified PBT snapshot forward by BAL-replay: applying the recorded writes of each subsequent block's Block-Level Access List (EIP-7928) directly to the PBT, with no re-execution. BALs sit outside the block body and are fetched from peers over eth/71 (EIP-8159). Replay MUST outpace block production so the converted state converges to and then tracks the tip, and from here the node maintains the PBT alongside its MPT. To bound the replay gap for nodes joining late, distributors re-anchor on a fixed cadence, which also keeps the range a node has to replay inside the EIP-7928 retention window (see BAL availability).

  3. Shadow-commitment period. Attesters SHOULD publish a shadow root: the PBT root of each block's post-state, signed with their validator key. Phases 2 and 3 are per-node onboarding, run on each node's own schedule, and a node starts publishing as soon as its own PBT tracks the tip, so this phase overlaps the others rather than following a network-wide switch. Consensus still runs on the MPT throughout, so the root carries no weight yet; divergence is visible and harmless, and bugs are caught and fixed ahead of the swap rather than after. The length of this period is what builds confidence that the PBT root is correct across clients.

  4. Swap and transition window. At the coordinated EL+CL hard fork PBT_ACTIVATION_FORK, the PBT becomes the canonical state commitment. Nothing else about execution changes. The transition window runs from PBT_ACTIVATION_FORK activation until it is finalized. Through this window, nodes MUST maintain both trees and MUST keep the migration recoverable to the MPT. Only after finality MAY a node dispose of the MPT.

Actors and roles

Conversion and distribution are permissionless and untrusted. Because the conversion output is a pure function of the state committed by ANCHOR_BLOCK's stateRoot, and because the dual-check verification lets any node reject a bad artifact without trusting its source, the identity of whoever produces or serves the PBT snapshot is irrelevant to correctness. Three roles are involved:

No protocol rule requires validators to produce or serve the conversion. In practice, the network SHOULD rely on at least one reliable, well-known distribution source, so that nodes joining around PBT_ACTIVATION_FORK do not depend on chance availability. That source is expected to run conversion and serving at every re-anchor point through the shadow-commitment period. This is an operational commitment, not a consensus requirement.

Preimages

The MPT is hash-keyed, and most clients do not persist the plain account addresses and storage-slot keys behind the trie paths, so those keys cannot in general be recovered from a client's own database. The PBT is hash-keyed too: EIP-8297 keys an account's header stem by key_hash(address), and an overflow storage group by the pair key_hash(address) || key_hash(address || tree_index). A PBT leaf carries no preimage of its own, so holding the PBT does not give a node the keys behind it. Key preimages MUST therefore be distributed alongside the PBT snapshot. They serve two consumers: self-converters running on hash-keyed clients, and verifiers running the consensus-anchoring check, which re-hashes the leaves under the MPT schema and cannot run without them. Preimages MUST be extracted at ANCHOR_BLOCK, so the set corresponds exactly to the state committed by ANCHOR_BLOCK's stateRoot.

Recovering the full set is the expensive part, and the anchor state alone does not yield it, since Keccak cannot be inverted. A preimage is either retained when the key is first seen, or recovered by replaying the chain. Block-Level Access Lists (EIP-7928) carry plain addresses and slot keys, so they yield preimages for every key touched since BAL activation, but the anchor state also holds long-dormant keys untouched since then. A complete set therefore needs a client-side preimage store or a full replay; BALs shorten the work without removing it.

The preimage file is a concatenation of per-account records with no framing between them. Each record is the RLP encoding of:

[address, [slotKey, slotKey, ...]]

that is, the 20-byte account address followed by the list of that account's storage-slot keys. An account with no storage carries an empty list. RLP framing makes each record self-delimiting, so the file is parsed by decoding records sequentially until end of input. The file ends immediately after the final record. There is no terminator, padding, or trailing newline, and any trailing byte makes the file invalid.

The file MUST be byte-canonical, so independent producers emit bit-identical output. To achieve this, the encoding and ordering are fixed:

A verifier recovers the MPT account path as keccak256(address) and each storage path as keccak256(slotKey), where slotKey is first left-padded back to 32 bytes. This is what makes the consensus-anchoring check against ANCHOR_BLOCK's header stateRoot possible.

Grouping slot keys under their account is deliberate. A globally deduplicated list would be smaller, but only slightly: the repetition sits in low-numbered slots, while most storage keys are mapping-derived and unique to one account. Grouping buys something better, namely that a converter can stream one account's storage trie at a time rather than hold a global lookup table in memory.

The converter

The converter is a deterministic function from MPT state to PBT state. Given the state at ANCHOR_BLOCK (i.e., the MPT, the contract bytecode it references, and the preimages), it MUST:

  1. Scan the source (MPT) leaves, recovering each leaf's full hashed path. A leaf node holds only the tail of that path, so the walk accumulates the rest from the branch indices and extension segments above it. The path is keccak256(address) in the account trie and keccak256(slotKey) in a storage trie, where slotKey is the 32-byte big-endian slot number.
  2. Index the preimages by keccak256(preimage), and require that this index and the set of leaf paths from step 1 match exactly, in both directions. A leaf path with no preimage means the set is incomplete. A preimage matching no leaf path means the set is not the one committed by ANCHOR_BLOCK's stateRoot. The converter MUST reject either case. Per-leaf hash equality is not a check on its own, since a preimage is only ever found by hashing it. What is enforced is the exact match of the two sets.
  3. Derive PBT keys per EIP-8297 using the preimages. Most of an account's state lands under its header stem in ACCOUNT_ZONE: basic data, code_hash, and storage slots 0 through 63 at sub-indices HEADER_STORAGE_OFFSET..HEADER_STORAGE_OFFSET + 63. Only slots 64 and above take storage-zone keys.
  4. For each account with code, fetch the bytecode from the code store using the account's code_hash, chunk it per EIP-8297, and emit the resulting code leaves in CODE_ZONE, content-addressed by code_hash, so accounts sharing bytecode share them: a converter MUST emit each code leaf exactly once, since a duplicate key would break byte-canonicality. A chunk whose 32-byte value is all zero, that is 31 zero code bytes carrying no PUSHDATA, MUST NOT be emitted, since EIP-8297 requires a zero-valued key to be absent.
  5. Sort leaves by PBT key order (an external merge-sort for mainnet-scale state).
  6. Construct the tree bottom-up in a single sequential pass.

Independent, correct converters operating on the same state at ANCHOR_BLOCK MUST produce a bit-identical PBT root and a bit-identical canonical PBT snapshot. Sorting in PBT-key order lets PBT snapshot ingestion be a sequential bulk-load rather than random inserts.

Step 2 is not redundant with the dual-check. A missing preimage does surface there, as a missing PBT leaf and so a root mismatch, but only at the end of a full rebuild and without naming the key at fault; step 2 names it in one pass. A surplus preimage does not surface there at all: consensus anchoring rebuilds the MPT from the PBT leaves, so an entry matching no leaf is never read and the roots still agree. Step 2 is what holds the preimage file to the exact set committed by ANCHOR_BLOCK's stateRoot, and so what makes it byte-canonical across producers.

A self-converter's input MPT state is its own, whose correctness the node already established by executing the chain to ANCHOR_BLOCK and checking its computed state root against the header stateRoot. That input needs no separate provenance check; still holding the state at ANCHOR_BLOCK (see Actors and roles) is the only additional requirement.

PBT snapshot artifact

The conversion result is published as a PBT snapshot with the following properties:

The artifact is a small fixed header followed by the sorted leaf-record stream:

pbtRoot[32] | leafCount[8, big-endian] | leafRecord * leafCount

pbtRoot is the claimed PBT root, leafCount the number of leaf records, and each leafRecord is encoded as defined under Leaf record below. Both header fields are recomputed and checked by the dual-check.

The snapshot contains only the PBT leaves; it carries no intermediate (inner) tree nodes. Every node reconstructs those locally by hashing the leaves bottom-up during verification. This keeps the artifact minimal and forces each node to derive the tree itself rather than trust distributed inner hashes: the only inner value in the artifact is the claimed pbtRoot, which is recomputed from scratch and checked, never trusted.

The root of trust for the artifact is ANCHOR_BLOCK's stateRoot, which a node obtains from its own header chain. A client release MAY additionally pin the pbtRoot of the designated swap anchor as a cross-check, but this is optional hardening and cannot cover the intermediate re-anchor snapshots, which are produced after the release ships.

How the artifact is split for transport is left to the distribution layer. The transports in use (snap-sync-style peer-to-peer, era-style files, CDNs, torrents) already provide partial-download integrity, parallelism, and resumption, and a distributor MAY additionally publish a chunk-hash index as a non-normative download accelerator. A distributor MAY also publish the tree's inner nodes down to a fixed depth, as a second accelerator: the snapshot is sorted in PBT-key order, so a node holding them can hash each completed subtree as it arrives and check it against the published value, catching a peer serving bad leaves during the download rather than at the end of it. Neither accelerator is ever trusted, and neither affects correctness, because the dual-check re-derives the tree from the leaves and authenticates the reassembled artifact against ANCHOR_BLOCK's stateRoot.

Leaf record

Each leaf of the EIP-8297 PBT is serialized as the RLP encoding of:

[key, value]

where key is the full PBT tree key and value its 32-byte leaf value. As in the preimage file, RLP framing makes each record self-delimiting and the encoding is pinned so that producers agree byte for byte:

A verifier left-pads value back to 32 bytes before hashing it into the tree; leaf hashing is defined over the full 32-byte value, unchanged from EIP-8297.

The leading zone byte of key fixes its length, so a decoder knows what it is reading and MUST reject a key whose length disagrees with its zone:

Zone byte Zone Key length, zone byte included
0x00 account header (basic data, code_hash, storage slots 0-63) 34
0x01 code, content-addressed chunks 34
0xFF storage, slots 64 and above only 66

An account or code key is zone[1] | stem[32] | subindex[1], and a storage key is zone[1] | stem[64] | subindex[1], per EIP-8297. A decoder MUST also reject any key in the 0x02-0xFE range, which EIP-8297 reserves and no anchor-state leaf can occupy.

The trailing byte of every key is the sub-index. Two records belong to the same stem if and only if their keys are equal in all bytes except the sub-index. In other words, key[:-1] is identical. Because the PBT snapshot is sorted in PBT-key order, all records sharing a stem are contiguous.

Canonical digests

Both distributed files are byte-canonical, so each has a single digest that every correct producer reproduces for a given anchor:

Neither is a root of trust; a node runs the dual-check whatever the digests say and however the bytes arrived. What the digests buy is cheap agreement ahead of an expensive download. Each is 32 bytes, so a node MAY compare them across several independent producers or distributors and decline a source that disagrees, rather than discovering the disagreement after reassembling and rebuilding the whole snapshot.

pbtRoot cannot serve this purpose. It commits to the leaf set rather than to the byte stream, and it can only be recomputed once every leaf is present, so it says nothing about a partial download. For the same reason it does not authenticate the optional chunk-hash index or the optional inner nodes above. A distributor publishing either SHOULD also publish a digest over it, so that it can be cross-checked the same way before it is relied on to localize a fault mid-download.

Verification (dual-check)

Any node MUST be able to verify a downloaded PBT snapshot without trusting the distribution source. This includes a fresh node with no prior state. Because the snapshot carries only leaves and no intermediate nodes, verification is also the step in which each node derives the full tree for itself. To verify, the node performs both checks:

  1. Internal PBT consistency. Rebuild the PBT from the PBT snapshot leaves: derive keys per EIP-8297, compute every intermediate node by hashing bottom-up, and verify that the resulting root matches the claimed PBT root. The intermediate nodes are a product of this step, not part of the distributed artifact.
  2. Consensus anchoring. Re-hash the PBT snapshot leaves under the MPT schema using the distributed preimages and verify the result against block ANCHOR_BLOCK's header stateRoot. That covers every field the MPT commits: nonce, balance, storage, and code_hash.

The MPT holds no code, so the re-hash alone leaves the code leaves and code_size unchecked. They are anchored instead to the code_hash it does cover. For each distinct code_hash, reassemble the bytecode from the 31-byte slices of that code's chunk leaves in chunk order, taking the chunk count from code_size and reading an absent chunk as 31 zero bytes, truncate the result to code_size, and require its keccak256 to equal that code_hash. Then re-chunk the recovered bytecode per EIP-8297 and require its non-zero chunks to equal the artifact's code leaves byte for byte, which pins each chunk's leading PUSHDATA count as well as its contents and its placement in CODE_ZONE. A wrong code_size yields different bytes, so the same preimage pins it. version is the one remaining field the MPT does not commit; EIP-8297 sets it to zero on every header write, so every basic-data leaf MUST carry version == 0.

A PBT snapshot that fails either check MUST be rejected, and the node MUST re-obtain or re-convert.

Without the code limb of check 2, a snapshot carrying corrupted or wholly absent code leaves would pass both checks: internal consistency recomputes the root over whatever leaves it is given, and the MPT re-hash never reads them. A downloading node has no other source of bytecode, since only a self-converter holds a code store.

BAL-replay

State transition from the anchor to the tip is performed by replaying Block-Level Access Lists (EIP-7928) without re-execution. For each block after ANCHOR_BLOCK, per-entry translation rules apply the recorded writes to the PBT:

Replay deletion semantics

Replay MUST preserve one invariant: the PBT obtained by replaying from ANCHOR_BLOCK to a block B MUST be bit-identical to the PBT obtained by converting the MPT state at B directly. Both routes are in use at once: re-anchoring publishes freshly converted snapshots at intermediate blocks, and the shadow commitment compares roots reported by nodes that reached the same block by different routes.

Deletion itself is defined by EIP-8297: a key whose value is 32 zero bytes MUST NOT be present, writing zero to a key removes it, and deleting an account removes its header and storage leaves, together with any of its content-addressed CODE_ZONE leaves that no remaining account's code_hash addresses. Those rules govern replay before PBT_ACTIVATION_FORK and execution from it alike, so nothing about deletion changes at activation. What replay adds is how each deletion is recognized in a BAL, which carries no deletion marker and MUST therefore be read from recorded post-values:

Reorg handling

Rollback MUST be performed by discarding state, never by reversing writes. EIP-7928 records post-values only (new_value, post_balance, new_nonce), so a BAL cannot be inverted: undoing a replayed block would require the values it overwrote, and they do not appear in the BAL.

Shadow roots MUST be keyed by block hash rather than by height. Two nodes reporting for the same height on opposite sides of a reorg hold different states and correctly report different roots. Keying by height would misread that as divergence.

BAL availability

BALs are not part of the block body, so a node cannot recover them from block data it already holds. A node obtains the BALs it needs for replay from peers over the eth/71 protocol defined in EIP-8159, using GetBlockAccessLists / BlockAccessLists. That protocol is the transport this migration relies on; no migration-specific wire protocol or gossip is introduced.

Replay therefore depends on BALs being available for the range a node actually has to cover, and EIP-8159 lets a peer answer with an empty entry for a block whose BAL it has pruned. Re-anchoring bounds that range: a joining node starts from the most recent published anchor, never an older one, so the required range is at most REANCHOR_CADENCE plus the lag between a re-anchor point and the publication of its artifacts (the point must be finalized first, and conversion takes time).

REANCHOR_CADENCE MUST be chosen so that this bound stays inside the EIP-7928 retention window, which is the weak subjectivity period (3533 epochs, roughly 113000 blocks). At the value specified here, 50400 blocks (~1 week), two full cadences fit inside that window. Ordinary EIP-7928 retention thus already keeps every BAL a node could need available over eth/71, and this EIP imposes no retention requirement of its own.

Re-anchoring

The BAL-replay gap between an anchor and the tip grows without bound as the chain advances, so a node that begins catch-up long after conversion would have to replay the entire elapsed chain. To bound that gap, a distributor re-runs the conversion at successive finalized anchors on a fixed cadence and publishes a fresh snapshot and preimage set for each. Re-anchor points are the blocks whose height is that of ANCHOR_BLOCK plus n * REANCHOR_CADENCE for n = 1, 2, ..., and each MUST be finalized before its artifacts are produced. The cadence also bounds how many BALs a node needs, which is what keeps replay inside the EIP-7928 retention window (see BAL availability).

Each re-anchored snapshot is a self-contained artifact anchored to its own block's stateRoot, verified by the same dual-check, with no dependency on earlier anchors. A joining node selects the most recent re-anchor at or below finality, verifies it, and BAL-replays only from that anchor forward. Through the shadow-commitment period the reliable distribution source SHOULD run conversion and serving at every re-anchor point, so that a node joining at any time has a recent snapshot to start from.

Shadow commitment

Through the pre-swap period, consensus still runs on the MPT. In that period attesters SHOULD compute the shadow root of each block, the PBT root of that block's post-state, and publish it signed with their validator key. Conversion correctness then becomes observable per block, in public, and traceable to whoever reported it.

Shadow roots travel in an out-of-consensus telemetry sidecar, and publication is never a block-validity condition. A missing or late shadow root counts against a coverage metric rather than as a divergence, which is what keeps the signal readable. The sidecar is expected to ship enabled by default in consensus-layer clients, so coverage comes from ordinary validator operation rather than from an opt-in program; like the reliable distribution source, that is an operational expectation, not a consensus requirement.

Wire format, aggregation scheme, publication timing, and any EL-to-CL plumbing are out of scope here. They are left to a companion EIP, planned but not yet published; nothing about them is settled elsewhere, and this EIP assumes nothing about them.

Activation

At PBT_ACTIVATION_FORK the PBT becomes the canonical state commitment. The change is confined to which tree produces the value in the existing stateRoot header field.

Transition window

Both the MPT and the PBT MUST be maintained from the activation of the PBT at PBT_ACTIVATION_FORK until PBT_ACTIVATION_FORK is finalized. Only after finality MAY a node dispose of the MPT. Until the activation release deploys, the migration MUST remain fully recoverable to the MPT.

Rationale

Why offline conversion instead of the online overlay

EIP-7748 and EIP-7612 convert the state inside consensus, behind a boundary that moves forward one block at a time. Both that online overlay and this offline design can be made correct, so the choice is about which costs to pay. This EIP takes the offline path. It pays more disk and gives up on-chain observability of the conversion, and in return gets a smaller consensus change, whole-state proofs throughout, and no conversion inside any zkEVM proof. Each of the five points is worked through below.

A smaller consensus change. An overlay's read rule is simple: try the overlay tree, fall back to the base MPT. The cost is the cursor that drives the conversion to completion, because it lives in the state. EIP-7748 tracks which account is being converted, how far into it the conversion has got, and whether it has finished, advancing by CONVERSION_STRIDE units every block. So every client must agree on the cursor bit for bit at every block, the order of MPT traversal becomes consensus-critical, avoiding stale writes over fresher values becomes a correctness condition that surfaces only as a wrong state root, and the stride has to be chosen for long reorgs, which rewind the cursor with the rest of the state. PBT_ACTIVATION_FORK adds none of that: no conversion state, no per-block schedule, no ordering requirement, just one header field computed from a different tree at one block.

No hybrid proof verifiers. Either way a new tree changes proof formats, and either way the header carries exactly one root, since EIP-7612 also swaps the header state root at its fork. The difference is how much that root covers. Offline, it covers the whole state at every block. During an overlay conversion it covers only the part converted so far, so proving a key still held in the base MPT takes a second proof against the frozen MPT root, which no header carries and which the verifier must pin out of band; proving absence takes both. So an on-chain bridge verifier needs three deployments under an overlay against two switching at a known block: an MPT verifier, a hybrid verifier carrying an out-of-band root, then a PBT verifier. The middle one is the expensive one, the only one that is not a plain tree lookup, built for a bounded window and then maintained anyway.

No in-consensus conversion for zkEVM provers. Block validity proofs are expected to be live by swap time. In an overlay, a prover must prove the conversion steps for every block in the window on top of proving normal execution. Offline conversion never enters a proof: provers keep proving plain MPT execution until PBT_ACTIVATION_FORK, then commit to the PBT root. How large the avoided cost is depends on how heavy a conversion step is to prove and on how mature zkEVM proving is by then, but the point is structural: only the online design pays it at all.

More disk. This is the main cost of going offline. An overlay can delete converted entries from the old tree as it goes, so it stores about one tree throughout. Offline holds both through the transition window, an extra ~300 GB at mainnet scale. That cost is temporary and confined to converting nodes, and holding the MPT is what keeps the migration recoverable until finality (see Transition window). A node that cannot spare the disk can snap-sync the PBT at PBT_ACTIVATION_FORK instead of self-converting.

No on-chain observability of the conversion. This is the second cost. An overlay computes the new root in consensus, so its correctness is observed on-chain as it proceeds; offline conversion is not. This EIP recovers that visibility off consensus, through the shadow-commitment period. The substitute is weaker, because publication is not enforced: what gets observed is coverage over voluntary reports, not a validity condition every node must satisfy. One residual exposure remains, a converter bug confined to the final pre-fork blocks, whose activated PBT root consensus never validates. It is addressed under Unvalidated-flip input.

Why an anchor block and a single fork

Pinning conversion to one finalized block ANCHOR_BLOCK makes the conversion output a pure function of committed state. So independent producers can be required to agree bit-for-bit, and a fresh node can anchor trust in ANCHOR_BLOCK's stateRoot without trusting any distributor. Collapsing activation into one fork PBT_ACTIVATION_FORK keeps the consensus change small and the swap semantics trivial (commitment only). That is what makes comprehensive rehearsal and full recoverability achievable.

Why BAL-replay for catch-up

The conversion-node lineage this design descends from relied on ad-hoc catch-up messages. Replaying EIP-7928 Block-Level Access Lists instead applies per-block writes directly and needs no re-execution. BALs are already produced for other reasons and are already exchanged between peers by eth/71 (EIP-8159), so catch-up reuses an existing wire protocol instead of adding a migration-specific one. BALs do live outside the block body and are prunable, but re-anchoring keeps the range a node must replay inside the EIP-7928 retention window, so no extra retention rule is needed: see BAL availability.

Replay does need to delete leaves, since the invariant the whole verification story rests on is that converting the MPT at a block and replaying BALs onto an earlier snapshot land on the same tree. EIP-8297 treats a zero value as absent and deletes on account deletion, so replay reuses the deletion path execution already needs and the invariant holds across PBT_ACTIVATION_FORK unchanged. All that is migration-specific is deriving those deletions from a BAL, which records no deletion marker: see replay deletion semantics.

Why shadow roots, and why publication is not a consensus rule

The offline model's weak point is that consensus does not observe conversion correctness before the swap. Having attesters publish signed per-block PBT roots through the pre-swap period restores that observability: divergence from the expected PBT root becomes visible and attributable while it is still harmless, so it can be caught and fixed before PBT_ACTIVATION_FORK rather than after. Attesters are the right source because they are the set that validates blocks, so the measurement covers the validating majority rather than whoever happens to build, and the validator signature is what makes a single report attributable.

Publication nonetheless stays a SHOULD and out of consensus. Enforcing it as a block-validity rule would make every validator compute the PBT post-state root for every block just to decide whether the block is valid. That puts PBT construction back on the consensus-critical path, the exact property the offline model exists to avoid, and it brings back the two-trees-consensus-live attack surface. Cross-client agreement therefore accumulates by observation rather than by enforcement, at the cost of coverage being a measured quantity instead of a guaranteed one.

That much is settled here; the wire specifics are not, and are left to the planned companion EIP. There is one narrow case where hard enforcement may still be warranted, the final blocks before PBT_ACTIVATION_FORK, discussed under Unvalidated-flip input.

Backwards Compatibility

PBT_ACTIVATION_FORK changes the state commitment only, so it is backwards compatible at the application layer:

The migration is not transparent to systems that depend on the state structure itself:

Test Cases

Security Considerations

Unvalidated-flip input

At PBT_ACTIVATION_FORK, the PBT root activated for the final pre-fork block has not itself been validated by consensus. So a converter bug affecting only those final blocks could be activated. There are two mitigations. One is to hard-enforce the shadow root for the final blocks before PBT_ACTIVATION_FORK. That is the one place where making it a validity condition may be worth the cost. The other is to rely on sustained cross-client agreement accumulated over the shadow-commitment period. A correlated all-client conversion bug would be undetectable under either the online or the offline model, so this is not unique to this proposal.

Shadow-root coverage

Because publication is voluntary, how much of the validating set reports depends on the telemetry sidecar shipping enabled by default rather than on enforcement. Readiness assessment must therefore treat coverage as a measured quantity, and read a low-coverage period as weak evidence rather than as evidence of agreement. What is at stake is coverage, not representativeness: the reports come from the set that validates blocks, not only from the parties that build them. Pre-swap divergence itself stays harmless and self-detectable, since consensus still runs on the MPT.

Distribution trust

The PBT snapshot is large (~100+ GB) and distributed off-chain, which in principle is a vector for serving corrupted state. The dual-check neutralizes it: the root of trust is ANCHOR_BLOCK's stateRoot, taken from the node's own header chain, so a fabricated but internally self-consistent package (fake leaves matching a fake pbtRoot) fails consensus anchoring, and fabricated code leaves fail its code limb. Integrity checking on partial downloads is left to the distribution transport (e.g. torrent piece hashes, Transport Layer Security (TLS), CDN checksums), letting a node drop a bad segment on arrival rather than after full reassembly; a malicious distributor serving altered bytes that pass those transport checks is still caught once the artifact is reassembled.

Recoverability

A fault discovered during or immediately after the swap is recovered by falling back to the MPT, which the transition window keeps available until PBT_ACTIVATION_FORK is finalized.

Copyright

Copyright and related rights waived via CC0.