feat: add E2E tests for EIP-1153 (TLOAD/TSTORE transient storage)#9
feat: add E2E tests for EIP-1153 (TLOAD/TSTORE transient storage)#9
Conversation
Introduces TestTSTORE_TLOAD_Roundtrip which stores 0xDEADBEEF into transient slot 0 via TSTORE and retrieves it via TLOAD, asserting revert pre-INTERSTELLAR (invalid opcode) and correct output post-fork.
…ng tests Adds TestTransientStorage_DoesNotPersistToSLOAD (5a) to verify that TSTORE and SLOAD operate on separate namespaces, and TestTransientStorage_ClearedBetweenTransactions (5b) to verify transient slots are zeroed at transaction boundaries.
…ct gas total to 118
…t cost (103 gas, not 118)
BenderVeChain
left a comment
There was a problem hiding this comment.
Review
Retracted
After discussion with Tony Li — finding #1 is withdrawn. Init-code execution via nil-To InspectClauses is correct: TLOAD/TSTORE are valid within init-code post-fork, and the gas measurements are accurate. No issue there.
Request Changes
TestTransientStorage_ClearedBetweenTransactions — use receipt block ID instead of "best"
// Current (racy)
results, err := client.InspectClauses(tloadCallData, thorclient.Revision("best"))Using "best" is racy in a 3-node network. Between WaitForReceipt returning and InspectClauses executing, the best block on the queried node may have advanced (or not yet caught up). The simulation should be pinned to the exact block in which the TSTORE tx was mined.
The receipt already carries Meta.BlockID:
// Fix
results, err := client.InspectClauses(tloadCallData, thorclient.Revision(tstoreReceipt.Meta.BlockID.String()))This guarantees the simulation runs against the state at the block immediately after the TSTORE tx, which is the correct semantics: verify that transient storage written in that tx is not visible to a new execution context at the same block height.
Confirmed Good
- Bytecode correctness: ✅ TSTORE/TLOAD opcodes, stack order, MSTORE layout, RETURN sizes all accurate
- STOP terminator in gas tests to avoid code-deposit charge: ✅ correct and well-commented
- Pre/post-fork revert pattern: ✅ consistent across all tests
- Namespace isolation test (
DoesNotPersistToSLOAD): ✅ most valuable test in the set RunTestMain2-arg signature: ✅ matches currenthelper/testmain.go- Inline bytecode annotations: ✅ excellent clarity
Using "best" is racy on a multi-node network — the simulated tx must run against the state at the block where the TSTORE tx was mined, not whatever block happens to be best at query time.
BenderVeChain
left a comment
There was a problem hiding this comment.
The requested change is in — tstoreReceipt.Meta.BlockID.String() pins the simulation to the exact block the TSTORE tx landed in. No further issues.
Full verification:
- Bytecode: all opcodes, stack order, byte offsets, and JUMPDEST target verified by hand — correct throughout
transientIsolationRuntimedispatcher:CALLDATASIZE → ISZERO → JUMPIcorrectly routes empty calldata to TSTORE handler (byte 16) and non-empty to TLOAD handler (byte 5)- TSTORE stack order:
PUSH2 0xCAFEthenPUSH1 0x00→ TSTORE pops key=0, value=0xCAFE ✅ - initcode header: 12 bytes, runtime offset 0x0C matches
PUSH1 0x0C✅ - Gas arithmetic: TSTORE=106, TLOAD=103 both correct (STOP avoids code-deposit charge) ✅
RunTestMain2-arg signature matches current helper ✅
LGTM.
Summary
tests/eip1153package with full E2E coverage for EIP-1153 transient storage opcodes (TSTORE/TLOAD)Tests Added
Test Plan
make testgo vetpasses, no linter issues