You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
We want to request for a new rpc endpoint eth_callMany, which provides a flexible interface for users to simulate arbitrary number of transactions at an arbitrary blockchain index. It's extremely useful for getting the intermediate evm state of a blockchain. For regular eth_call, we could only get the end state after all of the transactions in that block. We want an api that's similar with eth_callBundle but enables the simulations of transactions in the middle of a block. Here is the specification for this API.
Specification
eth_callMany
Executes a list of bundles (a bundle if a collection of transactions), without creating transactions on the blockchain. The eth_callMany method can be used similarly as eth_call besides three major distinctions.
The method supports simulating transactions at a intermediate state of a block (e.g. inheriting the block state after executing a portion of transactions in that block)
The method supports simulating multiple transactions with sequential dependencies. The transactions could be separated into different blocks.
The method supports overwrites for block headers (e.g. coinbase, difficulties, blockHash, and etc.)
Parameters
The method takes 3 parameters: a list of bundles where each bundle has a list of unsigned transactions objects and an optional setting for the block header, a simulation context which includes the block identifier, the transaction index, and the standard state overrides, and an optional timeout.
Bundles - a list of Bundle
Bundle
transactions: A list of unsigned transaction call objects following the same format as eth_call.
blockOverride: An optional overwrite of the block header
Field
Type
Bytes
Optional
Description
BlockNumber
Object
NA
Yes
Block number. Defaults to the block number of the first simulated block. Each following block increments its block number by 1
BlockHash
Dict[blockNumber, Hash]
NA
Yes
A dictionary that maps blockNumber to a user-defined hash. It could be queried from the solidity opcode BLOCKHASH
Coinbase
Address
20
Yes
The address of miner. Defaults to the original miner of the first simulated block.
Timestamp
Object
8
Yes
The timestamp of the current block. Defaults to the timestamp of the first simulated block. Each following block increments its timestamp by 1.
Difficulty
Object
4
Yes
The difficulty of the current block. Defaults to the difficulty of the first simulated block.
GasLimit
Object
4
Yes
The gas limit of the current block. Defaults to the difficulty of the first simulated block.
BaseFee
Object
32
Yes
The base fee of the current block. Defaults to the base fee of the first simulated block.
blockNumber : Quantity|Tag - Block Number or the string latest or pending.
The block number is mandatory and defines the context (state) against which the specified transaction should be executed. It is not possible to execute calls against reorged blocks.
transactionIndex : Number - The transaction index of the simulated transactions
The transaction index is optional. The default value of the transaction index is -1, which would place the simulated transactions after the entire block.
For some AMM pools, there might be multiple swap transactions for a pariticular pool in one block. Taking Uniswap V2 as an example, it's impossible to get the intermediate reserves of the pool using getReserves() function call. This is a toy example of how users might be able to use the new rpc call to get the intermediate states of a smart contract. The second transaction is the demonstration of how users might change the block header.
reserve_tx = {
"to": "0xB4e16d0168e52d35CaCD2c6185b44281Ec28C9Dc", // address of WETH/USDC Uniswap V2 Pool
"gas": "0x13880",
"maxPriorityFeePerGas": "0x59682f00",
"maxFeePerGas": "0x28ade5e73c",
"data": "0x0902f1ac", // function selector for getReserves()
}
blockNum_tx = {
"to": "0x0000000000000000000000000000000000000000",
"gas": "0x13880",
"maxPriorityFeePerGas": "0x59682f00",
"maxFeePerGas": "0x28ade5e73c",
"data": "0x7f6c6f10" // function selector for getBlockNum() from the EVMContext contract
}
params = [
[{"transactions": [reserve_tx, blockNum_tx], "blockOverride":{"blockNumber": "0xe39dd0"}}],
{"blockNumber": "0xe39ddf","transactionIndex": 234},
{"0x0000000000000000000000000000000000000000": {"code": EVMContext.deployedBytecode}
]
// EVMContext is a contract that can query the block context
$ curl --data '{"method":"eth_callMany","params":params,"id":1,"jsonrpc":"2.0"}' -H "Content-Type: application/json" -X POST localhost:8545
{
"id" : 1,
"jsonrpc": "2.0",
"result": [[{"value": "0x000000000000000000000000000000000000000000000000000048fc0e88a9d600000000000000000000000000000000000000000000092227c18803e8d401a500000000000000000000000000000000000000000000000000000000629e6eed"}, {"value": "0x0000000000000000000000000000000000000000000000000000000000e39dd0"}]]
}
The result of the first call is the intermediate reserves of the WETH/USDC Uniswap V2 Pool before the 234th transaction. The result of the second call is the overwritten block number from the block override.
debug_traceCallMany
The specification for debug_traceCallMany is quite similar with eth_callMany and we follow the go-ethereum's standard for the trace config.
Rationale
We want to request for a new rpc endpoint
eth_callMany
, which provides a flexible interface for users to simulate arbitrary number of transactions at an arbitrary blockchain index. It's extremely useful for getting the intermediate evm state of a blockchain. For regulareth_call
, we could only get the end state after all of the transactions in that block. We want an api that's similar witheth_callBundle
but enables the simulations of transactions in the middle of a block. Here is the specification for this API.Specification
eth_callMany
Executes a list of bundles (a bundle if a collection of transactions), without creating transactions on the blockchain. The
eth_callMany
method can be used similarly aseth_call
besides three major distinctions.The method supports simulating transactions at a intermediate state of a block (e.g. inheriting the block state after executing a portion of transactions in that block)
The method supports simulating multiple transactions with sequential dependencies. The transactions could be separated into different blocks.
The method supports overwrites for block headers (e.g. coinbase, difficulties, blockHash, and etc.)
Parameters
The method takes 3 parameters: a list of bundles where each bundle has a list of unsigned transactions objects and an optional setting for the block header, a simulation context which includes the block identifier, the transaction index, and the standard state overrides, and an optional timeout.
Bundles
- a list of Bundletransactions
: A list of unsigned transaction call objects following the same format aseth_call
.blockOverride
: An optional overwrite of the block headerBLOCKHASH
Object
- Simulation ContextblockNumber :
Quantity|Tag
- Block Number or the stringlatest
orpending
.transactionIndex :
Number
- The transaction index of the simulated transactionsExample:
Object
- State OverridesThe state override set is an optional address-to-state mapping, which follows the
eth_call
standard.Example:
Number
- TimeoffThe upper limit running time for the simulations in milliseconds. Defaults to
5000
milliseconds.Return Values
The method returns a list of list of
Binary
containing either the return value of the executed contract call or the reverted error code.Simple Example
Example Usage
For some AMM pools, there might be multiple swap transactions for a pariticular pool in one block. Taking Uniswap V2 as an example, it's impossible to get the intermediate reserves of the pool using
getReserves()
function call. This is a toy example of how users might be able to use the new rpc call to get the intermediate states of a smart contract. The second transaction is the demonstration of how users might change the block header.The result of the first call is the intermediate reserves of the WETH/USDC Uniswap V2 Pool before the 234th transaction. The result of the second call is the overwritten block number from the block override.
debug_traceCallMany
The specification for
debug_traceCallMany
is quite similar witheth_callMany
and we follow the go-ethereum's standard for the trace config.Implementation
We have a proof-of-concept implementation at https://github.com/hrthaowang/erigon/tree/callIntraBundleAlpha. We'd love to hear some feedbacks on this specification from the Erigon's team and we are happy to upstream it.
The text was updated successfully, but these errors were encountered: