Skip to content
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

debug_traceTransaction RPC method support #196

Merged
merged 104 commits into from
Mar 31, 2021
Merged

debug_traceTransaction RPC method support #196

merged 104 commits into from
Mar 31, 2021

Conversation

tgmichel
Copy link
Contributor

@tgmichel tgmichel commented Jan 22, 2021

This PR adds optional replaying and tracing capabilities for Ethereum transactions through debug_traceTransaction, and provides support for Blockscout tracer.

  • Support for additional methods in the debug namespace are not included in this PR.
  • Support for Javascript-based tracing support is not included in this PR - instead a tailored Blockscout tracer is included, coded in Rust.

The components included are:

  • RPC.
  • Runtime API .
  • pallet-evm Runner extension.
  • EVM stack executor wrapper.

RPC

Single method is included in this PR - debug_traceTransaction. It accepts an Ethereum transaction hash and an optional tracer property. It can be enabled by running the node with --ethapi debug.

Originally in Geth, this property's value is evaluated as a Javascript expression in Go and used to format the tracing output. We don't support this and instead we use it to identify if Blockscout tracing is part of the request - a.k.a. instead evaluating the JS expression we execute a stepping routine that will provide an output that satisfies Blockscout's requirements.

Runtime API

Interfaces the RPC with the Runtime, sets the required intermediate state and calls the Runner extension for either create or call transactions.

The intermediate state is calculated by applying all previous extrinsics - substrate or ethereum specific - that happened prior to the targeted transaction in that block, using the parent block as the initial state.

Runner extension

Additional methods to interface RPC requests with our executor wrapper.

EVM stack executor wrapper

Wraps an EVM's StackExecutor in a custom HandlerT implementor called TraceExecutorWrapper. It replaces the normal evm::runtime opcode recursive execution with opcode stepping. This allows us to capture the state between each step's execution and format a response.

Included in this PR there are two possible responses:

  • Raw: opcode-level response. A sequence of opcode objects with depth, gas, gasCost, memory, op, pc, stack and storage properties:
...
{
       "pc": 229,
       "op": "SWAP1",
       "gas": 62844,
       "gasCost": 3,
       "depth": 1,
       "stack": [
         "00000000000000000000000000000000000000000000000000000000398f7223",
         "0000000000000000000000000000000000000000000000000000000000000087",
         "0000000000000000000000001416aa2a27db08ce3a81a01cdfc981417d28a6e6",
         "0000000000000000000000000000000000000000000000000000000000000006",
         "0000000000000000000000001416aa2a27db08ce3a81a01cdfc981417d28a6e6",
         "0000000000000000000000000000000000000000000000000000000000000000",
         "0000000000000000000000001416aa2a27db08ce3a81a01cdfc981417d28a6e6"
       ],
       "memory": [
         "0000000000000000000000000000000000000000000000000000000000000000",
         "0000000000000000000000000000000000000000000000000000000000000000",
         "0000000000000000000000000000000000000000000000000000000000000080"
       ],
       "storage": {
         "0000000000000000000000000000000000000000000000000000000000000000": "0000000000000000000000000000000000000000000000000000000000000000"
       }
     },
     {
       "pc": 230,
       "op": "SSTORE",
       "gas": 62841,
       "gasCost": 20000,
       "depth": 1,
       "stack": [
         "00000000000000000000000000000000000000000000000000000000398f7223",
         "0000000000000000000000000000000000000000000000000000000000000087",
         "0000000000000000000000001416aa2a27db08ce3a81a01cdfc981417d28a6e6",
         "0000000000000000000000000000000000000000000000000000000000000006",
         "0000000000000000000000001416aa2a27db08ce3a81a01cdfc981417d28a6e6",
         "0000000000000000000000001416aa2a27db08ce3a81a01cdfc981417d28a6e6",
         "0000000000000000000000000000000000000000000000000000000000000000"
       ],
       "memory": [
         "0000000000000000000000000000000000000000000000000000000000000000",
         "0000000000000000000000000000000000000000000000000000000000000000",
         "0000000000000000000000000000000000000000000000000000000000000080"
       ],
       "storage": {
         "0000000000000000000000000000000000000000000000000000000000000000": "0000000000000000000000001416aa2a27db08ce3a81a01cdfc981417d28a6e6"
       }
     }
...
  • Blockscout: a compact sorted view of call/create contract interactions:
[
 {
   "type": "call",
   "callType": "call",
   "from": "0xfe2882ac0a337a976aa73023c2a2a917f57ba2ed",
   "to": "0x3ca17a1c4995b95c600275e52da93d2e64dd591f",
   "input": "0x398f72230000000000000000000000001416aa2a27db08ce3a81a01cdfc981417d28a6e60000000000000000000000000000000000000000000000000000000000000006",
   "output": "0x",
   "traceAddress": [],
   "value": "0x0",
   "gas": "0xf9be",
   "gasUsed": "0xf9be"
 },
 {
   "type": "call",
   "callType": "call",
   "from": "0x3ca17a1c4995b95c600275e52da93d2e64dd591f",
   "to": "0x1416aa2a27db08ce3a81a01cdfc981417d28a6e6",
   "input": "0xfd63983b0000000000000000000000000000000000000000000000000000000000000006",
   "output": "0x000000000000000000000000000000000000000000000000000000000000000d",
   "traceAddress": [
     0
   ],
   "value": "0x0",
   "gas": "0x9b9b",
   "gasUsed": "0x4f6d"
 }
]

Is there something left for follow-up PRs?

  • Support for the remaining functionality of the debug namespace is to be determined.
  • Generic support for Javascript based tracing is to be determined.

What alternative implementations were considered?

  • Use an optional hook to the EVM instead a custom executor wrapper. We may go with this approach in further iterations, although impact on non-tracing executions to be determined. Compatibility with the tailored Blockscout is to be determined.
  • Applying the intermediate state for replaying using execute_block instead apply_extrinsics. The result is the same in both cases, I decided to go with the latter.

What value does it bring to the blockchain users?

The ability of replaying transactions and tracing intermediate state enables detailed indexing of the network.

Checklist

  • Does it require a purge of the network?
  • You bumped the runtime version if there are breaking changes in the runtime ?
  • Does it require changes in documentation/tutorials ?

@notlesh
Copy link
Contributor

notlesh commented Jan 25, 2021

Looks good so far. Do you plan to support higher level stepping (e.g. step over or step out)?

# Conflicts:
#	Cargo.lock
#	Cargo.toml
#	client/rpc-core/txpool/Cargo.toml
#	client/rpc/txpool/Cargo.toml
#	node/Cargo.toml
#	node/rpc/Cargo.toml
#	node/src/rpc.rs
#	node/src/service.rs
#	node/standalone/Cargo.lock
#	node/standalone/Cargo.toml
#	node/standalone/src/command.rs
#	node/standalone/src/service.rs
#	primitives/rpc/txpool/Cargo.toml
#	runtime/Cargo.toml
#	runtime/account/Cargo.toml
#	runtime/precompiles/Cargo.toml
#	runtime/precompiles/src/lib.rs
#	runtime/src/lib.rs
@tgmichel
Copy link
Contributor Author

tgmichel commented Mar 30, 2021

@notlesh As I mention to @nanocryk, and because I don't know the status of our frontier branch notlesh-moonbeam-v0.7 (I don't want to give you headaches :)), I didn't updated it. That's why the CI here is failing with note: perhaps two different versions of crate "evm" are being used?.

Solution is as simple as pinning the same evm commit here in moonbeam and in the frontier branch:
https://github.com/rust-blockchain/evm?branch=master#317b82b5660150a37f84da6d7d570b52ad8f23a4

Sadly is not part of any release yet, but should be sufficient to get going.

.vscode/settings.json Outdated Show resolved Hide resolved
Copy link
Contributor

@JoshOrndorff JoshOrndorff left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here's some stuff that stood out to me when giving the code a look. I'm far from an expert on this work.

primitives/rpc/debug/src/lib.rs Outdated Show resolved Hide resolved
client/rpc-core/debug/src/lib.rs Outdated Show resolved Hide resolved
runtime/Cargo.toml Outdated Show resolved Hide resolved
runtime/extensions/evm/src/lib.rs Show resolved Hide resolved
runtime/extensions/evm/src/executor/util.rs Outdated Show resolved Hide resolved
runtime/extensions/evm/src/runner/stack.rs Show resolved Hide resolved
runtime/src/lib.rs Outdated Show resolved Hide resolved
runtime/src/lib.rs Show resolved Hide resolved
tests/replay/.gitignore Show resolved Hide resolved
@tgmichel
Copy link
Contributor Author

Here's some stuff that stood out to me when giving the code a look. I'm far from an expert on this work.

Thanks for taking some time to look at this! I pushed some corrections, please let me know.

Copy link
Contributor

@JoshOrndorff JoshOrndorff left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good as far as I can tell. Thanks for the docs and addressing my thoughts.

@JoshOrndorff JoshOrndorff added A6-mustntgrumble Pull request has areas for improvement. The author need not address them before merging. A9-buythat(wo)manabeer Pull request is reviewed well and worth buying the author a beer. B5-clientnoteworthy Changes should be mentioned in any downstream projects' release notes B7-runtimenoteworthy Changes should be noted in any runtime-upgrade release notes C1-low Does not elevate a release containing this beyond "low priority". labels Mar 31, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A6-mustntgrumble Pull request has areas for improvement. The author need not address them before merging. A9-buythat(wo)manabeer Pull request is reviewed well and worth buying the author a beer. B5-clientnoteworthy Changes should be mentioned in any downstream projects' release notes B7-runtimenoteworthy Changes should be noted in any runtime-upgrade release notes C1-low Does not elevate a release containing this beyond "low priority".
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants