fix(runtime): exact-slot eth_getStorageAt, eth_getCode fallback for create2, and receipt-poll retry - #31
Merged
Conversation
…create2, and receipt-poll retry
km631
approved these changes
Jun 2, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Three independent runtime/bridge fixes surfaced while running the OZ tron-contracts suite against TRE. Together they clear ~25 deterministic failures (proxy/upgradeable + create2) and stop a transient socket drop from cascading an entire test worker.
1.
stubProvider.getStorage— read the EXACT slot viaeth_getStorageAtgetStoragePOSTeddebug_storageRangeAt(0, 0, addr, slot, 1)to/treand returnedObject.values(storage)[0]— i.e. the FIRST slot the node yields, not the requested one (java-tron'sstorageRangeAtdoesn't filter to the key). So ERC-1967 reads came back as slot 0:getAddressInSlot(proxy, ImplementationSlot)returned the implementation'svaluefield (10/100/42) instead of the implementation address.This cascaded:
TransparentUpgradeableProxy's tests read the ProxyAdmin address from the admin slot (a deliberate TVM workaround), got garbage, then impersonated the wrong address — so every admin-gatedupgradeToAndCallreverted withdata=0xandproxyAdmin.owner()reverted ascall reverted (data=0x).Fix: read the exact slot via
eth_getStorageAt(hexAddr, slotHex, 'latest')on/jsonrpc(the same endpointmaybeAutoRegisterContractuses foreth_getCode), plus the EVM-predicted → TVM-actual remap thatgetCode/getBalancealready apply, and normalize the result withzeroPadValue(..., 32).2.
stubProvider.getCode— fall back toeth_getCodefor CREATE2-opcode contractsgetContractreads ContractStore, which doesn't contain contracts deployed via the CREATE2 opcode (e.g. RelayedCall's assembly-create2relayer, or OZ Clones) — those live in CodeStore. WhengetContractreturns empty, fall back toeth_getCodeon/jsonrpc, which reads CodeStore. Fixesprovider.getCode(relayer)returning0x.3.
wait.js _getInfoBigSafe— retry transient socket errors on the receipt pollThe receipt poll did a bare
fetch+resp.text()with no retry, unlikerpcCall(which already retries viaisTransientFetchError). A G1GC stop-the-world late in a long run drops the keep-alive socket →TypeError: fetch failed/ "other side closed" → the test fails. Worse, since every later fixture'swaitForReceipt(andrefundSigners) hits the same node, one drop cascades into failing the rest of the worker. Wrap the fetch+body-read in the same single-retry-with-100ms-backoff and exportisTransientFetchErrorfromcheatcodes.jsfor reuse. (Resilience for transient drops; node-level memory pressure is a separate, host-side concern.)Files
src/runtime/ethers-bridge.js—getStorage(eth_getStorageAt),getCode(eth_getCode fallback)src/runtime/wait.js—_getInfoBigSafetransient retrysrc/runtime/cheatcodes.js— exportisTransientFetchError