1 of 33

eth_simulateV1

S1na, OlegJakuskin, Micah, Lukasz Rozmej, Epheph, Killari

Oleg, Killari

https://github.com/ethereum/execution-apis/pull/484

EP484

2 of 33

https://github.com/ethereum/execution-apis/pull/484

3 of 33

What is eth_simulateV1?

  • New RPC method to replace eth_call and the non-standard, alchemy forking, Flashbots eth_callBundle etc
  • Simply: allows you to simulate multiple transactions and adds more powerful features

4 of 33

5 of 33

eth_simulateV1 Core Features

  • Calls are split to blocks, block simulation!
    • We can define block variables!
  • State overrides
  • We can replace code and balance of accounts!
  • ECrecover opcode override
  • Permit message fake signing!
  • Event logs & ETH Transfer logs (traceTransfers = true/false)�- Like ERC20 transfer logs, we can also follow ETH

6 of 33

  • Simulate calls inside blocks
  • You can override blocks, and set variables for them
  • You can override existing blocks, or create new block all together
  • The new blocks can contain calls
  • If some contract requires certain amount of time or blocks to pass, not an issue for simulation!

7 of 33

2) Replace account state

  • You can replace accounts:
    • Balance
    • Code
    • Nonce
    • State
    • StateDiff
    • Move Precompile�
  • Replace accounts code and call it right away without needing to deploy contract to be called

8 of 33

3) ECRecover precompile override

  • You can replace ECrecover with custom code and move the original to a new address

9 of 33

3) Precompile override - ECRecover

  • MovePrecompileToAddress can be used to move ECRecover to a new address
  • Precompiles code can be overridden with code
  • State override can be used to modify the variables dynamically

Mapping

Move ecrecover

Replace code

ECRecover

10 of 33

Use Case: Swap USDC -> ETH Permit message faking

Get The Interceptor: https://www.dark.florist/

11 of 33

12 of 33

13 of 33

14 of 33

3) Precompile override - The query itself

{

"jsonrpc": "2.0",

"id": 4993,

"method": "eth_simulateV1",

"params": [

{

"blockStateCalls": [

{

"calls": [

{ ... approve(address,uint256) ...},

{ ... Uniswap swap transaction ... },

],

"stateOverrides": {

"0x0000000000000000000000000000000000000001": {

"state": {

"0x259bff9b47742e0b81631440ff18b8f1b584a8bc37ef684764aeb20b8bca6068": "0x000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa96045"

},

"code": "ECRECOVER OVERRIDE BYTECODE",

"movePrecompileToAddress": "0x0000000000000000000000000000000000123456"

}

},

}

],

"traceTransfers": true,

"validation": false

},

"0x11b1ebd"

]

}

  • Approve Transaction

2) Permit message

3) Swap Transaction

15 of 33

The outcome of the whole query:

16 of 33

4) Event Logs + ETH transfer logs

  • In addition of showing normal logs you also get eth transfers
  • Enables users to follow where the ETH is going similar to ERC20’s
  • ETH logs are ERC20 logs that come address 0xeeeeeee...��Uniswap swap ETH -> WBTC:

17 of 33

4) ETH transfer logs

"logs": [

{

"address": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",

"topics": [

"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",

"0x000000000000000000000000b57ab8767cae33be61ff15167134861865f7d22c",

"0x000000000000000000000000ced10840f87a2320fdca1dbe17d4f8e4211840a8"

],

"data": "0x0000000000000000000000000000000000000000000000000f43fc2c04ee0000",

"blockNumber": "0x11b1f65",

"transactionHash": "0xdc7f600bef3a06b0864572f85634a4ffa00b8c4318949168727d89b4560b24b0",

"transactionIndex": "0x0",

"blockHash": "0x673fb12c793b9b118d6effdd74e9491a04e1666551f19bdb49fa95b9e134acaf",

"logIndex": "0x0",

"removed": false

}

]

18 of 33

Example: Governor Bravo execution simulation

  • Replace governance contracts timelock contract
  • Call the governance contract and get the outcome
  • ETH logs show nicely on where ETH goes after the execution

19 of 33

{

"jsonrpc": "2.0",

"id": 204,

"method": "eth_simulateV1",

"params": [

{

"blockStateCalls": [

{

"calls": [

{

"type": "0x2",

"from": "0xdbd38f7e739709fe5bfae6cc8ef67c3820830e0c",

"nonce": "0x0",

"maxFeePerGas": "0x0",

"maxPriorityFeePerGas": "0x0",

"to": "0xb57ab8767cae33be61ff15167134861865f7d22c",

"value": "0x0",

"input": "execute timelock",

"chainId": "0x1",

"accessList": []

}

],

"stateOverrides": {

"0xb57ab8767cae33be61ff15167134861865f7d22c": {

"stateDiff": {},

"code": "Timelock contract replacement bytecode"

}

}

}

],

"traceTransfers": true,

"validation": false

},

"0x11b1f64"

]

}

{

"jsonrpc": "2.0",

"id": 204,

"result": [

{

"number": "0x11b1f65",

"hash": "0x673fb12c793b9b118d6effdd74e9491a04e1666551f19bdb49fa95b9e134acaf",

"timestamp": "0x65509098",

"gasLimit": "0x1c9c380",

"gasUsed": "0xbe97",

"feeRecipient": "0x4838b106fce9647bdf1e7877bf73ce8b0bad5f97",

"baseFeePerGas": "0x429978e78",

"prevRandao": "0x0000000000000000000000000000000000000000000000000000000000000000",

"calls": [

{

"returnData": "0x",

"logs": [

{

"address": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",

"topics": [

"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",

"0x000000000000000000000000b57ab8767cae33be61ff15167134861865f7d22c",

"0x000000000000000000000000ced10840f87a2320fdca1dbe17d4f8e4211840a8"

],

"data": "0x0000000000000000000000000000000000000000000000000f43fc2c04ee0000",

"blockNumber": "0x11b1f65",

"transactionHash": "0xdc7f600bef3a06b0864572f85634a4ffa00b8c4318949168727d89b4560b24b0",

"transactionIndex": "0x0",

"blockHash": "0x673fb12c793b9b118d6effdd74e9491a04e1666551f19bdb49fa95b9e134acaf",

"logIndex": "0x0",

"removed": false

},

{

"address": "0xb57ab8767cae33be61ff15167134861865f7d22c",

"topics": [

"0xa560e3198060a2f10670c1ec5b403077ea6ae93ca8de1c32b451dc1a943cd6e7",

"0x3e6eeeeced3a3b85bb1f37bb260f823dca5e1013558c4d93984762be0154ff21",

"0x000000000000000000000000ced10840f87a2320fdca1dbe17d4f8e4211840a8"

],

"data": "0x0000000000000000000000000000000000000000000000000f43fc2c04ee0000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",

"blockNumber": "0x11b1f65",

"transactionHash": "0xdc7f600bef3a06b0864572f85634a4ffa00b8c4318949168727d89b4560b24b0",

"transactionIndex": "0x0",

"blockHash": "0x673fb12c793b9b118d6effdd74e9491a04e1666551f19bdb49fa95b9e134acaf",

"logIndex": "0x1",

"removed": false

}

],

"gasUsed": "0xbe97",

"status": "0x1"

}

]

}

]

}

20 of 33

Existing implementations of eth_simulateV1 EP484

Nethermind: https://github.com/NethermindEth/nethermind/ (95% of features merged into master)

Geth: https://github.com/s1na/go-ethereum/tree/multicall

�More implementations needed! Join us: https://github.com/ethereum/execution-apis/pull/484

21 of 33

Implementation details

22 of 33

Simplified

  • (1) Take request parent block
  • Apply user mock updates to chain
    • Accounts
    • Contract code and state
  • Based on that fill in the transactions
  • Process block
  • Trace results
  • GoTo (1)

* This is basically in part turning the Ethereum chain client into a multitenant app for many users to try on many chain versions

23 of 33

System changes

  • New Overlays for data access
  • Updates to EVM
  • Updates to JSON parsing

24 of 33

State updates

We allow to set:

  • Contract State
  • Users State

What eth_call second argument does, yet on per processed block level.

Overlay Updating DBs is hard, updating caching in-memory only ones combined with on disk is harder.

25 of 33

DB + Caches

  • All we create is single-use tmp data
  • We overlay a lot
    • Tree
    • State
    • CodeInfo
    • Precompiles

26 of 33

EVM updates

Users can override Precompiles:

  • A user can override precompiles with his code
  • A user can redirect precompiles to user-defined locations

*Some implementations may allow general smart contract redirects

Users get special logs…

27 of 33

Extra Logs!

  • To produce RPC call results we use tracers
  • We have special logging for transfers of ETH between users on call
    • This touches EVM implementation
    • This touches Tracers
  • For end user it looks like extra emitted event

28 of 33

RPC updates

Object data structures

Parsing of nested dictionaries/maps

Configuration Limits on max blocks, gas, request size

29 of 33

Validation Mode

  • Eth_simulate allows users to run in validation == on mode! With sane rules on default parameters setup
  • This allows transactions to be validated as if they are processed for block inclusion
  • We set sain defaults and produce a lot of logs so users could fill in as less as possible and get as complete picture of execution as possible

30 of 33

Skipped stuff

Q: What do we do when user asks for block 1, 100, 1000?

A:

  • We run each block,
  • limit them to 256 by default in changeable node config
  • We do no skippers - so it will be 1, 2,... 99, 100; use timestamps for cheaper simulations.

31 of 33

Development support

32 of 33

Eth_simulate overall

  • New RPC method to simulate chain forking/mocking/experiments
  • Is quite far from eth_call
  • Has a potential for use in MEV research, contract testing, complex “on-chain” simulations without consequences

https://github.com/ethereum/execution-apis/pull/484

33 of 33

Discussion

We want users to explore tree of possibilities over time and blockspace!