Repository navigation
Update EIP-8272: deploy recent root contract as standard contract - #12443
Conversation
|
✅ All reviewers have approved. |
|
In the past we often put the geas code into the EIP. |
|
lgtm, this is what I suggested on #12131, and it matches #12387. I checked that the deployment transaction reproduces, that the bytecode matches ethereum/sys-asm#53, and that it does what the spec says. The deployment needs about 700k of the 1.3M gas limit. Two small things before merging:
|
|
@soispoke renamed the rows in 8e9bc7d |
|
@soispoke could you approve if the rename looks ok? eth-bot needs one author review to merge 🙏 |
|
yes, lgtm |
eth-bot
left a comment
There was a problem hiding this comment.
All Reviewers Have Approved; Performing Automatic Merge...
eth-bot
left a comment
There was a problem hiding this comment.
All Reviewers Have Approved; Performing Automatic Merge...
#14437) * fix(eip8250): align TXPARAM keyed-nonce indices with the spec EIP-8250 assigns 0x0D legacy nonce, 0x0E key count, 0x0F nonce_keys_hash, 0x10 first key. EIP-8272 no longer defines a TXPARAM index, so 0x0F belongs to EIP-8250 on every fork and indices above 0x10 halt. * test(eip8250): pin TXPARAM 0x0F halting with only EIP-8272 active * fix(eip8272): verify recent roots with a canonical VERIFY frame Follow EIPs 20fb52b9 and 824cbc0b: drop the recent_root_references envelope field, RECENTROOTREFLOAD, the per-reference intrinsic gas and the native pre-execution check. A recent root is now verified by a VERIFY frame targeting RECENT_ROOT_ADDRESS whose data is n 72-byte tuples, validated by the predeploy with ordinary EVM execution. Install RECENT_ROOT_CODE from ethereum/sys-asm#53 at activation. * fix(eip8272): report an overrun frame tx payload as truncated * test(eip8272): pin the truncation error for an overrun frame tx payload * feat(eip8272): public mempool rules for the recent_root_verify frame * fix(eip8272): sweep the in-memory blob pool for stale recent roots Refuse a tuple-carrying blob frame tx in a persistent blob pool, whose frameless records the sweep cannot read, and skip the sweep while no pooled tx carries tuples. * fix(eip8272): count persistent-blob-pool recent-root refusals separately * fix(eip8272): evict recent-root frame txs once RECENT_ROOT_ADDRESS stops running RECENT_ROOT_CODE * feat(eip8272): index recent-root mempool dependencies by expiry slot Record each pending recent_root_verify transaction's (storage_key, entry_hash) dependencies and its first expiring current_slot. A head extending the previous one only ages tuples out, with no storage reads; any other head rechecks every indexed transaction, reading each distinct cell once. A head before activation evicts every such transaction. * fix(eip8272): read recent-root storage outside the dependency index lock * test: drop multiple-assert scope spanning state-mutating Process calls * test: resolve the recent-root block executor from production modules * test: drop unused using in FrameTxBlockProductionTests * test: fold the payload truncation message into the declared-length overrun test * fix(eip8272): reject a recent_root_verify frame unless RECENT_ROOT_ADDRESS runs RECENT_ROOT_CODE The tracer only withheld the SLOTNUM and recent-root SLOAD permissions over other code, so code needing neither (a bare STOP) was admitted. EIP-8272 requires rejection when the code differs or the fork is inactive. * test(eip8272): pool admission of recent_root_verify through the real prefix simulator Committed tuple then self-verify, with optional expiry and deploy prologue; tuple age at the head slot, 8190 and 8191 measured at head.slotNumber + 1; rejection for wrong code at RECENT_ROOT_ADDRESS and for a sender reading recent-root storage through a call. * fix(eip8272): release the hash of an aged-out recent_root_verify transaction so a slot rollback can readmit it * test(eip8272): resolve the recent_root_verify admission pool and simulator from the test container * fix(eip8272): judge pending recent roots against one snapshot of the canonical head Head events are consumed after the chain has moved, while admission validates against the canonical head. Taking the header and its state together from IChainHeadInfoProvider.TryGetHeadState keeps a transaction admitted against a newer head from being judged at an older event's slot. * chore(eip8272): drop the unused rlp using after the master merge * refactor(eip8272): drop the unused RecentRootStore reference check The mempool sweep checks age and commitment in RecentRootDependencyIndex, and block execution checks them in the predeploy, so only RecentRootStoreTests still called IsReferenceValid. The window, current-slot and mismatched-root cases stay pinned against the predeploy in Execute_RecentRootVerifyFrame_IsCheckedAgainstTheCommittedEntry. * docs(eip8272): rewrap the recent-root sweep remarks and name their subject * fix(eip8272): initialise the recent root predeploy only over an empty account * fix(eip8272): drop the recent-root dependency of a transaction the pool no longer holds * docs(eip8272): drop comments describing the removed envelope field * fix(eip8272): reject a chain spec activating EIP-8272 before EIP-8141 or EIP-7843 * perf(txpool): recheck recent-root dependencies before taking the head lock * test(eip8272): exempt EIP-8272 from the single-transition chain parameters check EIP-8272 cannot activate without EIP-8141 and EIP-7843, so a chain spec that sets only its timestamp is rejected. Its activation is covered by ChainSpecBasedSpecProviderTests. * fix(eip8272): reject a block when foreign code sits at the predeploy address * fix(eip8272): reject any non-empty predeploy account on the activation block EIP-8272 Activation requires RECENT_ROOT_ADDRESS to have empty code and empty storage in the parent state of the first active block, otherwise that block is invalid. The installer accepted an account already holding the canonical RECENT_ROOT_CODE as initialised, so a chain could activate over pre-seeded canonical code (and any storage under it). The installer now takes the parent block's release spec. When the predeploy is not active in the parent (the activation transition), any code, canonical included, or any storage makes the block invalid. When it is already active in the parent, an account with code or storage is left untouched and never re-initialised, so later blocks keep the installed code and the ring-buffer storage. The parent spec is resolved by IBlockAccessListManager.GetParentSpec from the parent header via IHeaderFinder and ISpecProvider, which BlockAccessListManager now takes as optional constructor dependencies (resolved by DI in production; passed explicitly by the stateless, witness-capturing and witness-generating environments). Both the normal and BAL system-contract handlers forward it into PredeployInstaller. An empty account (no code, no storage) is still installed when the parent already has EIP-8272 active, which keeps chains that enable the EIP from genesis working: block 1's parent is genesis, whose spec is already active, and the genesis allocation need not carry the code. On a chain whose activation is a real transition this case cannot arise after the activation block, since that block installs the code. Tests: the activation block is rejected over canonical code, foreign code, and storage without code; a block after activation keeps the installed code and storage and records no BAL change; the installer rejects every non-empty shape when the parent is inactive and leaves it unchanged when the parent is active; the genesis-active install over an empty account keeps passing. * refactor(eip8272): read recent root tuples with range slices RecentRootStore.ReadTuple now slices the source id, slot and root with C# range syntax instead of Span.Slice, as asked in review. Same offsets and lengths; no behaviour change. * refactor(eip8272): drop the chainspec activation-order guard ChainSpecBasedSpecProvider rejected a chainspec scheduling EIP-8272 before EIP-8141 or EIP-7843. Per review, the provider does not enforce activation ordering for any other EIP, so the check and the test that existed only for it are removed. No other test depended on the exception. * test(eip8272): drop the removed recent root reference list from the rpc view cases * feat(eip8272): deploy the recent root contract as an ordinary contract Follows ethereum/EIPs#12443: the recent root contract is no longer installed at EIP-8272 activation. It is created by the pre-signed keyless deployment transaction at 0x8272D9679689Ea2f307140CdF9002D27dC00Ffff. - RecentRootAddress moves to the deployed address; code and code hash unchanged - PredeployInstaller drops the recent root entry and the once-only initialisation path, so the parent-spec plumbing and the RecentRootPredeployNotEmpty block error go too - a test replays the EIP's deployment transaction and checks hash, sender, code hash and nonce at the derived address * test(eip8272): call the recent root contract a contract, not a predeploy * test(txpool): keep resubmission outside multiple-assert scopes * test(eip8272): share the activation tests with the expiry verifier
* fix(eip8250): align TXPARAM keyed-nonce indices with the spec EIP-8250 assigns 0x0D legacy nonce, 0x0E key count, 0x0F nonce_keys_hash, 0x10 first key. EIP-8272 no longer defines a TXPARAM index, so 0x0F belongs to EIP-8250 on every fork and indices above 0x10 halt. * test(eip8250): pin TXPARAM 0x0F halting with only EIP-8272 active * fix(eip8272): verify recent roots with a canonical VERIFY frame Follow EIPs 20fb52b9 and 824cbc0b: drop the recent_root_references envelope field, RECENTROOTREFLOAD, the per-reference intrinsic gas and the native pre-execution check. A recent root is now verified by a VERIFY frame targeting RECENT_ROOT_ADDRESS whose data is n 72-byte tuples, validated by the predeploy with ordinary EVM execution. Install RECENT_ROOT_CODE from ethereum/sys-asm#53 at activation. * fix(eip8272): report an overrun frame tx payload as truncated * test(eip8272): pin the truncation error for an overrun frame tx payload * feat(eip8272): public mempool rules for the recent_root_verify frame * fix(eip8272): sweep the in-memory blob pool for stale recent roots Refuse a tuple-carrying blob frame tx in a persistent blob pool, whose frameless records the sweep cannot read, and skip the sweep while no pooled tx carries tuples. * fix(eip8272): count persistent-blob-pool recent-root refusals separately * fix(eip8272): evict recent-root frame txs once RECENT_ROOT_ADDRESS stops running RECENT_ROOT_CODE * feat(eip8272): index recent-root mempool dependencies by expiry slot Record each pending recent_root_verify transaction's (storage_key, entry_hash) dependencies and its first expiring current_slot. A head extending the previous one only ages tuples out, with no storage reads; any other head rechecks every indexed transaction, reading each distinct cell once. A head before activation evicts every such transaction. * fix(eip8272): read recent-root storage outside the dependency index lock * test: drop multiple-assert scope spanning state-mutating Process calls * test: resolve the recent-root block executor from production modules * test: drop unused using in FrameTxBlockProductionTests * test: fold the payload truncation message into the declared-length overrun test * fix(eip8272): reject a recent_root_verify frame unless RECENT_ROOT_ADDRESS runs RECENT_ROOT_CODE The tracer only withheld the SLOTNUM and recent-root SLOAD permissions over other code, so code needing neither (a bare STOP) was admitted. EIP-8272 requires rejection when the code differs or the fork is inactive. * test(eip8272): pool admission of recent_root_verify through the real prefix simulator Committed tuple then self-verify, with optional expiry and deploy prologue; tuple age at the head slot, 8190 and 8191 measured at head.slotNumber + 1; rejection for wrong code at RECENT_ROOT_ADDRESS and for a sender reading recent-root storage through a call. * fix(eip8272): release the hash of an aged-out recent_root_verify transaction so a slot rollback can readmit it * test(eip8272): resolve the recent_root_verify admission pool and simulator from the test container * fix(eip8272): judge pending recent roots against one snapshot of the canonical head Head events are consumed after the chain has moved, while admission validates against the canonical head. Taking the header and its state together from IChainHeadInfoProvider.TryGetHeadState keeps a transaction admitted against a newer head from being judged at an older event's slot. * chore(eip8272): drop the unused rlp using after the master merge * refactor(eip8272): drop the unused RecentRootStore reference check The mempool sweep checks age and commitment in RecentRootDependencyIndex, and block execution checks them in the predeploy, so only RecentRootStoreTests still called IsReferenceValid. The window, current-slot and mismatched-root cases stay pinned against the predeploy in Execute_RecentRootVerifyFrame_IsCheckedAgainstTheCommittedEntry. * docs(eip8272): rewrap the recent-root sweep remarks and name their subject * fix(eip8272): initialise the recent root predeploy only over an empty account * fix(eip8272): drop the recent-root dependency of a transaction the pool no longer holds * docs(eip8272): drop comments describing the removed envelope field * fix(eip8272): reject a chain spec activating EIP-8272 before EIP-8141 or EIP-7843 * perf(txpool): recheck recent-root dependencies before taking the head lock * test(eip8272): exempt EIP-8272 from the single-transition chain parameters check EIP-8272 cannot activate without EIP-8141 and EIP-7843, so a chain spec that sets only its timestamp is rejected. Its activation is covered by ChainSpecBasedSpecProviderTests. * fix(eip8272): reject a block when foreign code sits at the predeploy address * fix(eip8272): reject any non-empty predeploy account on the activation block EIP-8272 Activation requires RECENT_ROOT_ADDRESS to have empty code and empty storage in the parent state of the first active block, otherwise that block is invalid. The installer accepted an account already holding the canonical RECENT_ROOT_CODE as initialised, so a chain could activate over pre-seeded canonical code (and any storage under it). The installer now takes the parent block's release spec. When the predeploy is not active in the parent (the activation transition), any code, canonical included, or any storage makes the block invalid. When it is already active in the parent, an account with code or storage is left untouched and never re-initialised, so later blocks keep the installed code and the ring-buffer storage. The parent spec is resolved by IBlockAccessListManager.GetParentSpec from the parent header via IHeaderFinder and ISpecProvider, which BlockAccessListManager now takes as optional constructor dependencies (resolved by DI in production; passed explicitly by the stateless, witness-capturing and witness-generating environments). Both the normal and BAL system-contract handlers forward it into PredeployInstaller. An empty account (no code, no storage) is still installed when the parent already has EIP-8272 active, which keeps chains that enable the EIP from genesis working: block 1's parent is genesis, whose spec is already active, and the genesis allocation need not carry the code. On a chain whose activation is a real transition this case cannot arise after the activation block, since that block installs the code. Tests: the activation block is rejected over canonical code, foreign code, and storage without code; a block after activation keeps the installed code and storage and records no BAL change; the installer rejects every non-empty shape when the parent is inactive and leaves it unchanged when the parent is active; the genesis-active install over an empty account keeps passing. * refactor(eip8272): read recent root tuples with range slices RecentRootStore.ReadTuple now slices the source id, slot and root with C# range syntax instead of Span.Slice, as asked in review. Same offsets and lengths; no behaviour change. * refactor(eip8272): drop the chainspec activation-order guard ChainSpecBasedSpecProvider rejected a chainspec scheduling EIP-8272 before EIP-8141 or EIP-7843. Per review, the provider does not enforce activation ordering for any other EIP, so the check and the test that existed only for it are removed. No other test depended on the exception. * test(eip8272): drop the removed recent root reference list from the rpc view cases * feat(eip8272): deploy the recent root contract as an ordinary contract Follows ethereum/EIPs#12443: the recent root contract is no longer installed at EIP-8272 activation. It is created by the pre-signed keyless deployment transaction at 0x8272D9679689Ea2f307140CdF9002D27dC00Ffff. - RecentRootAddress moves to the deployed address; code and code hash unchanged - PredeployInstaller drops the recent root entry and the once-only initialisation path, so the parent-spec plumbing and the RecentRootPredeployNotEmpty block error go too - a test replays the EIP's deployment transaction and checks hash, sender, code hash and nonce at the derived address * test(eip8272): call the recent root contract a contract, not a predeploy * test(txpool): keep resubmission outside multiple-assert scopes * test(eip8272): share the activation tests with the expiry verifier * refactor(consensus): remove the now-empty predeploy installer EIP-8141, EIP-8250 and EIP-8272 system contracts are now deployed by ordinary transactions, so the installer has no entries left and its block-processing hook never runs.
…led (#327) ethereum/EIPs#12443 made the EIP-8272 recent root contract an ordinary contract at `0x8272D9679689Ea2f307140CdF9002D27dC00Ffff`, deployed by the keyless transaction in the EIP. The fork does not install it, so it has to be in state when the fork activates. This predeploys it when Heze (EL bogota) is scheduled, same pattern as #324, with `DEPLOY_EIP8272_CONTRACTS` (default `true`) to skip it. The code is `RECENT_ROOT_CODE` from the EIP, 320 bytes, nonce 1. Needed for frames-devnet-1, see the open genesis item in ethereum/execution-specs#3727. Checked with a local image build on `test-cases/case5-frames-enabled.env`: the account is in `genesis.json` with the EIP code, it is absent with `DEPLOY_EIP8272_CONTRACTS=false`, and absent when bogota is not scheduled. Co-authored-by: Barnabas Busa <busa.barnabas@gmail.com>
#14437) * fix(eip8250): align TXPARAM keyed-nonce indices with the spec EIP-8250 assigns 0x0D legacy nonce, 0x0E key count, 0x0F nonce_keys_hash, 0x10 first key. EIP-8272 no longer defines a TXPARAM index, so 0x0F belongs to EIP-8250 on every fork and indices above 0x10 halt. * test(eip8250): pin TXPARAM 0x0F halting with only EIP-8272 active * fix(eip8272): verify recent roots with a canonical VERIFY frame Follow EIPs 20fb52b9 and 824cbc0b: drop the recent_root_references envelope field, RECENTROOTREFLOAD, the per-reference intrinsic gas and the native pre-execution check. A recent root is now verified by a VERIFY frame targeting RECENT_ROOT_ADDRESS whose data is n 72-byte tuples, validated by the predeploy with ordinary EVM execution. Install RECENT_ROOT_CODE from ethereum/sys-asm#53 at activation. * fix(eip8272): report an overrun frame tx payload as truncated * test(eip8272): pin the truncation error for an overrun frame tx payload * feat(eip8272): public mempool rules for the recent_root_verify frame * fix(eip8272): sweep the in-memory blob pool for stale recent roots Refuse a tuple-carrying blob frame tx in a persistent blob pool, whose frameless records the sweep cannot read, and skip the sweep while no pooled tx carries tuples. * fix(eip8272): count persistent-blob-pool recent-root refusals separately * fix(eip8272): evict recent-root frame txs once RECENT_ROOT_ADDRESS stops running RECENT_ROOT_CODE * feat(eip8272): index recent-root mempool dependencies by expiry slot Record each pending recent_root_verify transaction's (storage_key, entry_hash) dependencies and its first expiring current_slot. A head extending the previous one only ages tuples out, with no storage reads; any other head rechecks every indexed transaction, reading each distinct cell once. A head before activation evicts every such transaction. * fix(eip8272): read recent-root storage outside the dependency index lock * test: drop multiple-assert scope spanning state-mutating Process calls * test: resolve the recent-root block executor from production modules * test: drop unused using in FrameTxBlockProductionTests * test: fold the payload truncation message into the declared-length overrun test * fix(eip8272): reject a recent_root_verify frame unless RECENT_ROOT_ADDRESS runs RECENT_ROOT_CODE The tracer only withheld the SLOTNUM and recent-root SLOAD permissions over other code, so code needing neither (a bare STOP) was admitted. EIP-8272 requires rejection when the code differs or the fork is inactive. * test(eip8272): pool admission of recent_root_verify through the real prefix simulator Committed tuple then self-verify, with optional expiry and deploy prologue; tuple age at the head slot, 8190 and 8191 measured at head.slotNumber + 1; rejection for wrong code at RECENT_ROOT_ADDRESS and for a sender reading recent-root storage through a call. * fix(eip8272): release the hash of an aged-out recent_root_verify transaction so a slot rollback can readmit it * test(eip8272): resolve the recent_root_verify admission pool and simulator from the test container * fix(eip8272): judge pending recent roots against one snapshot of the canonical head Head events are consumed after the chain has moved, while admission validates against the canonical head. Taking the header and its state together from IChainHeadInfoProvider.TryGetHeadState keeps a transaction admitted against a newer head from being judged at an older event's slot. * chore(eip8272): drop the unused rlp using after the master merge * refactor(eip8272): drop the unused RecentRootStore reference check The mempool sweep checks age and commitment in RecentRootDependencyIndex, and block execution checks them in the predeploy, so only RecentRootStoreTests still called IsReferenceValid. The window, current-slot and mismatched-root cases stay pinned against the predeploy in Execute_RecentRootVerifyFrame_IsCheckedAgainstTheCommittedEntry. * docs(eip8272): rewrap the recent-root sweep remarks and name their subject * fix(eip8272): initialise the recent root predeploy only over an empty account * fix(eip8272): drop the recent-root dependency of a transaction the pool no longer holds * docs(eip8272): drop comments describing the removed envelope field * fix(eip8272): reject a chain spec activating EIP-8272 before EIP-8141 or EIP-7843 * perf(txpool): recheck recent-root dependencies before taking the head lock * test(eip8272): exempt EIP-8272 from the single-transition chain parameters check EIP-8272 cannot activate without EIP-8141 and EIP-7843, so a chain spec that sets only its timestamp is rejected. Its activation is covered by ChainSpecBasedSpecProviderTests. * fix(eip8272): reject a block when foreign code sits at the predeploy address * fix(eip8272): reject any non-empty predeploy account on the activation block EIP-8272 Activation requires RECENT_ROOT_ADDRESS to have empty code and empty storage in the parent state of the first active block, otherwise that block is invalid. The installer accepted an account already holding the canonical RECENT_ROOT_CODE as initialised, so a chain could activate over pre-seeded canonical code (and any storage under it). The installer now takes the parent block's release spec. When the predeploy is not active in the parent (the activation transition), any code, canonical included, or any storage makes the block invalid. When it is already active in the parent, an account with code or storage is left untouched and never re-initialised, so later blocks keep the installed code and the ring-buffer storage. The parent spec is resolved by IBlockAccessListManager.GetParentSpec from the parent header via IHeaderFinder and ISpecProvider, which BlockAccessListManager now takes as optional constructor dependencies (resolved by DI in production; passed explicitly by the stateless, witness-capturing and witness-generating environments). Both the normal and BAL system-contract handlers forward it into PredeployInstaller. An empty account (no code, no storage) is still installed when the parent already has EIP-8272 active, which keeps chains that enable the EIP from genesis working: block 1's parent is genesis, whose spec is already active, and the genesis allocation need not carry the code. On a chain whose activation is a real transition this case cannot arise after the activation block, since that block installs the code. Tests: the activation block is rejected over canonical code, foreign code, and storage without code; a block after activation keeps the installed code and storage and records no BAL change; the installer rejects every non-empty shape when the parent is inactive and leaves it unchanged when the parent is active; the genesis-active install over an empty account keeps passing. * refactor(eip8272): read recent root tuples with range slices RecentRootStore.ReadTuple now slices the source id, slot and root with C# range syntax instead of Span.Slice, as asked in review. Same offsets and lengths; no behaviour change. * refactor(eip8272): drop the chainspec activation-order guard ChainSpecBasedSpecProvider rejected a chainspec scheduling EIP-8272 before EIP-8141 or EIP-7843. Per review, the provider does not enforce activation ordering for any other EIP, so the check and the test that existed only for it are removed. No other test depended on the exception. * test(eip8272): drop the removed recent root reference list from the rpc view cases * feat(eip8272): deploy the recent root contract as an ordinary contract Follows ethereum/EIPs#12443: the recent root contract is no longer installed at EIP-8272 activation. It is created by the pre-signed keyless deployment transaction at 0x8272D9679689Ea2f307140CdF9002D27dC00Ffff. - RecentRootAddress moves to the deployed address; code and code hash unchanged - PredeployInstaller drops the recent root entry and the once-only initialisation path, so the parent-spec plumbing and the RecentRootPredeployNotEmpty block error go too - a test replays the EIP's deployment transaction and checks hash, sender, code hash and nonce at the derived address * test(eip8272): call the recent root contract a contract, not a predeploy * test(txpool): keep resubmission outside multiple-assert scopes * test(eip8272): share the activation tests with the expiry verifier
deploys the recent root contract with a standard nick's method transaction, same as the expiry verifier in #12387. RECENT_ROOT_CODE and RECENT_ROOT_ADDRESS are now fixed, activation makes no state change. this overlaps the 8272 part of #12406