Repository navigation
feat(tests): add missing EIP-8141 frame transaction coverage - #3917
Mannan-Goyal wants to merge 15 commits into
Conversation
… and introspection bounds
Read every expected gas amount off the bytecode under test or the fork's calculators instead of rebuilding it from schedule constants: state gas from `.state_cost(fork)`, refunds from `.refund(fork)`, stipends from `fork.call_value_stipend()`, the refund cap from `fork.max_refund_quotient()`, intrinsic terms as calculator deltas and burns from `GasConsumer`. Drop the self-check asserts and the `storage_set_cost`/`account_creation_cost`/`clearing_refund`/ `restoring_refund` helpers, and restore the framework-priced lines in `test_state_gas.py` that the helpers had replaced. Also, in the same modules: cover the call and create opcode families with `with_all_call_opcodes`/`with_all_create_opcodes`, handle every parametrized value with an explicit branch, add the passing side of the one-sided batch boundaries, keep gas numbers out of docstrings, and stop restating the gas limit as the expected gas used.
Cover the call and create opcode families with the covariant markers, handle every parametrized value with an explicit branch, say why each listed exception of a multi-error case is valid, drop the module-level `inclusion_test` mark from the raw RLP rejections, add the passing side of the one-sided introspection boundaries and keep gas numbers out of docstrings.
Move each new module whose subject an existing module already owns into that module, keeping every test name and case: - test_cross_frame_access.py -> test_warmth.py - test_tx_validity_bounds.py -> test_static_validity.py (transaction tests) and test_admission_validity.py (in-block test) - test_block_limits.py -> test_admission_validity.py - test_introspection_bounds.py -> test_introspection.py - test_refund_edges.py -> test_gas_settlement.py - test_state_gas_subcalls.py -> test_state_gas.py - test_default_code_approval_refusals -> test_approval_edges.py Duplicate constants and helpers now use the destination's version, and helpers shared by two modules live in helpers.py.
- Deploy non-zero runtime code from the frame-create init code again, so the `code=` post checks fail for an init code that copies nothing. - Split the pre-existing victim out of the create-opcode-marked self-destruct refill test; it creates nothing, so its CREATE2 case duplicated the CREATE one. - Restore the premise that the calldata floor sits exactly `cap_excess` byte prices from the gas cap.
|
Taking this out of draft. I've kept it as one PR, but happy to split it by the areas in the description if that's easier to review. It merges cleanly with the current |
|
Thanks @Mannan-Goyal for the offer to split, let's do that. At 12.5k lines, this can't get a careful review as one PR. This should ideally be 6-7 different PRs (at least), split based on theme (or even which section of the EIP text the PR tackles). I'll leave that up to you but a couple of guidelines.
This will save the maintainers a lot of review time while also making sure we get a chance to go through the proposed changes thoroughly. |
|
Thanks @gurukamath, that makes sense. I'll split this into smaller PRs, one or two related themes each, and open them one at a time, waiting for each to be reviewed and dealt with before opening the next. I've closed this one so only one part is open at a time (GitHub also wouldn't let me open a third PR here while this and #3916 were open). The table below is also at the top of this PR's description; I'll keep it updated there as the parts go in. Part 1 is #3939.
#3916 (the test-specs framework change, against |
Split into smaller PRs
Closed in favour of smaller PRs, opened one at a time (see the last comment). I'll keep this table updated as they go in.
APPROVEedge cases; sender and payer balance againstmax_costDescription
Adds tests for EIP-8141 rules that the suite didn't cover yet, found by going through the EIP text rule by rule and checking each against the existing tests (including the open draft PRs, to avoid duplicates). Every new test was checked by temporarily breaking the spec rule it targets and confirming it fails. The whole
eip8141_frame_transactionsdirectory fills on Bogota: 2,455 passed, 0 failed. Gas expectations are read off the bytecode under test and the fork's calculators (.state_cost/.refund/.execution_cost,frame_transaction_intrinsic_cost_calculator,call_value_stipend,GasConsumer); the onlyfork.gas_costs()reads left are single constants for charges no opcode makes (frame-entry andAPPROVEaccount creation) and precompile prices the framework does not model.It's large (+12.5k lines; 16 new test files, 9 extended). Happy to split it if that's easier to review: it divides by the areas below, with shared helpers first. Several of the files marked * also hold tests grouped into them by subject, so a split would go by file, not strictly by area.
helpers.py,signature_helpers.pytest_static_validity.py:test_gas_limit_cap_from_calldata_floor*[below_cap, above_cap](the frames now call a target and the floor lands exactly on the cap, sobelow_capis one byte under it, with a newat_capcase between), andtest_signature_constraints*[secp256k1_v_27, secp256k1_s_zero, p256_signer_mismatch](each now carries a signature that otherwise verifies, so only the rule under test rejects it).test_static_validity.py,test_admission_validity.py,test_raw_rlp_rejections.py,test_default_code_signatures.py,test_approve_balance.pys/v/rbounds for secp256k1 and P256; default code rejecting a missing entry, wrong scheme, wrong signer or explicit message; APPROVE balance atmax_costand one wei below, read when APPROVE runs; wrong chain id; frame-gas sum and calldata-floor caps; reservations for a second transaction in a blocktest_transient_storage.py,test_verify_frame_static.py,test_caller_origin.py,test_frame_opcodes_outside_frames.py,test_approval_edges.py,test_delegated_sender.py,test_batch_status.py,test_frame_environment.py,test_introspection.py,test_frame_transactions.py,test_target_resolution.py*CALLER/ORIGINper mode and depth; frame opcodes halting outside type 6; APPROVE edges (double payment approval, split approval, approval through CALLCODE, halt discarding the approval, default-code refusals); EIP-7702-delegated senders; atomic batch status; out-of-range introspection operands;GASPRICE/CALLVALUE/logs per frametest_frame_create.py,test_frame_selfdestruct.py,test_frame_opcode_gas.py,test_intrinsic_cost.py,test_payer_settlement.py,test_fee_budget.py,test_gas_settlement.py,test_state_gas.py,test_warmth.py* existing file, tests appended or tables extended (no existing test id renamed or removed).
Where no test was written. The EIP is silent, or EELS differs from the text. Raising these rather than pinning either reading:
nonce < 2**64, while EELS rejects2**64 - 1, and two existing tests pin EELS's bound.chain_id < 2**256, while EELS decodes it as 64-bit (invalid either way; only the error differs).max_priority_fee * max_gas) can exceed 2256, and nothing says they must not wrap. A test with a 2255 tip pins EELS's arbitrary-precision result.Also checked against a client: all fixtures at
1d798f927were run through Nethermind'snethteston itsbogota-devnet-2branch, with the open devnet-2 PRs (#15045, #14791, #15033) merged locally: blockchain 775/775, state 743/743, engine 766/775, transaction 144/162. None of the 27 failures changes block validity, and all were present before the first push: 2 are the one real Nethermind difference the new tests found — frame gas sums just below2**64, which the EIP allows, are rejected because the intrinsic gas is added in 64 bits (block validity is not affected; fix: NethermindEth/nethermind#15270); 22 are the test runner lacking a mapping from Nethermind's rejection message to the fixture's exception label (5 engine fixtures forINSUFFICIENT_MAX_FEE_PER_GAS, 16 raw-RLP and 1 nonce transaction fixtures; NethermindEth/nethermind#15274 adds the decode mappings); 3 engine fixtures report the block access list error before the transaction's own error, rejecting the block either way.Related: #3916 makes
fillalso check the raw-RLP cases here against EELS (today transaction fixtures aren't run through EELS). The two PRs don't depend on each other.Related Issues or PRs
eips/bogota/eip-8141, the head branch of feat(spec-specs,test-forks,tests): implement EIP-8141 frame transactions #3936, so these tests become part of feat(spec-specs,test-forks,tests): implement EIP-8141 frame transactions #3936 once merged. If feat(spec-specs,test-forks,tests): implement EIP-8141 frame transactions #3936 merges first, I'll retarget this PR toforks/bogota.cc @spencer-tb @gurukamath
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