Skip to content
This repository has been archived by the owner on Feb 26, 2024. It is now read-only.

debug_storageRangeAt fails to find storage when the slot was created earlier in the same block #3338

Closed
haltman-at opened this issue Jul 6, 2022 · 1 comment · Fixed by #3470
Assignees

Comments

@haltman-at
Copy link
Contributor

Issue

In some cases, when the transaction index is greater than 0 (i.e. you're not looking at the first transaction in a block), debug_storageRangeAt will fail to find storage that was there at the start of the transaction.

This doesn't happen in all cases. If there was storage at that slot at the start of the block, it seems like it works fine; it will correctly report the storage for that index. If however there was no storage at that slot at the start of the block, but storage was set in transaction 0, then doing debug_storageRangeAt with index 1 will fail to find the storage that was set there in transaction 0.

(At least, that's how the problem looks to me.)

Reproduction steps

I found this using the solc8-magic-square project in the solidity-test-cases repo, but I'll admit that this would probably be more easily reproduced with a SimpleStorage contract. So, modify as appropriate. The relevant fact here is that doing generateMagicSquare(n) will set storage slot 0 to the number n, at least when n is small and odd (you might want to use SimpleStorage instead if you don't like being restricted to small odd numbers :P ).

I compiled the project. I ran ganache -p 7545 -b 5. I then did truffle migrate to migrate the project, then truffle console. I then did the following:

it = await MagicSquare.deployed()
it.generateMagicSquare(1), it.generateMagicSquare(3) //send both txs, hope they end up in same block
block = await web3.eth.getBlock(/* block number I saw in output */)
block //confirm there are exactly two txs in the block
promisify = require("util").promisify
provider = web3.currentProvider
send = promisify(provider.send.bind(provider))
slothash = web3.utils.soliditySha3("0x" + "00".repeat(32))
await send({ jsonrpc: "2.0", method: "debug_storageRangeAt", id: Date.now(), params: [block.hash, 0, it.address, slothash, 1]}) //no storage returned, as expected
await send({ jsonrpc: "2.0", method: "debug_storageRangeAt", id: Date.now(), params: [block.hash, 1, it.address, slothash, 1]}) //no storage returned... uh-oh!

No storage was returned for index 1, despite the slot having been set in index 0. If you do an eth_getStorageAt for the block, you'll be able to see that the slot is correctly set to 3 at the end of the block.

I also tested this with three transactions in the block instead of two; the result was that no storage was returned for any of the three indices.

Non-reproduction steps

I also did the same thing, but with an extra step of doing it.generateMagicSquare(5) in a separate block before doing the two transactions above. In this case, the problem does not occur; the first debug_storageRangeAt shows the correct value of 5, and the second debug_storageRangeAt shows the correct value of 1. The problem only seems to occur when there was no storage present at that slot at the beginning of the block.

(Of course, it's possible I have the exact conditions of the bug incorrect, but I thought this was worth pointing out all the same.)

Environment

Version: This problem probably exists in all released versions of Ganache 7, since it exists on both 7.0.0 and on 7.3.2.

@davidmurdoch
Copy link
Member

I think you're right. It looks like we only consider keys that we've seen before the block that the transaction is in. Our tests initialize all slots upon deployment, so we missed this.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
Status: Done
Development

Successfully merging a pull request may close this issue.

2 participants