Open xermicus opened 1 month ago
Note that revive currently does not support the diff mode in the debug trace API. This means that functionality has to be implemented first in pallet-revive.
Implementing this is a dependency for this issue. It should be implemented in polkadot-sdk first.
is that something we need in the eth-rpc proxy, don't we get it if we use Anvil testing node?
cc @smiasojed
is that something we need in the eth-rpc proxy, don't we get it if we use Anvil testing node?
cc @smiasojed
@pgherveou I think it is not supported in anvil now: https://github.com/foundry-rs/foundry/issues/9397, https://github.com/foundry-rs/foundry/issues/5403
Note that revive currently does not support the diff mode in the debug trace API. This means that functionality has to be implemented first in pallet-revive.
Implementing this is a dependency for this issue. It should be implemented in polkadot-sdk first.
keeping track of internal thread regarding this https://matrix.to/#/!DdfYhHuqjPrESXfCDj:parity.io/$zqo6BDe0rMkxn0oanOVTPWVpvhPhjAJp0qSHTi_j4Es?via=parity.io&via=web3.foundation
Looked a bit into it. One general question I have about the framework is: Do we really need to execute transactions for the differential tests? wouldn't comparing the dry-run be more practical?
the rpc debug endpoints can operate on an existing transaction (debug_traceTransaction) or directly on a call (debug_traceCall).
the advantage you have with the call is that you get the result back directly, you don't need to wait for the receipt, you can even define the api to be blocking if you wish, and since there are no side effects you may evn run tests in parallel
That being said, there is an API in substrate state_traceBlock
that let you get storage changes for a block.
But it might be more practical to build a new RPC that wrap the StateBackend and track storage changes, will look into it in more details today
Ok looked a bit more into state_traceBlock
this should provide the necessary foundations to build our tracer endpoint.
Exploration notes I did a quick test with a simple transfer Alice -> Ferdie
We can query the state changes with
# block_hash = 0x8e4bec0fdaff5b68e218ad40e8eed899dd93b035d94a9df575adc36b3cc9413d
# storage_key filter = twox_128("System") + twox_128("Account")
# = 0x26aa394eea5630e07c48ae0c9558cef7 + 0xb99d880ec681799c0cf30e8886371da9
curl http://localhost:9944 \
-H "Content-Type: application/json" \
-d '{
"id":1,
"jsonrpc":"2.0",
"method":"state_traceBlock",
"params":[
"0x8e4bec0fdaff5b68e218ad40e8eed899dd93b035d94a9df575adc36b3cc9413d",
"state",
"26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9",
"Put"
]
}' \
| jq '
[
.result.blockTrace.events[]
| { key: .data.stringValues.key,
value: .data.stringValues.value,
method:.data.stringValues.method }
]
| unique_by(.key)
| .[]
'
This indeed shows the system.account FrameSystemAccountInfo changes for the two accounts
{
"key": "26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da923a05cabf6d3bde7ca3ef0d11596b5611cbd2d43530a44705ad088af313e18f80b53ef16b36177cd4b77b846f2a5f07c",
"value": "Some(00000000000000000100000000000000fc030000000000000000000000000000000000000000000000000000000000000000000000000080)",
"method": "Put"
}
{
"key": "26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d",
"value": "Some(01000000000000000100000000000000e8030000000000000000000000000000000000000000000000000000000000000000000000000080)",
"method": "Put"
}
If need be I think the substrate rpc can be updated as well to support tracing a dry_run
for reference I think the API @xermicus mentioned in this issue is the following documented here https://geth.ethereum.org/docs/developers/evm-tracing/built-in-tracers#prestate-tracer
debug.traceCall(
{
from: '0x35a9f94af726f07b5162df7e828cc9dc8439e7d0',
to: '0xc8ba32cab1757528daf49033e3673fae77dcf05d',
data: '0xd1a2eab2000000000000000000000000000000000000000000000000000000000024aea100000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000050000000204895cd480cc8412691a880028a25aec86786f1ed2aa5562bc400000000000000c6403c14f35be1da6f433eadbb6e9178a47fbc7c6c1d568d2f2b876e929089c8d8db646304fd001a187dc8a600000000000000000000000000000000'
},
'latest',
{ tracer: 'prestateTracer' }
);
Return:
{
0x0000000000000000000000000000000000000002: {
balance: "0x0"
},
0x008b3b2f992c0e14edaa6e2c662bec549caa8df1: {
balance: "0x2638035a26d133809"
},
0x35a9f94af726f07b5162df7e828cc9dc8439e7d0: {
balance: "0x7a48734599f7284",
nonce: 1133
},
0xc8ba32cab1757528daf49033e3673fae77dcf05d: {
balance: "0x0",
code: "0x608060405234801561001057600080fd5b50600436106100885760003560e01c8063a9c2d...
nonce: 1,
storage: {
0x0000000000000000000000000000000000000000000000000000000000000000: "0x000000000000000000000000000000000000000000000000000000000024aea6",
0x59fb7853eb21f604d010b94c123acbeae621f09ce15ee5d7616485b1e78a72e9: "0x00000000000000c42b56a52aedf18667c8ae258a0280a8912641c80c48cd9548",
0x8d8ebb65ec00cb973d4fe086a607728fd1b9de14aa48208381eed9592f0dee9a: "0x00000000000000784ae4881e40b1f5ebb4437905fbb8a5914454123b0293b35f",
0xff896b09014882056009dedb136458f017fcef9a4729467d0d00b4fd413fb1f1: "0x000000000000000e78ac39cb1c20e9edc753623b153705d0ccc487e31f9d6749"
}
}
}
Yeah exactly it is the state diff mode.
Do we really need to execute transactions for the differential tests? wouldn't comparing the dry-run be more practical?
I think it will execute the transaction first anyways and then gather the diff via the trace call. If all information that is required to reconstruct the diff geth outputs is available in the dry run output, dry running it first would work - however my request here would be to just implement the missing state diff mode. It improves our eth compatibilty.
I think it will execute the transaction first anyways
so this particular tracer is called prestate tracer, and just like the other one it's exposed through 3 debug rpc debug_traceBlockByNumber, debug_traceTransaction and debug_traceCall
the first two replay an exisiting block or transaction, the latest will dry_run the provided call.
I am about to add support for debug_traceBlockByNumber, debug_traceTransaction, we can deal with the latest one later, I do think though that this might be better for diff testing as mentioned above
Ah thanks that is a nice breakdown! I wasn't aware traceCall does actually dry run it. FWIW I think traceTransaction should work fine for our use case here regardless.
This requires adding a
kitchensink
module in therevive-dt-node
crate. See also the trait implementation for go-ethereum.Note that revive currently does not support the diff mode in the debug trace API. This means that functionality has to be implemented first in
pallet-revive
.Depends on #6