-
Notifications
You must be signed in to change notification settings - Fork 20.3k
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
Batch eth_getStorageAt #23925
Comments
Okay, just discovered eth_getProof.... but this seems to take quite a bit of time just to get 3 variables (~1.2ms).. |
You can also use a JSON-RPC batch request. While this may still incur some internal overhead for each storage slot, it will at least save the overhead of sending the requests. |
I'm using go & I"m calling "eth_getStorageAt" via an rpclient (i..e. rpclient.CallContext). I can write my own batch request but I believe these requests are still handled one by one internally. My understanding is that a new stateDB and stateObj has to be created for every request, so I'm looking to create a new function (i.e. getBatchStorageAt, GetBatchState, GetBatchCommitedState...) which will return an array of storage variables based on an array of indexes for 1 address. |
I understand you are talking about creating a new method here, just trying to avoid it. Let's explore the existing alternatives before adding a new RPC method. If the performance of RPC batch is not enough for you, you can also get multiple slots using |
This step should be kind of cheap because a lot of things are cached internally. I'd prefer you try the RPC batch first and check if the performance is good enough for your use case. |
Fair point, I'll measure the performance of all-ready available methods before going forward with creating new methods. With Eth_Call, not too clear about the stateDiff format as it's not given in the examples, would you know what the format for that parameter is? (i.e. "stateDiff": {"0x0000000000000000000000000000000000000001": {"code": "0x6080604052600760005260206000f3fe"}} ) ? |
@FeurJak , could your batching needs be met with their GraphQL api? |
This is the best graphql query I could come up with for re this issue: query slots($blocknum: Long!, $addr: Address!, $key0: Bytes32!, $key1: Bytes32!, $key2: Bytes32!) {
slot0: block (number: $blocknum) {
account(address: $addr) { storage (slot: $key0)}
},
slot1: block (number: $blocknum) {
account(address: $addr) { storage (slot: $key1)}
},
slot2: block (number: $blocknum) {
account(address: $addr) { storage (slot: $key2)}
}
} With the variables being something like (example is a random contract from Goerli): {
"blocknum": "6004069",
"addr":"0xD3909f56dFb3B6F11Fc0d82Ef6022C6485EB0AE0",
"key0":"0x0000000000000000000000000000000000000000000000000000000000000003",
"key1": "0x7461cd233bf72e6c1fab8f2ffafce9cd48c96e1b422444c78aeae2cdd60843c8",
"key2": "0x7461cd233bf72e6c1fab8f2ffafce9cd48c96e1b422444c78aeae2cdd60843c9"
} This could've been re-written to become a bit shorter had graphql supported parameterized fragments (graphql/graphql-spec#204). Right now this is what we're stuck with which sucks a bit if you have a dynamic and variable list of slots you want to query each time. You'll have to do some string juggling to construct the query. I'm going to try that next and compare the performance with a doing several |
Surprisingly for large numbers of storage slots requested GraphQL can be slower than sending a series of separate JSON-RPC requests. I wrote a script which gets the prestate for a block, turns that into an access-list and then does first: a series of
|
Sorry for not replying to you guys, had no idea that this thread was still alive. I unfortunately can't go down the GraphQL route for my application.
Current solution is very quick. |
@FeurJak I'm trying to find the fastest way to get a batch of storage values without having to add a new method to the API and I kinda hijacked your thread to share the results. Sorry about that :) Feel free to mute the thread if you're not interested in this anymore. By splitting the storage slots and doing multiple GraphQL queries (say each with 100 slots) I managed to gain a 3-5x speedup compared to JSON-RPC. I updated the gist with the new script if anyone's interested. 3-5x is still not the speed-up I was hoping for so I'll keep the thread open for now in case I find another optimization. |
@s1na I'm very much interested ! I think the batch storage lookup requirement would be needed by many others and the GraphQL looks to be a viable solution without adding a new method to the API. |
@s1na I am curious as to why it would provide a 3-5x speedup compared to JSON-RPC though. |
@s1na Did you find out where the slowdown in big queries comes from? I find it surprising that this splitting of queries is necessary. |
@fjl almost the whole time is spent here: https://github.com/graph-gophers/graphql-go/blob/eae31ca73eb3473c544710955d1dbebc22605bfe/graphql.go#L212. First loop of the Validation function. @FeurJak well GraphQL has turned out to be much faster than JSON-RPC in many cases, e.g. ~100x in an experiment I did for fetching receipts for a range of blocks. Mostly because you're packing in a large number of requests in one query and avoiding all the network latency. Edit: created an issue upstream: graph-gophers/graphql-go#499 |
Thanks Sina! Great find! |
So it turns out one of the specified validation rules ( query slots {
block {
account0: account(address: "0x...") {
slot0: storage (slot: "0x..."),
slot1: storage (slot: "0x...")
},
account1: account(address: "0x...") {
slot0: storage (slot: "0x...")
}
}
} In the meanwhile I also prototyped a JSON-RPC batch request. You can find the implementation for both in the same gist. Now to some results:
For anyone needing to fetch many storage slots I recommend first the new GraphQL query, and then the JSON-RPC batch request until there's an update from |
awesome work s1na, I'll be sure to spread this around to those who have the same issue. |
Sorry for bumping this. But i want to get reserves ( getreserves function) for 10k uniswap lp , per block. What is the fastest way to to this. Anyone have idea or recommedation ? Thanks. |
@berktaylan. You can index the storage keys for the reserves for the 10k Lps, and read directly off storage. You can read my blog post (go through tutorial 1 to 3) : https://medium.com/@fejleuros/tutorial-1-part-1-350694af2632 |
@berktaylan assuming the 10k Lps are just from Uniswap and its a V2 Lp, I believe the storage key is 0x08 for Reserves, so you can utilize the GraphQL query that s1na did to do a batch read of storage. |
@FeurJak hi, so i tried with 5k lps ( yes they are v2 ) with the batch request its 250 ms minimum and sometimes 1k ms randomly. with graphql its 1k to 2k ms. Im planning to go with batch request and aiming for 10k lps. Any tricks to make my batch requests faster ? Thanks. |
@berktaylan which "batch request" method are you referring to? |
for (let i = 0; i < lpv.length; i++) { wssend.send(JSON.stringify(reqs)); Not sure am i doing it correctly, so our goal was run it through db cache instead of EVM ? and i think eth_getStorageAt runs over cache/db not evm ? |
Yes that's correct, eth_getStorageAt reads from the latest state (cached or fetched from disk), not EVM. But it needs to fetch the latest block state first and I believe this process is halted when the node is syncing a new state. Maybe this is why you have 1k ms randomly. Without modifying GETH you won't get any better speed really. |
I'm surprised its slower by so much. Which query is that, this one? |
Yes like this, i think same
|
Hi @s1na , I wonder how is the performance of JSON-RPC batch compares with the new GraphQL nowadays? |
@tinoh99 I don't believe things have changed much since that benchmark. But the gist I posted contains the scripts I used. Feel free to compare them for yourself. |
Is there an available method to do a batch eth_getStorageAt to retrieve multiple storage variables? I know the exact indexes all-ready, but it's inefficient for me to make a single rpc call per variable.
The text was updated successfully, but these errors were encountered: