Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Anvil evm_revert with the same snapshotId is inconsistent on subsequent calls #6463

Closed
1 of 2 tasks
Tracked by #8269
vlad-blana opened this issue Nov 29, 2023 · 4 comments
Closed
1 of 2 tasks
Tracked by #8269
Labels
C-anvil Command: anvil T-bug Type: bug

Comments

@vlad-blana
Copy link

vlad-blana commented Nov 29, 2023

Component

Anvil

Have you ensured that all of these are up to date?

  • Foundry
  • Foundryup

What version of Foundry are you on?

forge 0.2.0 (d7d2901 2023-11-29T00:25:43.341327400Z)

What command(s) is the bug in?

.\anvil.exe --fork-url "http://127.0.0.1:8547" --auto-impersonate

Operating System

Windows

Describe the bug

Reusing the same snapshot with evm_revert via JSON RPC works as expected the first time:

  • reverts the state
  • the block number is back to the one the evm_snapshot was called at
  • the memory used by new data seems to be freed

On subsequent calls the state is reverted, but the block number doesn't change and the new blocks can be fetched. The anvil process memory used increases and leads to dangerous memory leaks when enough transactions and blocks are mined in between evm_revert. The memory never goes down.

I suspect this could be fixed if the blocks get discarded just like after the first evm_revert call.

There's an aditional child issue, that I will come back to only after this issue is resolved since the cause might be different. After a while anvil doesn't answer back to rpc calls on the existing connection. Establishing a new connection works, but it's inconsistent with regular behavior of the live evm json rpc nodes.

I'm running anvil forking a local node - but it happens with any other remote node.
I'm communicating with it with ethers.js 6.8.0 in node.js.

Here's a demo of the issue. I've made it platform independent to the best of my abilities.
The README.md contains setup and run instructions, as well as the console output I get from running the code on my end.
Running it should yield the same results on your end.

It creates a snapshot one time.
Then loops 5 times

  • prints the iteration index and block number
  • prints USDT balances of a sender and receiver account before the transfer operation
  • sends 1000 USDT between 2 accounts and prints the iteration index
  • print the USDT balances again
  • calls evm_revert
  • waits 3 seconds for evm_revert to do its magic because it doesn't seem to be a sync command in my live tests with 100-30k transactions when it takes a few seconds for evm_revert or anvil_reset to finish the state transitions

This is the anvil command for the node fork used with the demo

anvil --fork-url "https://rpc.mevblocker.io" --fork-block-number 18679420 --auto-impersonate

It forks ethereum mainnet. The code is build around ethereum mainnet only, but the issue occurs on all evm networks I managed to play with.

I've disabled the ethers cache in the code to avoid its quirks and make it seem like it's related to it.

2023_11_29_foundry_anvil_same_snapshot_block_number_bug.zip

Expectations

  1. The block number should be 18679420 in every iteration

  2. fetching blocks after 18679420 should not be possible

  • currently it is possible
  1. Memory should not increase after evm_revert
  • it should actually decrease if any data gets erased in the process
@vlad-blana vlad-blana added the T-bug Type: bug label Nov 29, 2023
@gakonst gakonst added this to Foundry Nov 29, 2023
@github-project-automation github-project-automation bot moved this to Todo in Foundry Nov 29, 2023
@mattsse
Copy link
Member

mattsse commented Dec 1, 2023

On subsequent calls

can you elaborate here. repeated calls to evm_revert with the same id?

@vlad-blana
Copy link
Author

vlad-blana commented Dec 1, 2023

After calling the evm_snapshot which returns a snapshot id:

Let's say you do one transaction, or 100. It doesn't matter.
You do no snapshots in the meantime.

Then you call evm_revert -> everything is back to the state when the evm_snapshot was generated and the new blocks are deleted. And the process memory is released.

Then you repeat the same transactions again.

You call evm_revert the 2nd time with the same snapshot id -> only the balances and contracts are reset, but the blocks are not deleted.

Then you do the same transactions again - they will work because the state is like the initial state (the surplus blocks don't do anything)

You call evm_revert again for the 3rd time with the same snap id-> the state is back to the initial state, but all the blocks after the first evm_revert are still present.

The undesired blocks pile up after the 1st evm_revert, no matter how many times one calls evm_revert with the same snapshot id, while the contract storage, account balances state gets properly reset.

And on and on again until you run out of memory.

What's interesting is that the actual evm_revert call increases the memory too.

But let's ignore the memory problem.

What matters is consistency which is lacking in the current feature state.

@mattsse
Copy link
Member

mattsse commented Dec 10, 2023

there was indeed a bug that caused the inconsistency wrt to state: should be fixed by #6486

evm_revert deletes the snapshot, this mimics the OG ganache implementation:

https://github.com/trufflesuite/ganache/blob/ef1858d5d6f27e4baeb75cccd57fb3dc77a45ae8/src/chains/ethereum/ethereum/RPC-METHODS.md#evm_revert

though we will make this optional:

#6366 (comment)

@zerosnacks
Copy link
Member

Marking this as completed

Feel free to re-open if this is still an issue

@jenpaff jenpaff moved this from Todo to Completed in Foundry Sep 30, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-anvil Command: anvil T-bug Type: bug
Projects
Archived in project
Development

No branches or pull requests

3 participants