Test Cases Tracker for EIP-8141: Frame Transaction #3358
Unanswered
gurukamath
asked this question in
Ideas
Replies: 2 comments 1 reply
1 reply
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
test_transfer_with_default_codeVERIFYframe approving execution and payment against the sender's signature entry, followed by aSENDERframe carrying10**17wei to a recipient EOAtest_contract_sender_approvesAPPROVEAPPROVE(0, 0, EXECUTION_AND_PAYMENT); aSENDERframe calls a target contract that writes storagetest_eoa_paymasterVERIFYframe approves execution only; a secondVERIFYframe targets the payer EOA and approves payment only, backed by the payer's signature entry; aSENDERframe calls the targettest_atomic_batch_rollbackLOG0frame and a reverting frame form an atomic batch after theVERIFYframe; theATOMIC_BATCH_FLAGplacement selects which frame terminates the batch:•
unrolls_executed_frames: the storage frame is flagged, so the reverting frame terminates the batch•
skips_remaining_frames: the reverting frame is flagged and runs first•
unrolls_executed_frames: the executed batch frame's state changes are unrolled; its receipt retains statusSUCCESSand gas used but logs are discarded•
skips_remaining_frames: the remaining batch frame is skipped with status0x2(SKIPPED) andgas_used=0test_sender_frame_before_approvalSENDERframe that runs before any frame has approved executionSENDERframe calling a target precedes theVERIFYframe that would approve executionTYPE_6_INVALID_FRAME_EXECUTION; target storage untouchedtest_verify_frame_revertsVERIFYframe revertsVERIFYframe withAPPROVE_NONEtargets a contract that executesREVERT(0, 0)TYPE_6_INVALID_FRAME_EXECUTIONtest_expiry_verifier_frameVERIFYframe withAPPROVE_NONEtargets the expiry verifier predeploy carrying an 8-byte big-endian expiry timestamp; aSENDERframe follows. The predeploy's genesis account is pinned in the post state so a missing predeploy fails loudly. Parametrized expiry:•
future_expiry: block timestamp + 1•
expiry_at_block_timestamp: exactly the block timestamp•
expired: block timestamp − 1future_expiry/expiry_at_block_timestamp: all frames succeed and the target executes•
expired: the predeploy reverts, which for aVERIFYframe invalidates the whole transaction withTYPE_6_INVALID_FRAME_EXECUTIONtest_txparamTXPARAMDEFAULTframe storesTXPARAM(selector), one selector per case:•
type•
nonce•
priority_fee•
max_fee•
max_blob_fee•
blob_count•
frame_count•
frame_index•
signature_count•
type: the frame transaction type•
nonce: 0•
priority_fee/max_fee: the transaction's fee fields•
max_blob_fee/blob_count: 0 (no blobs)•
frame_count: 2•
frame_index: 1•
signature_count: 1test_txparam_max_costTXPARAM's max cost selector against the payer's escrowTXPARAM(MAX_COST)with the gap between the sender's funding and itsBALANCEduring frame executiontest_txparam_sender_and_sig_hashTXPARAMTXPARAM(SENDER),ISZERO(TXPARAM(SIG_HASH)), andSIGPARAM(1, MSG)of an explicit-digest signature entrymsgreads back as the exact digesttest_frameparamFRAMEPARAMFRAMEPARAM(frame_index, selector), one selector per case:• against frame 0 (
VERIFY):mode,flags,allowed_scope,empty_data(data length 0),gas_limit,atomic_batch,status_of_earlier_frame• against frame 1 (the probe's own):
data_length,value,own_gas_limitSUCCESSstatus and the probe frame's own gas limit and data lengthtest_frameparam_resolved_targetFRAMEPARAMreports the resolved targetFRAMEPARAM(TARGET)of frame 0 (empty target) and frame 1 (the probe itself)test_frameparam_atomic_batch_setFRAMEPARAMATOMIC_BATCH_FLAG; a trailingDEFAULTframe terminates the batch (a flagged frame cannot be last). Probe reads both the dedicatedATOMIC_BATCHselector and the rawFLAGSATOMIC_BATCH_FLAGtest_frameparam_haltsFRAMEPARAMhalts exceptionally on invalid reads•
status_of_current_frame:FRAMEPARAM(1, STATUS)from frame 1 itself•
frame_index_out_of_bounds: frame index 2 in a two-frame transaction•
undefined_param: selector0x09VERIFYmodetest_introspection_haltsTXPARAM,SIGPARAM,FRAMEDATALOADandFRAMEDATACOPYhalt exceptionally on undefined selectors and out of bounds indices•
txparam_undefined_param•
sigparam_undefined_param•
sigparam_signature_index_out_of_bounds•
framedataload_frame_index_out_of_bounds•
framedatacopy_frame_index_out_of_boundstest_framedataloadFRAMEDATALOAD•
first_word: offset 0 of the probe frame•
tail_zero_padded: offset 32, straddling the end of the 40-byte data•
past_the_end: offset 64•
empty_frame_data: offset 0 of frame 0, which carries no datafirst_word: reads back exactly•
tail_zero_padded: the 8-byte tail reads back left-aligned and zero-padded•
past_the_end/empty_frame_data: read as zerotest_framedatacopyFRAMEDATACOPYMLOADtest_sigparamSIGPARAMARBITRARYentry with a 5-byte witness. Parametrized reads:•
secp256k1_scheme:SCHEMEof entry 0•
secp256k1_length:SIGNATURE_LENGTHof entry 0•
canonical_hash_msg:MSGof entry 0•
arbitrary_scheme:SCHEMEof entry 1•
arbitrary_length:SIGNATURE_LENGTHof entry 1SECP256K1, length 65,msgreads zero (canonical-hash entry)•
ARBITRARYentry: its scheme and the witness length 5test_sigparam_resolved_signerSIGPARAMSIGPARAM(RESOLVED_SIGNER)of the secp256k1 entry; a second probe attempts the same read against anARBITRARYentry, writing a marker firstARBITRARYentry halts the frame (protocol assigns no signer to bytes it does not validate), rolling back the markertest_sigparam_copy_arbitraryARBITRARYentry's raw signature bytes into memory viaSIGPARAM's copy operationARBITRARYwitness into memory and stores it; a second attempts the same copy against the protocol-validated secp256k1 entrytest_sender_is_warmDEFAULTframe runs a gas probe measuringBALANCE(sender); the frame involves the sender in no other waygas_usedpins the cold entry charge for the probe contract itself plus the probe codetest_coinbase_is_warmDEFAULTframe runs a gas probe measuringBALANCE(coinbase)test_frame_target_entry_chargeDEFAULTframes share the same non-pre-warmed target; the target's code ends with the parametrized outcome:•
success_carries_target_warmth: targetSTOPs•
revert_discards_target_warmth: targetREVERTs•
halt_discards_target_warmth: target halts onINVALID, gated on call data (first frame sends none and halts, second sends one byte and executes cleanly) so the receipts stay observable•
success: second frame pays only the warm access•
revert: warmth discarded, second frame pays cold again•
halt: frame forfeits its entire gas limit and discards the target's warmth, so the second frame pins a cold entry chargetest_warmth_carry_to_next_frameBALANCE(subject)then ends with the parametrized outcome; the next frame's probe measuresBALANCE(subject):•
success_carries: warmerSTOPs•
revert_discards: warmerREVERTs•
halt_discards: warmer halts onINVALIDsuccess: the frame commits its accesses to the warm journal shared across frames, next frame measures warm•
revert/halt: accesses discarded, next frame pays cold (the halting frame additionally forfeits its whole gas limit)test_warmth_from_inner_callCALLs a child that executesBALANCE(subject)and ends withchild_outcome; the outer contract then ends withframe_outcome; the next frame probesBALANCE(subject). Parametrized(child_outcome, frame_outcome):•
child_and_frame_succeed: (success, success)•
child_reverts: (revert, success)•
child_halts: (halt, success)•
frame_reverts: (success, revert)•
frame_halts: (success, halt)test_invalid_tx_fieldsVERIFYframe, default code) with one field overridden per case:•
nonce_overflow: nonce2**64 − 1, leaving no room for the post-execution increment•
priority_fee_above_max_fee: priority fee 11, max fee 10•
priority_fee_equals_max_fee: both 10 (boundary, valid)•
no_frames: empty frame list•
frame_count_above_max:MAX_FRAMES + 1frames•
frame_count_at_max: exactlyMAX_FRAMESframes (boundary, valid)•
blob_fee_without_blobs:max_fee_per_blob_gasset with an empty blob hash list•
invalid_blob_hash_version: blob hash with version byte 2•
blob_count_above_max:max_blobs_per_tx() + 1blob hashes•
nonce_overflow:NONCE_IS_MAX•
priority_fee_above_max_fee:PRIORITY_GREATER_THAN_MAX_FEE_PER_GAS•
no_frames/frame_count_above_max/blob_fee_without_blobs:TYPE_6_INVALID_FRAME_FORMAT•
invalid_blob_hash_version:TYPE_3_TX_INVALID_BLOB_VERSIONED_HASH•
blob_count_above_max:TYPE_3_TX_BLOB_COUNT_EXCEEDEDThe boundary variants are accepted. Sender nonce increments only on acceptance
test_frame_constraints•
default_frame_with_value: value on aDEFAULTframe•
verify_frame_with_value: value on aVERIFYframe•
sender_frame_with_value: value on aSENDERframe (valid — the empty target resolves to the sender, transferring to itself)•
approve_execution_frame_with_foreign_target: execution-approvingVERIFYframe targeting a foreign address•
approve_execution_frame_with_explicit_sender_target: same but explicitly targeting the sender (valid)•
atomic_flag_on_verify_frame•
atomic_flag_on_last_frame•
atomic_batch_followed_by_verify_frame•
atomic_batch_of_default_frames: batch with a trailingDEFAULTterminator (valid)•
frame_gas_sum_overflows: each frame's gas limit fits 64 bits but their total does notDecode-time rejections (out-of-domain values never construct, so the transaction never decodes):
•
undefined_frame_mode/undefined_frame_mode_high: mode 3 / 255•
reserved_frame_flag/reserved_frame_flag_high: flags 0x08 / 0xFF•
frame_gas_above_64_bits: frame gas limit2**64TYPE_6_INVALID_FRAME_FORMAT; the nearest-valid variants (sender_frame_with_value,approve_execution_frame_with_explicit_sender_target,atomic_batch_of_default_frames) acceptedtest_expiry_verifier_constraintsVERIFYframe targeting the expiry verifier predeploy•
expiry_data_empty/expiry_data_too_short/expiry_data_too_long: data of 0 / 7 / 9 bytes•
expiry_frame_with_flags: carriesAPPROVE_PAYMENT•
expiry_frame_with_value: carries value•
multiple_expiry_frames: two well-formed expiry frames in one transaction•
default_frame_targeting_expiry_verifier:DEFAULTframe targeting the predeploy with 7-byte data (valid — shape rules apply only toVERIFYframes, and a failing non-VERIFYframe does not invalidate the transaction)•
verify_frame_with_expiry_data_to_other_target:VERIFYframe with 7-byte data targeting a succeeding contract (valid — shape rules key on the predeploy's address)TYPE_6_INVALID_FRAME_FORMAT; the two off-target variants acceptedtest_signature_constraintssecp256k1 (a valid signature over an explicit digest, tampered in one component):
•
secp256k1_digest_entry: untampered (valid)• signature resized to 64 / 66 / 0 bytes
•
v= 2 / 27 (the legacy transaction encoding)•
r= 0 / at the curve order•
s= 0 / high-scomplement•
secp256k1_signer_mismatch: valid signature, explicit signer differs from what it recovers to•
secp256k1_wrong_key: empty signer (resolves to the sender) but signed with an unrelated key• signer of 19 / 21 bytes
Message shape (via
ARBITRARYentries, checked before scheme dispatch):•
msgof 1 / 31 / 33 bytes•
msg_all_zeros: reserved as the EVM-visible representation of the canonical-hash caseARBITRARY:
•
arbitrary_entry: bare 5-byte witness (valid)•
arbitrary_with_signer: carries a signerP256:
•
p256_valid_entry(valid)• signature of 127 / 129 bytes
•
r= 0 / at the curve order•
s= 0 / high-s•
p256_signer_mismatch: empty signer never matches the hash of the key words•
p256_not_on_curve: signer matches a (0, 0) key that is not on the curve•
p256_signature_over_different_digest: well-formed signature over a different digest than the entry'smsgDecode-time:
• undefined signature schemes 3 / 255
TYPE_6_INVALID_FRAME_FORMAT, cryptographic ones withTYPE_6_INVALID_SIGNATURE; the three valid entries acceptedtest_gas_limit_cap_from_frame_gasVERIFYframe sized so the derived gas limit lands:•
at_cap: exactly on the per-transaction gas cap•
above_cap: one above itat_capaccepted;above_caprejected withGAS_LIMIT_EXCEEDS_MAXIMUMtest_gas_limit_cap_from_calldata_floorDEFAULTframe carries zero-byte data driving the calldata floor to the cap boundary while the standard gas limit stays far below it:•
below_cap: the largest data length whose floor fits under the cap•
above_cap: one more bytebelow_capaccepted;above_caprejected withGAS_LIMIT_EXCEEDS_MAXIMUMtest_nonce_at_maximum2**64 − 2, one below the overflow bound, leaving room for the post-execution increment2**64 − 1test_raw_rlp_decode_rejectionsTransactionmodelTYPE_6_INVALID_FRAME_FORMATbefore any validation or execution runstest_bal_atomic_batch_writeSENDERframe flaggedATOMIC_BATCHwrites a storage slot; the following unflagged frame terminates the batch with the parametrized outcome:•
committed: the terminatorSTOPs•
unrolled: the terminatorREVERTsSUCCESSeven when the batch unrolls.•
committed: the slot appears as a storage change carrying the written value•
unrolled: the write is dropped from the BAL and the slot is re-filed as a bare storage read; post state shows the slot unwrittentest_bal_atomic_batch_skipped_frame_absentSKIPPEDwithgas_used=0; its target is asserted absent from the BAL (explicit exclusion), and its storage stays untouchedtest_bal_frame_revert_write_droppedSENDERframe calls a target that writes a storage slot and then executesREVERT(0, 0)FAILURE; the BAL carries no storage change for the target and lists the slot as a storage read; post state shows the slot unwrittentest_bal_sponsored_payer_and_senderVERIFYframe approves execution only; a secondVERIFYframe targets the payer EOA and approves payment, backed by the payer's signature entry; aSENDERframe writes storage in a target contract. The fee per gas is pinned to the genesis base fee so the payer's charge carries no priority tiptest_precompile_targetVERIFYframe targets, dispatching by address like a top-level callDEFAULTorSENDERframe (parametrized) targets theIDENTITYprecompile carrying parametrized input:•
no_input: empty data•
one_word: 32 bytes•
two_words: 33 bytesgas_usedpins the warm frame-entry access (precompiles seed the warm set) plusIDENTITY's input-dependent cost for the exact word counttest_precompile_target_rejecting_its_inputDEFAULTframe targetsBN254_ADDwith 128 bytes that are not a pair of curve pointsFAILUREwithgas_usedequal to its entire gas limittest_verify_frame_precompile_targetVERIFYframe targets a precompile: the empty code hash routes to the default code instead of dispatchingIDENTITY; the first frame approves both execution and payment, so dispatching the precompile instead of running the default code would leave the transaction validTYPE_6_INVALID_FRAME_EXECUTION; sender nonce pinned unchangedtest_delegated_target_entry_chargeDEFAULTframe targets an EOA delegated to aSTOPcontract; the delegate's warmth is parametrized:•
cold_delegate: no prior access•
warm_delegate: a preceding frame targets the delegate directly, paying its cold accessframe_entry_gas_calculator(delegated=True, delegation_warm=...): the target's cold access plus the delegate's cold or warm accesstest_delegated_to_precompile_targetDEFAULTframe carrying one word of input targets an EOA delegated toIDENTITYIDENTITY's per-word cost despite the input pins that no precompile ran (the delegate, a precompile, is pre-warmed)test_verify_frame_delegated_to_precompile_targetVERIFYframe's delegated target rather than running the default codeVERIFYframe approving nothing targets an EOA delegated toIDENTITY: the resolved code is empty, as for a codeless target, but the target itself holds a designation and so is not codelesstest_frame_entry_gas_boundaryVERIFYframe runs with its gas limit sized to the derived full frame cost — entry charges fromframe_entry_gas_calculatorplus the target code's cost, including the state gas anSSTOREspills into execution gas (a frame holds no reservoir) — and one below it. Parametrized(target shape × boundary side):•
plain_contract: cold storage-writing target•
delegated: target designating a storage-writing contract, adding the designation's access to the entry charge•
precompile:IDENTITYwith input, warm entry plus the input-dependent precompile cost×
exact/short_by_oneexact: the frame succeeds with receiptgas_usedequal to the full derived cost, and the target's effect (storage write / precompile output) lands•
short_by_one: the frame fails forfeiting its entire gas limit (gas_used= limit), leaving state untouched; the transaction itself stays valid and the sender's nonce incrementstest_bal_unaffordable_designation_absentSENDERframe targets an EOA delegated to a storage-writing contract, with gas limitframe_entry_gas_calculator(delegated=True) − 1— the most gas that still cannot afford the designation's accessAll reactions