-
Notifications
You must be signed in to change notification settings - Fork 505
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
Support debug trace RPC APIs #768
Conversation
User @a-moreira, please sign the CLA here. |
I think is worth noting that this code can only work with runtime overrides. Let me (try to) explain. Environmental in the runtimeTo enable tracing you need to apply extrinsics For obvious reasons, you cannot enable Environmental in the clientIn addition to that, there is what we called internally a "double environmental hop" here - because we need a way to dodge the limited WASM memory restrictions and avoid overflowing it:
So we don't handle any trace in WASM and proxy everything back to the client instead. The way the tracing works is very dependant on what I just explained. ExampleHow a single transaction is traced:
|
The problem can be solved if |
If you use native you are always replaying the requested transactions over the same STF, which will most likely be different in comparison to the one the original transaction was executed over. Edit: maybe I should re-phrase |
Yes, but EVM config can be customized by simply passing a new My arguments are basically:
|
To get accurate EVM execution, we can also do the following:
|
But it's not just the evm related transactions, it's all the Frame extrinsics that might preceed the one you want to trace in that block. For example, imagine you changed how you ration the fees in the most recent runtime and now Author take 60% of the fees instead of 10%. If the (old) evm transaction you want to trace uses that address balance in any case, contract execution might take another code path and result in a completely different trace result. |
All the pre-conditions can be executed in native without tracing though. It's only the final EVM transaction that requires tracing as well as the block initialization. We simply need to build a storage overlay executing them (which Substrate's block initialization code in RPC calls is already an example). For the subsequent per-requisite EVM transactions, it can be done either calling |
You meant in wasm? Maybe could be worth experimenting with if:
Again, I need to think more about this but I'm pretty sure that there will be side effects. For example on top of my head if |
Yeah sorry. Meant to say wasm. |
Yes, from my experience, Native definitely provides different output than WASM in substrate. However it might not be the case in EVM which has different requirements in terms of op codes. |
According to paritytech/polkadot-sdk#62, the tracing feature discussed above will be broken once the native runtime execution has been abandoned? |
@sorpaas I've been thinking on what you suggested and I like the idea, as it would remove the more complex requirements. But in order for it to work, we need to check all the below, to summarize (please add if I miss something):
If we cannot satisfy all of the above points we will likely run into problems when tracing or end up with an implementation that covers just (Side note: |
The rationale for the deprecation of native runtime is to avoid compliance errors between native and wasm (so wasm becomes the single source of truth). This has been historically troublesome even for Polkadot mainnet. Those are all more or less in the consensus layer (there are some overlaps in the workers, but that doesn't matter much for this), and that is the layer that the deprecation is concerned. The code of the native runtime will never be deprecated, because it can't be -- it is used to build the wasm runtime. You'd always able to use the native runtime as a library, which is what we do here. If non-compliance bugs should be absolutely minimized then this is indeed a concern, cause we just run into the same problem as the original rational above. However, here, we don't need to treat it as strict as the consensus layer. Plus, deep state non-compliance should be extremely rare as long as the same evm version is used. If non-compliance only happens in the surface level, then it's always easy to debug and fix. An alternative to avoid the hacky runtime override is to store a runtime hash of the specialized build tracing runtime. Then in node, we keep a registry of all past tracing runtime build, and enable debug API only if the on-chain tracing runtime hash is in the registry. This may be a good compromise. However, note that it does not avoid the non-compliance problem because we're still using different code paths for tracing and non-tracing. |
I see, yeah makes sense, thanks for explaining.
From our experience this last year running the tracing in production, this is the case. Even the smallest mismatches are a huge headache, specially because they cascade into more serious mismatches in big nested transactions (internal calls). At the end it boils down to we cannot anticipate the side effects of even the smallest mismatch.
I agree, but is the edge cases the ones that concern me, as they ultimately render the whole service as "unreliable". Additionally, because they are rare and hard to reproduce, the tend to slip in from testnet and show up in production.
I'm not sure I understand this part. Are you suggesting to map the modified/tracing runtime wasm in offchain storage and use it instead of configuring a runtime overrides path through cli? |
Are there any updates available? |
Hi @tgmichel @a-moreira - are there any updates regarding this PR, or timeline estimates for merge? Thanks! |
Unfortunately no. In order to move the tracing code here we need a fully compliant solution, otherwise external projects relying on it will 100% malfunction. Consider the following: we don't use runtime overrides and we use purely Native somehow conditionally loading EVM configuration depending on the block we are tracing.
|
#703