Repository navigation
feat(spec-specs,test-forks,tests): implement EIP-8141 frame transactions - #3936
gurukamath wants to merge 42 commits into
Conversation
* feat(specs): EIP-8141 transaction types * WiP * feat(specs): EIP-8141 frame transaction processing Implement the type-6 frame transaction flow on the amsterdam fork, separated from the regular flow from admission onwards: - static validation, signature verification, intrinsic gas, and the two gas anchors (standard_gas_limit, max_gas) in transactions/frame_transaction.py - consensus receipt types (FrameReceipt, FrameTransactionReceipt) and the 0x06 receipt codec arms in blocks.py - TransactionEnvironment split into top_level_context/frame_context in vm/__init__.py - admission through a dedicated check_frame_transaction in frame_processing.py; process_transaction dispatches frame transactions after the chain-id check - frames execute as independent top-level calls in vm/frame_interpreter.py: per-frame gas meters, atomic batches, cross-frame warm journal, default verify code, approval rollback - the six frame opcodes (TXPARAM, FRAMEDATALOAD, FRAMEDATACOPY, FRAMEPARAM, SIGPARAM, APPROVE) in vm/instructions/frame.py - settlement anchored on the standard gas limit with the calldata floor binding through max_gas; the payer refund is max_cost - charged_fee; the frame transaction receipt reports status, gas, and logs per frame Co-authored-by: lightclient <lightclient@protonmail.com> * feat(spec-tools): adapt t8n for FrameTransaction Co-authored-by: lightclient <lightclient@protonmail.com> * feat(test-types): Add EIP-8141 support to testing framework Co-authored-by: lightclient <lightclient@protonmail.com> * feat(tests): EIP-8141 frame transaction tests Co-authored-by: lightclient <lightclient@protonmail.com> * fix(bogota): correct SIGPARAM copy operand order EIP-8141 aligned the SIGPARAM (0xb4) copy operation's stack order with CALLDATACOPY (ethereum/EIPs 4a9ad32c): after signatureIndex and param the operands are memOffset, dataOffset, length. The implementation still popped them in the old order (length, dataOffset, memOffset) — the reverse of its own FRAMEDATACOPY. Swap to match the live spec. * Restore minimal comment on SIGPARAM copy form * fix: warm the sender for frame transactions Frame transaction processing initializes the shared, once-per-tx warm address set with the sender so its first EVM access is charged warm (100) rather than cold (2600). The sender is loaded unconditionally for the nonce check and, like a regular transaction's origin, must start warm per EIP-2929 and EIP-3651. * feat(spec): add EXPRIY_VERIFIER contract * feat(tests): add introspection tests test: cover the EIP-8141 introspection instructions * feat(tests): add more introspection tests * feat(tests): add frame transaction warmth tests * fix(tests): restore EIP-8141 reference spec pin * fix(spec): adapt frame transaction gas to ExecutionGas/StateGas newtypes Upstream #3121 wrapped amsterdam gas values in ExecutionGas/StateGas NewTypes; wrap the frame transaction call sites accordingly. * feat(tests): add frame transaction validity tests * feat(tests): more frame transaction validity tests * fix(tests): fix broken egacy tests for frames * feat(tests): add block access list cases for frame transactions * feat(tests): frame-transaction block access list cases Add EIP-8141 frame-transaction cases that pin the consensus-visible EIP-7928 block access list across frame rollback paths: an atomic-batch unroll and a frame revert drop the discarded storage write and re-file the slot as a bare access; a skipped atomic-batch frame stays absent from the BAL; and a sponsored transaction attributes the payer's fee and the sender's nonce to distinct accounts. These paths are exercised only as state tests today, so the BAL is unpinned for them. * refactor(tests): tighten frame BAL cases and reuse module helpers Build the frames with the module's `verify_frame`/`sender_frame` helpers instead of hand-rolled `Frame` literals, matching the rest of the suite. Tighten the assertions so each case pins what it claims: the sponsored transaction now asserts the sender has no balance change and the payer no nonce bump, so a spurious BAL entry cannot pass on a correct post state, and the atomic-batch cases assert the sender's nonce bump is recorded whether or not the batch unrolls. Derive the payer's post balance from the charged gas and fee per gas rather than hardcoding it, and pin both on the transaction, so a gas change surfaces as a gas mismatch instead of an opaque balance. --------- Co-authored-by: Marc Harvey-Hill <10379486+Marchhill@users.noreply.github.com> * feat(tests): additional gas helpers for frame transactions * feat(tests): add frame target resolution test cases * feat(tests): frame target resolution cases Cover the three ways a frame's resolved target carries the empty code hash: a precompile under each non-VERIFY mode and under VERIFY, and an EIP-7702 authority whose designation is resolved at frame entry or points at a precompile. * feat(tests): discriminate the VERIFY target resolution split Move the approvals of the precompile-target `VERIFY` case onto the first frame and leave the frame under test approving nothing. With the approvals on the frame under test, dispatching the precompile leaves the transaction with no payment approver, so it is rejected either way and the case rests on matching the exact rejection reason; with them moved, dispatching makes the transaction valid. Add a `VERIFY` frame whose target designates a precompile: its resolved code is empty, as for the codeless target that does route to the default code, but the target holds a designation and so must follow it instead. * refactor(tests): pair the warming frame with its receipt The warming frame, its expected receipt and the designated address's access charge each branched on `warm_delegate` separately, the receipt through a comprehension over the frame list. Decide all three in one place so the frame and its receipt cannot drift apart. * feat(tests): frame gas that cannot afford the designation access The designated account is read only once its access is paid for, so a frame that cannot afford it leaves the account out of the block access list as well as unexecuted. * refactor(tests): use the frame entry gas calculator Account the frame entry charges with `fork.frame_entry_gas_calculator()` rather than summing `gas_costs` members, so the target and designation access charges come from one place. Pin the sender's nonce as unchanged in the rejected precompile-target case, and move the unaffordable-designation case to the block access list suite: the receipts cannot tell a resolution failure from a failure inside the resolved code, since either forfeits the whole frame gas limit, so assert the designated account absent from the BAL and the target present as a bare access. Its frame gas is the largest that still cannot afford the designation's access. --------- Co-authored-by: Marc Harvey-Hill <10379486+Marchhill@users.noreply.github.com> * feat(tests): create transaction tests from validity checks * fix(specs,tests): add max gas checks and tests plus some other fixes suggested in spencers review * feat(tests): cover the frame-entry charge a target that is not alive adds This covers the third charge `create_evm_from_frame` levies against a frame's own gas before its EVM is built: the `NEW_ACCOUNT` state gas a client levies when the frame's value transfer revives a target that is not alive. `test_frame_target_entry_charge` covers the target's own access and `test_delegated_target_entry_charge` the delegate's; this covers the remaining one. `test_dead_target_entry_charge` covers the case where a client enters a `SENDER` frame moving value to an account that is not alive. The target has no code, so the frame runs empty code and the receipt's `gas_used` is the entry charge alone. `NEW_ACCOUNT` is 120 state bytes, 183_600 gas, which is more than a frame usually declares, so the affordable arm is only half the behavior. The second arm gives the frame one gas less than the charge and covers the case where a client cannot enter the frame at all: it forfeits its whole gas limit, the target stays dead, and no transfer log is emitted. The case pins per-frame `gas_used` rather than the transaction total, because the EIP-7623 calldata floor can dominate a small frame transaction's total and hold it constant while a frame's own gas moves. `frame_entry_gas_calculator` already takes `sends_value_to_dead_account` and the test derives its expectations from it. Filled against the reference implementation; both arms go red if the charge is not levied. It came up while running a devnet. Co-authored-by: ilitteri <ivan.litteri@lambdaclass.com> --------- Co-authored-by: Guruprasad Kamath <guru241987@gmail.com> Co-authored-by: lightclient <lightclient@protonmail.com> Co-authored-by: Marc Harvey-Hill <10379486+Marchhill@users.noreply.github.com> Co-authored-by: Daniil Ankushin <ankushin.daniil42@gmail.com> Co-authored-by: Marc <Marchhill@users.noreply.github.com> Co-authored-by: Ivan Litteri <67517699+ilitteri@users.noreply.github.com> Co-authored-by: ilitteri <ivan.litteri@lambdaclass.com>
Two halves of the same EIP-8141 revision (ethereum/EIPs `9c915ee49`), which the implementation here predates. The static rule is new to both the spec and the tests: approval scope is disallowed on every frame of an atomic batch, including its terminating frame -- a frame belongs to a batch when it or its predecessor carries the flag. Keeping the approval context constant across a batch means unrolling one can never withdraw an execution approval that later SENDER frames rely on, and whether the transaction sets a payer never depends on a batch outcome. Three cases cover it: the flagged member, the terminating frame, and a frame after the terminator, which is outside the batch and stays valid so the rule's upper boundary is pinned too. The revert rule is tests-only; the implementation already behaves correctly and this pins it. A frame that reverts discards the approval context it granted. APPROVE exits its own call context, so a frame cannot approve and then revert directly, but a nested call back into the frame's target can: the inner call approves and returns, and the outer frame decides afterwards. Keeping the approval does not merely leak it -- the payer stays bound while the max_cost collection it performed is rolled back, so the transaction is valid and settles fees against an account that paid nothing. The reverting case is paired with a returning control case, which is what makes it meaningful: without the control, an implementation that keeps the approval would pass the reverting case for the wrong reason, having been rejected for never approving at all.
…3398) * Cover the signature-validation precompiles being absent from the block access list A frame transaction's protocol-validated signatures are checked before execution, outside the EVM, so ecrecover and P256VERIFY are never called by the transaction and must not appear in the block access list. Nothing in state distinguishes the two behaviours -- a precompile has no storage, balance or nonce to change -- but the block access list is committed to in the header, so an implementation that validates signatures by dispatching through its own EVM adds the precompile as a touched address, produces a different block access list hash, and has its block rejected while every other result matches. That is what makes it worth a fixture rather than a comment. The transaction carries one signature of each protocol-validated scheme so both precompiles are exercised, and asserts each is absent. Flipping either assertion to expect the address present fails, so the absence is really being checked. * Reuse the shared precompile address constants and take the default frame gas The ecrecover and P256VERIFY addresses are already defined in tests/frontier/precompiles/spec.py and tests/osaka/eip7951_p256verify_precompiles/spec.py, so import them instead of redefining the literals. The sender frame targets Op.STOP and writes nothing, so it does not need WRITE_FRAME_GAS, which is documented as what a writing frame requires beyond the framework default.
…#3412) Co-authored-by: spencer-tb <spencer.tb@ethereum.org>
Co-authored-by: Marc Harvey-Hill <10379486+Marchhill@users.noreply.github.com>
…gota (#3418) Co-authored-by: Felix H <felix314159@users.noreply.github.com>
This implements the spec updates from this PR - ethereum/EIPs#12226 * fix(eip-8141): account block execution gas before refund * test(eip-8141): bump reference spec for EIP-7778 integration * fix(eip-8141): settle refund and floor accounting together * test(eip-8141): derive refund floor cases dynamically * style(test): format gas settlement test * fix(tests): static checks * fix(tests): pin search transaction nonce --------- Co-authored-by: Guruprasad Kamath <guru241987@gmail.com>
* feat(tests/amsterdam): pin frame-tx spent gas across a refill rollback Add two EIP-8141 state tests that a storage refill returned to a frame by a later frame's rollback lands in the transaction's spent gas, not only in the per-frame receipt. One drives an atomic batch that unrolls after a batch frame refills a pre-batch receipt; the other reverts the refilling frame itself. Both assert every frame's state gas and the transaction's cumulative gas used. * chore(tests): move refill settlement tests to test_gas_settlement --------- Co-authored-by: Guruprasad Kamath <guru241987@gmail.com>
…mapper (#3467) NethermindExceptionMapper had no TYPE_6_* entries, so every frame transaction rejection fell through to the TYPE_3_TX_WITH_FULL_BLOBS catch-all, which matches the client's generic "Transaction <n> is not valid: <cause>" decode wrapper and discards the cause. Add the format, signature and execution wordings, and the decode-time and fee-overflow ones the same catch-all was swallowing. The mapper is additive, so these narrow what a fixture matches without changing any message that already resolved. Co-authored-by: Marc Harvey-Hill <10379486+Marchhill@users.noreply.github.com>
#3500) * chore(tests): pin spec to the latest This does not require an implementation update or additional tests since the implementation already exihibits this behaviour * feat(tests): refill legacy state tests as frame transactions A tree-level tests/conftest.py that parametrizes every state test with a second, frame-transaction shape. The frame variant rewrites the test's transaction into the canonical [VERIFY, SENDER] frame pair — carrying fees (the default legacy gas price included), blobs, and non-gas receipt/header pins through, and stripping gas pins, which the fixture's post-state root still covers via the fee balances — and refills it otherwise unchanged, gated on the fork supporting transaction type 6. The SENDER frame's budgets are derived per test: execution maximized against the EIP-7825 cap net of the calldata intrinsic, state fitted under the block gas limit. A test's smaller block gas limit is raised to the framework default for the frame variant, since the two frame gas dimensions cannot spill into each other the way the legacy pool does. Unconvertible transactions (types 1 and 4, creation, access lists, explicit gas limits, reservoir semantics, delegated senders) are reported under a dedicated frame-unconvertible category: no progress characters, one grouped per-reason summary block. A test pinning the sender's post balance fails its frame variant with a message directing to the receipt-pin idiom; test_value_move_to_precompiles is rewritten to that idiom accordingly. Oracles that genuinely depend on the transaction type opt out via the new frame_tx_incompatible marker — first user: test_all_opcodes, whose invalid-opcode expectation for TXPARAM (0xB0) only holds outside a frame transaction. The ported_static skip-list normalizer learns to strip the transaction-shape id segments. Verified at Bogota over the full tree (state tests, not slow): 18,492 passed, 0 failed; 4,402 frame variants filled green; the amsterdam directory's 522 blockchain-fixture twins have post storage identical to their legacy counterparts; pre-Bogota fills are byte-identical with and without the conftest. * refactor(tests): fill frame-tx variants as labeled fixture formats Replace the tree-level conftest's parametrize/fixture-override machinery with the test-variants mechanism: FrameTransactionVariant, a LabeledFixtureFormat subclass, labels every fill-phase state-test format as <format_id>_frame_tx, and StateTest.generate() applies the transaction rewrite itself when handed the variant. The converter moves into the testing package next to StateTest, base fixture ids stay exactly as authored (the -non_frame_tx segment disappears), and the same-name state_test fixture shadowing is gone. The variant vetoes itself where the old conftest skipped: at collection for non-frame forks (supports_fork) and for tests marked exception_test or frame_tx_incompatible — now seen at param level too, which the function-level check missed — and at fill time, via runtime skips, for unconvertible transactions. The engine_x and stateful formats are excluded: their pre-alloc phases hash the genesis of the untransformed test. Each variant carries its own transition-tool cache key so a frame transaction never shares the base format's cached t8n output, and the filler's sort key learns the cache key so interleaved base/variant items stop clearing the single-key cache. The frame-unconvertible skip reporting moves from the conftest into a filler plugin module, registered tryfirst: pytest-custom-report claims every skipped report in the firstresult race, and only a conftest — registered last — used to win without it. Framework unit tests follow the mechanism: the duplicate-cache-key verifier treats an empty key as the caching opt-out it is, the derived-labels test counts only non-variant labels, the forks-plugin tests consult the label's supports_fork rather than the wrapped format's, and the collect-only test expects the discarded variants in pytest's pre-discard collection count. Verified at Bogota: fixture content is identical to the conftest mechanism across the amsterdam tree, the DUPN/SWAPN/EXCHANGE directory's full formats, and the ported skip-listed files, with a 100% t8n cache hit rate; pre-frame Amsterdam fills are byte-identical to the bare upstream base. * fix(tests): preserve state-test context in frame variants * fix(tests): preserve chain ID in frame transaction variants * fix(tests): preserve block gas limit in frame variants --------- Co-authored-by: spencer <spencer.tb@ethereum.org>
…fork transition (#3539) * feat(test-specs,tests): exercise the EIP-8141 expiry verifier install at the fork transition EIP-8141 installs the expiry verifier's runtime code at 0x...8141 when the fork activates, and leaves the account's nonce and balance as they were (EIPs@b75cbe6, "Expiry verifier contract"; `apply_fork` in the Amsterdam spec module on this branch). No fixture exercised that install: every EIP-8141 test starts at Bogota with the account already in the genesis allocation, so a client that installs it with a nonce of one passes the whole suite and diverges on the state root of the activation block of a live network. Three things stood in the way of a transition fixture: - there was no transition fork into Bogota; - `make_genesis` seeds `transitions_to().pre_allocation_blockchain()`, so even a transition fixture would have carried the code at genesis; - nothing in the filler applies a fork's activation-time state change (`apply_fork` is only called by `ethereum_spec_tools.sync`), which no fork since the DAO fork has needed. Add `BaseFork.activation_code_installs()`: the runtime code a fork writes when it activates, keyed by address. `EIP8141` moves the verifier from `pre_allocation_blockchain` to this hook; state tests keep `pre_allocation`, having no activation to cross. `Alloc.with_installed_code` applies such installs changing only the code. The blockchain filler applies the genesis fork's installs at genesis and, in `generate_block_data`, the installs new to a block's fork relative to its parent's fork before the block executes. The hive `execute` genesis and the engine_x pre-alloc groups apply the genesis-side installs the same way. Add `AmsterdamToBogotaAtTime15k`. Add `test_fork_transition.py`. A probe records `EXTCODESIZE` of the verifier per block, none before the fork and the code from the fork block on, with the account absent, funded by a pre-fork transfer, or already present with a nonce and balance that must survive the install; and a frame transaction carrying an expiry frame executes in the activation block itself. A pre-fork type-6 rejection test is not possible while Bogota shares Amsterdam's spec module. No pre-existing fixture changes: filling tests/amsterdam/eip8141_frame_transactions at Bogota with all formats on the unmodified and on the modified tree yields 943 hash-identical fixtures; the new tests add 21 (7 cases in 3 formats). `just static` and the forks, specs and fixtures unit tests pass. * docs(tests): describe what the EIP-8141 transition test pins, not what a wrong install would do The docstring of the install test explained the nonce check by describing one incorrect implementation. State the check itself instead: the post-state pins nonce, balance and code, so an install that writes anything other than the code fails. * refactor(test-specs): compare activation installs by Address The fork-block install diff in generate_block_data looked up the parent fork's installs with whatever key type each hook returned. Normalising both sides to Address means an int key on one fork and an Address key on another still compare equal, instead of re-installing code the parent fork already had. * feat(tests): pin storage and the block access list in the EIP-8141 install tests Add a case where the verifier address already holds storage before the fork, so the post-state pins that only the code changes and the storage survives, matching the hook's contract of a code-only install. Assert the block access list of every block: the verifier appears only through the transactions that touch it and never with a code change, in the fork block included. The install is not a block-level operation and must leave no trace there. Mark the module valid_at_transition_to("Bogota") rather than the EIP name, and document two limits in the module docstring: these tests cover the verifier install, not the activation block as a whole, and a transition test that needs pre-fork Amsterdam rules is not possible while EIP-8141 lives inside the amsterdam spec package and Bogota is only a test-side label for it.
* feat(consume): map Besu EIP-8141 frame transaction exceptions
Besu rejects invalid type-6 frame transactions with its own error
strings, none of which BesuExceptionMapper knew about, so every
EIP-8141 negative test failed with "Undefined exception message"
rather than comparing the exception.
Signed-off-by: jflo <justin+github@florentine.us>
* feat(consume): map Besu EIP-8141 frame transaction exceptions
Besu rejects invalid type-6 frame transactions with its own error
strings, none of which BesuExceptionMapper knew about, so every
EIP-8141 negative test failed with "Undefined exception message"
rather than comparing the exception.
Signed-off-by: jflo <justin+github@florentine.us>
EIP branches that each rewrite the Bogota fork docstring conflict when the devnet workflow merges them, so this branch leaves it as forks/bogota has it; the EIP is listed there when it lands.
…ing inside a frame (#3757) ethereum/EIPs#12458 adds the approval context to what EIP-8141 journals with state, alongside the state-gas ownership records and the frame receipt edits: "Reverting a call, frame, or atomic batch restores all of them to the corresponding checkpoint." The spec already restores the frame context on every failed message call, but the suite only reverted frames and atomic batches, so a client that restored nothing on a failed call inside a successful frame passed it. test_call_revert_above_approve_discards_the_approval nests an APPROVE two calls below a frame that succeeds and reverts the call in between: the approval goes with it, leaving the transaction without a payer, and the frame can approve again afterwards; returning instead is the control. test_call_revert_restores_refilled_receipt reverts a call that refilled an earlier frame's receipt and checks the receipt and the executing frame's pool. test_reversion_restores_charge_ownership consumes a slot's charge ownership record in a reverted call, a reverted frame and an unrolled batch, and checks that a later clear still refills the frame that paid. The reference spec pin moves to 7752622050, which includes #12458 and the parameter names #3754 already uses.
… the minimum data (#3784) Co-authored-by: Guruprasad Kamath <48196632+gurukamath@users.noreply.github.com> Co-authored-by: 蔡佳誠 Louis Tsai <72684086+LouisTsai-Csie@users.noreply.github.com>
* feat(tests): pin the memory charge of a refused EIP-8141 APPROVE A refused APPROVE still pays the memory expansion of its return-data region, charged before the checks that refuse it; one case per refusal: wrong caller, scope beyond the mask, scope outside the frame's flags, payer already set. * feat(tests): charge creation of an EIP-8141 sender emptied mid-tx A sender an earlier frame spent down to empty does not exist under EIP-8037's rule, so APPROVE charges its account creation; the creation tests now cover it and pin the budget at the charge and one unit below. * feat(tests): leave an EIP-8141 delegate unread on a failed transfer A SENDER frame whose value exceeds the balance fails before dispatch, so a delegated recipient's delegate is neither charged nor recorded in the BAL. * feat(tests): accept an EIP-8141 transaction from the zero address The static rules only check the sender's length, so a zero-address sender whose code approves is valid; pinned as a state test and a transaction test. * feat(tests): delegate an EIP-8141 failed transfer to a precompile A precompile delegate is always warm, so a client that reads the delegate on a failed transfer shows it only as an extra block access list entry. The contract case alone catches that read through its cold access gas. * refactor(tests): delegate a failed EIP-8141 transfer to every precompile The precompile case moves into its own test over with_all_precompiles, sharing the transaction with the contract case through a helper, since a client can single out some precompiles. * refactor(tests): take EIP-7708 transfer logs from its spec module The value transfer tests rebuilt the EIP-7708 log address, topic and log helper that the 7708 suite's spec module already defines.
Cover blob-carrying frame transactions beyond the single-transaction frame variants of the Cancun blob tests: BLOBHASH and the TXPARAM blob fields in DEFAULT, SENDER and VERIFY frames; frame and EIP-4844 transactions sharing the block blob limit; rejection of a block body carrying the network wrapper; and execute-only blob_transaction_test cases that submit the wrapper over eth_sendRawTransaction and read the blobs back through engine_getBlobsV*. In execute mode a blob-carrying frame transaction now defaults its blob fee cap as a type-3 one does, and set_gas_price and signer_minimum_balance account for it. Frame transactions without blobs keep a blob fee cap of 0, and filled fixtures do not change. Backport of #3824, merged into devnets/bogota/1 as 6e38ded, without its EIP-7906 POST_TX BLOBHASH test, which lands on eips/bogota/eip-7906 separately. Co-authored-by: Guruprasad Kamath <guru241987@gmail.com>
The frame transaction rewrite changes only the transaction and the post-state expectations, never the pre-allocation or the environment, so a variant derives the same genesis as its base test and can join its pre-allocation group. Give every format except the stateful one a frame_tx variant, and add a test that the rewrite keeps the genesis.
* feat: add frame transaction helper * refactor: apply helper to all the test implementation * refactor(tests): drop the EIP-8141 frame gas budget that restates the default * refactor(tests): drop the EIP-8141 frame pins the helper derives * test(tests): pin the EIP-8141 deployment and transition frame gas
…ges for `bogota-devnet-2` (#3892) Co-authored-by: Guruprasad Kamath <48196632+gurukamath@users.noreply.github.com>
The shared devnet release feature fills through Bogota on this branch, so its build matrix ends with the bogota range. The assertion that it ends at Amsterdam came in with #3597 against the fork branch's config, where the feature stops at Amsterdam.
(cherry picked from commit 8a0247f)
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## forks/bogota #3936 +/- ##
================================================
+ Coverage 95.10% 95.12% +0.02%
================================================
Files 673 677 +4
Lines 40904 41914 +1010
Branches 3778 3941 +163
================================================
+ Hits 38903 39872 +969
- Misses 1393 1417 +24
- Partials 608 625 +17
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
bt-recneps
left a comment
There was a problem hiding this comment.
Mutated 30 EIP-8141 spec rules, six survive every fill, also uncaught are payment before execution, exact payer balance and the TSTORE reset :(
Reviewed in 14m 49s
| @pytest.mark.parametrize( | ||
| "call_opcode,scope", | ||
| [ | ||
| pytest.param(Op.CALL, Spec.APPROVE_PAYMENT, id="caller_not_target"), |
There was a problem hiding this comment.
caller_not_target also fails payer_already_set and passes with APPROVE's ADDRESS != resolved_target check deleted, so run its inner CALL before any payer is set.
| if len(signature.message) != 0: | ||
| return FrameStatus.FAILURE |
There was a problem hiding this comment.
Deleting this empty-msg check passes every fill, so add a default-code VERIFY case whose index-0 entry is signed_digest_entry(sender.key), expecting TYPE_6_INVALID_FRAME_EXECUTION.
The EIP-8141 share of #3926, which landed on devnets/bogota/2 and in no EIP branch, so every devnet rebuild would have had to re-pick it.
fef700f to
bac6e1a
Compare
|
Re the bt-recneps review above: I ran these mutants against the tests in #3917 (which targets this branch). It catches the 3 surviving mutants from the inline comments and the 3 uncaught rules from the summary. The current tests on
How I ran it: each mutation applied to The summary doesn't show the exact edits for the last three, so I used the simplest edit that breaks each rule: deleted the "execution approved first" check, changed |
…torage tests (#3939) * feat(tests): add EIP-8141 VERIFY-frame static context and transient storage tests * refactor(tests): share CALL_VALUE and drop an always-true TLOAD check
Opening this PR as an alternative to #3878 but with an
execution-specsbranch instead of a fork branch so that all changes flow directly through to the PR without needing a manual push.Description
Merge the
eips/bogota/eip-8141branch intoforks/bogota. EIP-8141 (FrameTransactions) is Scheduled for Inclusion in the Hegotá meta EIP (EIP-8081),
so the implementation moves from its prototyping branch onto the fork branch.
The branch is rebased onto the current
forks/bogotatip and brings:ethereum.forks.bogota: framedecoding and static validity, the
VERIFY/SENDER/PAYER/CALL/POST_TXframe modes, approval scope, the per-frame gas accounting andcalldata floor settlement, the frame interpreter and introspection
opcodes, the expiry verifier deployed as an ordinary contract, and the
block execution gas accounting before refunds.
signatures).
EIP8141fork mixin for Bogota, frame transactiontypes and signing helpers, the frame transaction variant that re-fills
eligible earlier-type tests as frame transactions (state, blockchain and
engine_x formats), and client exception mappings for geth, Nethermind,
besu, ethrex and Reth.
tests/bogota/eip8141_frame_transactionscovering admissionand static validity, target resolution, warmth, block access lists,
introspection, the expiry verifier, the fork transition install, approval
edge cases, blob-carrying frame transactions and value-moving frames.
Every commit on the branch was reviewed as a separate PR against it. On the
tip,
just staticpasses andfill --from Amsterdam --until Bogota tests/bogota/eip8141_frame_transactionsproduces 875 fixtures.
Follow-ups once merged: rebase
eips/bogota/eip-8250,eips/bogota/eip-8272,eips/bogota/eip-7906anddevnets/bogota/1ontoforks/bogota; #3799retargets to
forks/bogota.Related Issues or PRs
Part of #2829.
Checklist
just static<type>(<area>): <description>, where<type>and<area>come from an appropriateC-<type>, respectivelyA-<area>, label. The title should match the target squash commit message.Cute Animal Picture