From aa5db21a68d90881325836a9eb25d0ab2026b22f Mon Sep 17 00:00:00 2001 From: Thomas Coratger <60488569+tcoratger@users.noreply.github.com> Date: Sun, 14 Jul 2024 17:45:45 +0200 Subject: [PATCH] feat(rpc): implement `debug_traceCall` (#1280) * wip draft * trace call implementation * add test * cleanup * fix lint * update test and clean up * fix fmt * trace instrument fix * fix comment * fix conflicts * fix comment * fix * Update src/tracing/mod.rs Co-authored-by: greged93 <82421016+greged93@users.noreply.github.com> --------- Co-authored-by: greged93 <82421016+greged93@users.noreply.github.com> --- Cargo.lock | 343 +++++++++++++++++++++---------- Cargo.toml | 2 + src/eth_provider/error.rs | 6 +- src/eth_rpc/api/debug_api.rs | 13 +- src/eth_rpc/servers/debug_rpc.rs | 40 +++- src/tracing/builder.rs | 45 +++- src/tracing/mod.rs | 110 ++++++++-- tests/tests/trace_api.rs | 171 ++++++++++++++- 8 files changed, 589 insertions(+), 141 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fcffeec6a..32af558b1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -378,7 +378,7 @@ checksum = "d83524c1f6162fcb5b0decf775498a125066c86dda6066ed609531b0e912f85a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -621,7 +621,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -637,7 +637,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", "syn-solidity", "tiny-keccak", ] @@ -653,7 +653,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", "syn-solidity", ] @@ -802,7 +802,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -1091,7 +1091,7 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -1102,7 +1102,7 @@ checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -1138,7 +1138,7 @@ checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -1288,7 +1288,7 @@ dependencies = [ "regex", "rustc-hash 1.1.0", "shlex", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -1308,7 +1308,7 @@ dependencies = [ "regex", "rustc-hash 1.1.0", "shlex", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -1623,7 +1623,7 @@ checksum = "6be9c93793b60dac381af475b98634d4b451e28336e72218cad9a20176218dbc" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", "synstructure", ] @@ -1828,7 +1828,7 @@ checksum = "1ee891b04274a59bd38b412188e24b849617b2e45a0fd8d057deb63e7403761b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -1839,9 +1839,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.6.0" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" +checksum = "a12916984aab3fa6e39d655a33e09c0071eb36d6ab3aea5c2d78551f1df6d952" dependencies = [ "serde", ] @@ -1978,7 +1978,7 @@ dependencies = [ "quote", "serde_json", "starknet 0.9.0", - "syn 2.0.70", + "syn 2.0.71", "thiserror", ] @@ -1991,7 +1991,7 @@ dependencies = [ "quote", "serde_json", "starknet 0.10.0", - "syn 2.0.70", + "syn 2.0.71", "thiserror", ] @@ -2007,7 +2007,7 @@ dependencies = [ "quote", "serde_json", "starknet 0.9.0", - "syn 2.0.70", + "syn 2.0.71", "thiserror", ] @@ -2025,7 +2025,7 @@ dependencies = [ "quote", "serde_json", "starknet 0.10.0", - "syn 2.0.70", + "syn 2.0.71", "thiserror", ] @@ -2042,7 +2042,7 @@ dependencies = [ "quote", "serde_json", "starknet 0.9.0", - "syn 2.0.70", + "syn 2.0.71", "thiserror", ] @@ -2059,7 +2059,7 @@ dependencies = [ "quote", "serde_json", "starknet 0.10.0", - "syn 2.0.70", + "syn 2.0.71", "thiserror", ] @@ -2469,7 +2469,7 @@ source = "git+https://github.com/software-mansion/scarb?rev=f1aa7b09507a84d209d8 dependencies = [ "quote", "scarb-stable-hash", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -2597,7 +2597,7 @@ source = "git+https://github.com/starkware-libs/cairo?tag=v2.6.3#2203a47f8a098cd dependencies = [ "cairo-lang-debug 2.6.3 (git+https://github.com/starkware-libs/cairo?tag=v2.6.3)", "quote", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -2607,7 +2607,7 @@ source = "git+https://github.com/starkware-libs/cairo?rev=d9984ef58e2f704909e271 dependencies = [ "cairo-lang-debug 2.6.3 (git+https://github.com/starkware-libs/cairo?rev=d9984ef58e2f704909e271f2f01327f520ded632)", "quote", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -2618,7 +2618,7 @@ checksum = "0c90d812ec983c5a8e3173aca3fc55036b9739201c89f30271ee14a4c1189379" dependencies = [ "cairo-lang-debug 2.6.4", "quote", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -3514,9 +3514,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.1.0" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaff6f8ce506b9773fa786672d63fc7a191ffea1be33f72bbd4aeacefca9ffc8" +checksum = "47de7e88bbbd467951ae7f5a6f34f70d1b4d9cfce53d5fd70f74ebe118b3db56" dependencies = [ "jobserver", "libc", @@ -3613,9 +3613,9 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.5.7" +version = "4.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d598e88f6874d4b888ed40c71efbcbf4076f1dfbae128a08a8c9e45f710605d" +checksum = "5b4be9c4c4b1f30b78d8a750e0822b6a6102d97e62061c583a6c1dea2dfb33ae" dependencies = [ "clap", ] @@ -3629,7 +3629,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -4011,7 +4011,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "edb49164822f3ee45b17acd4a208cfc1251410cf0cad9a833234c9890774dd9f" dependencies = [ "quote", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -4079,7 +4079,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -4151,7 +4151,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.11.1", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -4184,7 +4184,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core 0.20.10", "quote", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -4302,7 +4302,7 @@ checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -4323,7 +4323,7 @@ dependencies = [ "darling 0.20.10", "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -4333,7 +4333,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "206868b8242f27cecce124c19fd88157fbd0dd334df2587f36417bafbc85097b" dependencies = [ "derive_builder_core", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -4346,7 +4346,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version 0.4.0", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -4490,7 +4490,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -4907,7 +4907,7 @@ dependencies = [ "heck 0.4.1", "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -4918,7 +4918,7 @@ checksum = "6fd000fd6988e73bbe993ea3db9b1aa64906ab88766d654973924340c8cddb42" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -5377,7 +5377,7 @@ dependencies = [ [[package]] name = "foundry-config" version = "0.2.0" -source = "git+https://github.com/foundry-rs/foundry?branch=master#1e0603f9239deec110753ff57032f8b3cba3c4a9" +source = "git+https://github.com/foundry-rs/foundry?branch=master#5902a6fa87600cf0cbe44e689c97479c16fd474e" dependencies = [ "Inflector", "alloy-chains", @@ -5499,7 +5499,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -5567,7 +5567,7 @@ checksum = "553630feadf7b76442b0849fd25fdf89b860d933623aec9693fed19af0400c78" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -6045,7 +6045,7 @@ checksum = "999ce923619f88194171a67fb3e6d613653b8d4d6078b529b15a765da0edcc17" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -6819,9 +6819,9 @@ dependencies = [ [[package]] name = "http-body" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", "http 1.1.0", @@ -6836,7 +6836,7 @@ dependencies = [ "bytes", "futures-util", "http 1.1.0", - "http-body 1.0.0", + "http-body 1.0.1", "pin-project-lite", ] @@ -6915,7 +6915,7 @@ dependencies = [ "futures-util", "h2 0.4.5", "http 1.1.0", - "http-body 1.0.0", + "http-body 1.0.1", "httparse", "httpdate", "itoa", @@ -7016,7 +7016,7 @@ dependencies = [ "futures-channel", "futures-util", "http 1.1.0", - "http-body 1.0.0", + "http-body 1.0.1", "hyper 1.4.1", "pin-project-lite", "socket2 0.5.7", @@ -7179,7 +7179,7 @@ checksum = "d2abdd3a62551e8337af119c5899e600ca0c88ec8f23a46c60ba216c803dcf1a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -7640,7 +7640,7 @@ dependencies = [ "futures-timer", "futures-util", "http 1.1.0", - "http-body 1.0.0", + "http-body 1.0.1", "http-body-util", "jsonrpsee-types 0.23.2", "parking_lot 0.12.3", @@ -7664,7 +7664,7 @@ checksum = "2d90064e04fb9d7282b1c71044ea94d0bbc6eff5621c66f1a0bce9e9de7cf3ac" dependencies = [ "async-trait", "base64 0.22.1", - "http-body 1.0.0", + "http-body 1.0.1", "hyper 1.4.1", "hyper-rustls 0.27.2", "hyper-util", @@ -7704,7 +7704,7 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -7738,7 +7738,7 @@ dependencies = [ "anyhow", "futures-util", "http 1.1.0", - "http-body 1.0.0", + "http-body 1.0.1", "http-body-util", "hyper 1.4.1", "hyper-util", @@ -7903,6 +7903,8 @@ dependencies = [ "reth-node-api", "reth-primitives", "reth-revm", + "reth-rpc", + "reth-rpc-eth-types", "reth-rpc-types", "reth-rpc-types-compat", "revm-inspectors", @@ -8539,7 +8541,7 @@ checksum = "f8dccda732e04fa3baf2e17cf835bfe2601c7c2edafd64417c627dabae3a8cda" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -8708,9 +8710,9 @@ dependencies = [ [[package]] name = "metrics-exporter-prometheus" -version = "0.15.1" +version = "0.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf0af7a0d7ced10c0151f870e5e3f3f8bc9ffc5992d32873566ca1f9169ae776" +checksum = "b4f0c8427b39666bf970460908b213ec09b3b350f20c0c2eabcbba51704a08e6" dependencies = [ "base64 0.22.1", "indexmap 2.2.6", @@ -8728,7 +8730,7 @@ checksum = "38b4faf00617defe497754acde3024865bc143d44a86799b24e191ecff91354f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -8941,7 +8943,7 @@ checksum = "934305ae9c66ef6a3aa728c66dec8fa2424de4dfcd043c7acaffacae2bf99442" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -9256,7 +9258,7 @@ dependencies = [ "proc-macro-crate 1.3.1", "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -9368,7 +9370,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -9545,7 +9547,7 @@ dependencies = [ "regex", "regex-syntax 0.8.4", "structmeta", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -9627,7 +9629,7 @@ dependencies = [ "proc-macro2", "proc-macro2-diagnostics", "quote", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -9716,7 +9718,7 @@ dependencies = [ "phf_shared 0.11.2", "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -9760,7 +9762,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -9898,7 +9900,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f12335488a2f3b0a83b14edad48dca9879ce89b2edd10e80237e4e852dd645e" dependencies = [ "proc-macro2", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -9975,7 +9977,7 @@ checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", "version_check", "yansi 1.0.1", ] @@ -10079,7 +10081,7 @@ checksum = "6ff7ff745a347b87471d859a377a9a404361e7efc2a971d73424a6d183c0fc77" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -10500,7 +10502,7 @@ dependencies = [ "h2 0.4.5", "hickory-resolver", "http 1.1.0", - "http-body 1.0.0", + "http-body 1.0.1", "http-body-util", "hyper 1.4.1", "hyper-rustls 0.27.2", @@ -10542,6 +10544,40 @@ dependencies = [ "quick-error", ] +[[package]] +name = "reth-beacon-consensus" +version = "1.0.1" +source = "git+https://github.com/paradigmxyz/reth.git?tag=v1.0.1#d599393771f9d7d137ea4abf271e1bd118184c73" +dependencies = [ + "futures", + "itertools 0.13.0", + "metrics 0.23.0", + "reth-blockchain-tree-api", + "reth-chainspec", + "reth-db-api", + "reth-engine-primitives", + "reth-errors", + "reth-ethereum-consensus", + "reth-metrics", + "reth-network-p2p", + "reth-payload-builder", + "reth-payload-primitives", + "reth-payload-validator", + "reth-primitives", + "reth-provider", + "reth-prune", + "reth-rpc-types", + "reth-stages-api", + "reth-static-file", + "reth-tasks", + "reth-tokio-util", + "schnellru", + "thiserror", + "tokio", + "tokio-stream", + "tracing", +] + [[package]] name = "reth-blockchain-tree-api" version = "1.0.1" @@ -10609,7 +10645,7 @@ dependencies = [ "convert_case 0.6.0", "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -11101,7 +11137,7 @@ dependencies = [ "proc-macro2", "quote", "regex", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -11113,7 +11149,7 @@ dependencies = [ "proc-macro2", "quote", "regex", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -11301,7 +11337,7 @@ dependencies = [ "humantime", "jsonrpsee 0.23.2", "metrics 0.23.0", - "metrics-exporter-prometheus 0.15.1", + "metrics-exporter-prometheus 0.15.3", "metrics-process 2.1.0", "metrics-util 0.17.0", "once_cell", @@ -11380,6 +11416,17 @@ dependencies = [ "tokio", ] +[[package]] +name = "reth-payload-validator" +version = "1.0.1" +source = "git+https://github.com/paradigmxyz/reth.git?tag=v1.0.1#d599393771f9d7d137ea4abf271e1bd118184c73" +dependencies = [ + "reth-chainspec", + "reth-primitives", + "reth-rpc-types", + "reth-rpc-types-compat", +] + [[package]] name = "reth-primitives" version = "1.0.1" @@ -11533,6 +11580,58 @@ dependencies = [ "tracing", ] +[[package]] +name = "reth-rpc" +version = "1.0.1" +source = "git+https://github.com/paradigmxyz/reth.git?tag=v1.0.1#d599393771f9d7d137ea4abf271e1bd118184c73" +dependencies = [ + "alloy-dyn-abi", + "alloy-genesis 0.1.4", + "alloy-primitives", + "alloy-rlp", + "async-trait", + "derive_more", + "futures", + "http 1.1.0", + "http-body 1.0.1", + "hyper 1.4.1", + "jsonrpsee 0.23.2", + "jsonwebtoken", + "parking_lot 0.12.3", + "pin-project", + "rand 0.8.5", + "reth-chainspec", + "reth-consensus-common", + "reth-errors", + "reth-evm", + "reth-network-api", + "reth-network-peers", + "reth-primitives", + "reth-provider", + "reth-revm", + "reth-rpc-api", + "reth-rpc-engine-api", + "reth-rpc-eth-api", + "reth-rpc-eth-types", + "reth-rpc-server-types", + "reth-rpc-types", + "reth-rpc-types-compat", + "reth-tasks", + "reth-transaction-pool", + "revm", + "revm-inspectors", + "revm-primitives 6.0.0", + "secp256k1", + "serde", + "serde_json", + "thiserror", + "tokio", + "tokio-stream", + "tower", + "tracing", + "tracing-futures", +] + [[package]] name = "reth-rpc-api" version = "1.0.1" @@ -11547,6 +11646,34 @@ dependencies = [ "serde", ] +[[package]] +name = "reth-rpc-engine-api" +version = "1.0.1" +source = "git+https://github.com/paradigmxyz/reth.git?tag=v1.0.1#d599393771f9d7d137ea4abf271e1bd118184c73" +dependencies = [ + "async-trait", + "jsonrpsee-core 0.23.2", + "jsonrpsee-types 0.23.2", + "metrics 0.23.0", + "reth-beacon-consensus", + "reth-chainspec", + "reth-engine-primitives", + "reth-evm", + "reth-metrics", + "reth-payload-builder", + "reth-payload-primitives", + "reth-primitives", + "reth-rpc-api", + "reth-rpc-types", + "reth-rpc-types-compat", + "reth-storage-api", + "reth-tasks", + "serde", + "thiserror", + "tokio", + "tracing", +] + [[package]] name = "reth-rpc-eth-api" version = "1.0.1" @@ -12168,7 +12295,7 @@ dependencies = [ "regex", "relative-path", "rustc_version 0.4.0", - "syn 2.0.70", + "syn 2.0.71", "unicode-ident", ] @@ -12679,7 +12806,7 @@ dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -12904,7 +13031,7 @@ checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -12915,7 +13042,7 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -12959,7 +13086,7 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -13048,7 +13175,7 @@ dependencies = [ "darling 0.20.10", "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -13060,7 +13187,7 @@ dependencies = [ "darling 0.20.10", "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -13667,7 +13794,7 @@ checksum = "bbc159a1934c7be9761c237333a57febe060ace2bc9e3b337a59a37af206d19f" dependencies = [ "starknet-curve 0.4.2", "starknet-ff", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -13710,7 +13837,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95d549d3078bdbe775d0deaa8ddb57a19942989ce7c1f2dfd60beeb322bb4945" dependencies = [ "starknet-core 0.10.0", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -13944,7 +14071,7 @@ dependencies = [ "proc-macro2", "quote", "structmeta-derive", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -13955,7 +14082,7 @@ checksum = "152a0b65a590ff6c3da95cabe2353ee04e6167c896b28e3b14478c2636c922fc" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -14005,7 +14132,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -14018,7 +14145,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -14096,9 +14223,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.70" +version = "2.0.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f0209b68b3613b093e0ec905354eccaedcfe83b8cb37cbdeae64026c3064c16" +checksum = "b146dcf730474b4bcd16c311627b31ede9ab149045db4d6088b3becaea046462" dependencies = [ "proc-macro2", "quote", @@ -14114,7 +14241,7 @@ dependencies = [ "paste", "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -14137,7 +14264,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -14263,22 +14390,22 @@ checksum = "a38c90d48152c236a3ab59271da4f4ae63d678c5d7ad6b7714d7cb9760be5e4b" [[package]] name = "thiserror" -version = "1.0.61" +version = "1.0.62" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" +checksum = "f2675633b1499176c2dff06b0856a27976a8f9d436737b4cf4f312d4d91d8bbb" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.61" +version = "1.0.62" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" +checksum = "d20468752b09f49e909e55a5d338caa8bedf615594e9d80bc4c565d30faf798c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -14415,7 +14542,7 @@ checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -14610,7 +14737,7 @@ dependencies = [ "bitflags 2.6.0", "bytes", "http 1.1.0", - "http-body 1.0.0", + "http-body 1.0.1", "http-body-util", "pin-project-lite", "tower-layer", @@ -14661,7 +14788,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -14829,7 +14956,7 @@ checksum = "1f718dfaf347dcb5b983bfc87608144b0bad87970aebcbea5ce44d2a30c08e63" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -15139,7 +15266,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", "wasm-bindgen-shared", ] @@ -15173,7 +15300,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -15331,7 +15458,7 @@ checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -15342,7 +15469,7 @@ checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -15625,7 +15752,7 @@ checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", "synstructure", ] @@ -15646,7 +15773,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -15666,7 +15793,7 @@ checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", "synstructure", ] @@ -15687,7 +15814,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -15709,7 +15836,7 @@ checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 3c662bb9f..6801ad0b8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -67,6 +67,8 @@ reth-rpc-types = { git = "https://github.com/paradigmxyz/reth.git", tag = "v1.0. "arbitrary", ] } reth-rpc-types-compat = { git = "https://github.com/paradigmxyz/reth.git", tag = "v1.0.1", default-features = false } +reth-rpc-eth-types = { git = "https://github.com/paradigmxyz/reth.git", tag = "v1.0.1", default-features = false } +reth-rpc = { git = "https://github.com/paradigmxyz/reth.git", tag = "v1.0.1", default-features = false } reth-revm = { git = "https://github.com/paradigmxyz/reth.git", tag = "v1.0.1", default-features = false } reth-evm-ethereum = { git = "https://github.com/paradigmxyz/reth.git", tag = "v1.0.1", default-features = false } reth-node-api = { git = "https://github.com/paradigmxyz/reth.git", tag = "v1.0.1", default-features = false } diff --git a/src/eth_provider/error.rs b/src/eth_provider/error.rs index af2c1b651..795acf032 100644 --- a/src/eth_provider/error.rs +++ b/src/eth_provider/error.rs @@ -34,7 +34,8 @@ impl From<&EthApiError> for EthRpcErrorCode { } EthApiError::Signature(_) | EthApiError::EthereumDataFormat(_) - | EthApiError::CalldataExceededLimit(_, _) => Self::InvalidParams, + | EthApiError::CalldataExceededLimit(_, _) + | EthApiError::RethEthApi(_) => Self::InvalidParams, EthApiError::Transaction(err) => err.into(), EthApiError::Unsupported(_) | EthApiError::Kakarot(_) => Self::InternalError, EthApiError::Execution(_) => Self::ExecutionError, @@ -65,6 +66,8 @@ pub enum EthApiError { Kakarot(KakarotError), /// Error related to transaction calldata being too large. CalldataExceededLimit(usize, usize), + /// Reth Eth API error + RethEthApi(#[from] reth_rpc_eth_types::EthApiError), } impl std::fmt::Display for EthApiError { @@ -75,6 +78,7 @@ impl std::fmt::Display for EthApiError { Self::TransactionNotFound(tx) => write!(f, "transaction not found {tx}"), Self::Transaction(err) => write!(f, "{err}"), Self::Signature(err) => write!(f, "{err}"), + Self::RethEthApi(err) => write!(f, "{err}"), Self::Unsupported(feature) => write!(f, "unsupported: {feature}"), Self::EthereumDataFormat(err) => write!(f, "ethereum data format error: {err}"), Self::Execution(err) => write!(f, "{err}"), diff --git a/src/eth_rpc/api/debug_api.rs b/src/eth_rpc/api/debug_api.rs index 92a7e3d44..f89d5ffc3 100644 --- a/src/eth_rpc/api/debug_api.rs +++ b/src/eth_rpc/api/debug_api.rs @@ -1,8 +1,8 @@ use jsonrpsee::{core::RpcResult as Result, proc_macros::rpc}; use reth_primitives::{Bytes, B256}; use reth_rpc_types::{ - trace::geth::{GethDebugTracingOptions, GethTrace, TraceResult}, - BlockId, BlockNumberOrTag, + trace::geth::{GethDebugTracingCallOptions, GethDebugTracingOptions, GethTrace, TraceResult}, + BlockId, BlockNumberOrTag, TransactionRequest, }; /// Debug API @@ -56,4 +56,13 @@ pub trait DebugApi { transaction_hash: B256, opts: Option, ) -> Result; + + /// Runs an `eth_call` within the context of a given block execution and returns the Geth debug trace. + #[method(name = "traceCall")] + async fn trace_call( + &self, + request: TransactionRequest, + block_number: Option, + opts: Option, + ) -> Result; } diff --git a/src/eth_rpc/servers/debug_rpc.rs b/src/eth_rpc/servers/debug_rpc.rs index 4c083f0e2..88aa1f68e 100644 --- a/src/eth_rpc/servers/debug_rpc.rs +++ b/src/eth_rpc/servers/debug_rpc.rs @@ -12,8 +12,8 @@ use alloy_rlp::Encodable; use jsonrpsee::core::{async_trait, RpcResult as Result}; use reth_primitives::{Block, Bytes, Header, Log, Receipt, ReceiptWithBloom, TransactionSigned, B256}; use reth_rpc_types::{ - trace::geth::{GethDebugTracingOptions, GethTrace, TraceResult}, - BlockId, BlockNumberOrTag, + trace::geth::{GethDebugTracingCallOptions, GethDebugTracingOptions, GethTrace, TraceResult}, + BlockId, BlockNumberOrTag, TransactionRequest, }; use std::sync::Arc; @@ -32,7 +32,7 @@ impl DebugRpc

{ #[async_trait] impl DebugApiServer for DebugRpc

{ /// Returns an RLP-encoded header. - #[tracing::instrument(skip(self), err, fields(block_id = ?block_id))] + #[tracing::instrument(skip(self), err)] async fn raw_header(&self, block_id: BlockId) -> Result { tracing::info!("Serving debug_getRawHeader"); @@ -52,7 +52,7 @@ impl DebugApiServer for DebugRpc

} /// Returns an RLP-encoded block. - #[tracing::instrument(skip(self), err, fields(block_id = ?block_id))] + #[tracing::instrument(skip(self), err)] async fn raw_block(&self, block_id: BlockId) -> Result { tracing::info!("Serving debug_getRawBlock"); @@ -72,7 +72,7 @@ impl DebugApiServer for DebugRpc

/// Returns a EIP-2718 binary-encoded transaction. /// /// If this is a pooled EIP-4844 transaction, the blob sidecar is included. - #[tracing::instrument(skip(self), err, fields(hash = ?hash))] + #[tracing::instrument(skip(self), err)] async fn raw_transaction(&self, hash: B256) -> Result> { tracing::info!("Serving debug_getRawTransaction"); @@ -97,7 +97,7 @@ impl DebugApiServer for DebugRpc

} /// Returns an array of EIP-2718 binary-encoded transactions for the given [BlockId]. - #[tracing::instrument(skip(self), err, fields(block_id = ?block_id))] + #[tracing::instrument(skip(self), err)] async fn raw_transactions(&self, block_id: BlockId) -> Result> { tracing::info!("Serving debug_getRawTransactions"); @@ -123,7 +123,7 @@ impl DebugApiServer for DebugRpc

} /// Returns an array of EIP-2718 binary-encoded receipts. - #[tracing::instrument(skip(self), err, fields(block_id = ?block_id))] + #[tracing::instrument(skip(self), err)] async fn raw_receipts(&self, block_id: BlockId) -> Result> { tracing::info!("Serving debug_getRawReceipts"); @@ -168,7 +168,7 @@ impl DebugApiServer for DebugRpc

} /// Returns the Geth debug trace for the given block number. - #[tracing::instrument(skip(self), err, fields(block_number = ?block_number, opts = ?opts))] + #[tracing::instrument(skip(self), err)] async fn trace_block_by_number( &self, block_number: BlockNumberOrTag, @@ -188,7 +188,7 @@ impl DebugApiServer for DebugRpc

} /// Returns the Geth debug trace for the given block hash. - #[tracing::instrument(skip(self), err, fields(block_hash = ?block_hash, opts = ?opts))] + #[tracing::instrument(skip(self), err)] async fn trace_block_by_hash( &self, block_hash: B256, @@ -207,7 +207,7 @@ impl DebugApiServer for DebugRpc

} /// Returns the Geth debug trace for the given transaction hash. - #[tracing::instrument(skip(self), err, fields(transaction_hash = ?transaction_hash, opts = ?opts))] + #[tracing::instrument(skip(self), err)] async fn trace_transaction( &self, transaction_hash: B256, @@ -224,4 +224,24 @@ impl DebugApiServer for DebugRpc

Ok(tracer.debug_transaction(transaction_hash)?) } + + /// Runs an `eth_call` within the context of a given block execution and returns the Geth debug trace. + #[tracing::instrument(skip(self), err)] + async fn trace_call( + &self, + request: TransactionRequest, + block_number: Option, + opts: Option, + ) -> Result { + tracing::info!("Serving debug_traceCall"); + + let tracer = TracerBuilder::new(Arc::new(&self.eth_provider)) + .await? + .with_block_id(block_number.unwrap_or_default()) + .await? + .with_tracing_options(opts.unwrap_or_default().into()) + .build()?; + + Ok(tracer.debug_transaction_request(&request)?) + } } diff --git a/src/tracing/builder.rs b/src/tracing/builder.rs index d18f102f3..b8bf1d9eb 100644 --- a/src/tracing/builder.rs +++ b/src/tracing/builder.rs @@ -6,7 +6,8 @@ use crate::eth_provider::{ use reth_primitives::{B256, U256}; use reth_revm::primitives::{BlockEnv, CfgEnv, Env, EnvWithHandlerCfg, HandlerCfg, SpecId}; use reth_rpc_types::{ - trace::geth::GethDebugTracingOptions, Block, BlockHashOrNumber, BlockId, BlockTransactions, Header, + trace::geth::{GethDebugTracingCallOptions, GethDebugTracingOptions}, + Block, BlockHashOrNumber, BlockId, BlockTransactions, Header, }; use revm_inspectors::tracing::TracingInspectorConfig; @@ -22,6 +23,40 @@ pub enum TracingOptions { Geth(GethDebugTracingOptions), /// Parity tracing options. Parity(TracingInspectorConfig), + /// Geth debug call tracing options. + GethCall(GethDebugTracingCallOptions), +} + +impl TracingOptions { + /// Returns `Some` with a reference to [`GethDebugTracingOptions`] if this is `Geth`, + /// otherwise returns `None`. + pub const fn as_geth(&self) -> Option<&GethDebugTracingOptions> { + if let Self::Geth(ref options) = self { + Some(options) + } else { + None + } + } + + /// Returns `Some` with a reference to [`TracingInspectorConfig`] if this is `Parity`, + /// otherwise returns `None`. + pub const fn as_parity(&self) -> Option<&TracingInspectorConfig> { + if let Self::Parity(ref config) = self { + Some(config) + } else { + None + } + } + + /// Returns `Some` with a reference to [`GethDebugTracingCallOptions`] if this is `GethCall`, + /// otherwise returns `None`. + pub const fn as_geth_call(&self) -> Option<&GethDebugTracingCallOptions> { + if let Self::GethCall(ref options) = self { + Some(options) + } else { + None + } + } } impl Default for TracingOptions { @@ -42,6 +77,12 @@ impl From for TracingOptions { } } +impl From for TracingOptions { + fn from(options: GethDebugTracingCallOptions) -> Self { + Self::GethCall(options) + } +} + #[derive(Debug)] pub struct TracerBuilder { eth_provider: P, @@ -113,7 +154,7 @@ impl TracerBuilder { .ok_or(match block_id { BlockId::Hash(hash) => EthApiError::UnknownBlock(hash.block_hash.into()), BlockId::Number(number) => { - EthApiError::UnknownBlock(BlockHashOrNumber::Number(number.as_number().unwrap())) + EthApiError::UnknownBlock(BlockHashOrNumber::Number(number.as_number().unwrap_or_default())) } })?; diff --git a/src/tracing/mod.rs b/src/tracing/mod.rs index 3102a370e..83bcf5915 100644 --- a/src/tracing/mod.rs +++ b/src/tracing/mod.rs @@ -14,15 +14,19 @@ use reth_evm_ethereum::EthEvmConfig; use reth_node_api::{ConfigureEvm, ConfigureEvmEnv}; use reth_primitives::{ruint::FromUintError, B256}; use reth_revm::{ - primitives::{Env, EnvWithHandlerCfg, ExecutionResult, ResultAndState}, + primitives::{CfgEnvWithHandlerCfg, Env, EnvWithHandlerCfg, ExecutionResult, ResultAndState}, Database, DatabaseCommit, }; +use reth_rpc_eth_types::revm_utils::build_call_evm_env; use reth_rpc_types::{ trace::{ - geth::{GethDebugBuiltInTracerType, GethDebugTracerType, GethDebugTracingOptions, GethTrace, TraceResult}, + geth::{ + GethDebugBuiltInTracerType, GethDebugTracerType, GethDebugTracingCallOptions, GethDebugTracingOptions, + GethTrace, TraceResult, + }, parity::LocalizedTransactionTrace, }, - TransactionInfo, + TransactionInfo, TransactionRequest, }; use revm_inspectors::tracing::{TracingInspector, TracingInspectorConfig}; use std::collections::HashMap; @@ -43,7 +47,7 @@ enum TracingResult { impl TracingResult { /// Converts the tracing result into Geth traces. - fn into_geth(self) -> Option> { + const fn as_geth(&self) -> Option<&Vec> { if let Self::Geth(traces) = self { Some(traces) } else { @@ -52,18 +56,17 @@ impl TracingResult { } /// Converts the tracing result into Parity traces. - fn into_parity(self) -> Option> { + const fn as_parity(&self) -> Option<&Vec> { if let Self::Parity(traces) = self { Some(traces) } else { None } } - - /// Creates a default failure `TracingResult` based on the `TracingOptions`. + /// Creates a default failure [`TracingResult`] based on the [`TracingOptions`]. fn default_failure(tracing_options: &TracingOptions, tx: &reth_rpc_types::Transaction) -> Self { match tracing_options { - TracingOptions::Geth(_) => Self::Geth(vec![TraceResult::Success { + TracingOptions::Geth(_) | TracingOptions::GethCall(_) => Self::Geth(vec![TraceResult::Success { result: GethTrace::Default(reth_rpc_types::trace::geth::DefaultFrame { failed: true, ..Default::default() @@ -196,14 +199,14 @@ impl Tracer

{ /// Trace the block in the parity format. pub fn trace_block(self) -> TracerResult>> { let txs = self.transactions.clone(); - Ok(Some(self.trace_transactions(TracingResult::into_parity, &txs)?)) + Ok(Some(self.trace_transactions(TracingResult::as_parity, &txs)?)) } /// Returns the debug trace in the Geth. /// Currently only supports the call tracer or the default tracer. pub fn debug_block(self) -> TracerResult> { let txs = self.transactions.clone(); - self.trace_transactions(TracingResult::into_geth, &txs) + self.trace_transactions(TracingResult::as_geth, &txs) } pub fn debug_transaction(mut self, transaction_hash: B256) -> TracerResult { @@ -211,7 +214,7 @@ impl Tracer

{ if tx.hash == transaction_hash { // We only want to trace the transaction with the given hash. let trace = self - .trace_transactions(TracingResult::into_geth, &[tx])? + .trace_transactions(TracingResult::as_geth, &[tx])? .first() .cloned() .ok_or(TransactionError::Tracing(eyre!("No trace found").into()))?; @@ -229,15 +232,84 @@ impl Tracer

{ Err(EthApiError::TransactionNotFound(transaction_hash)) } + /// Debugs a transaction request by tracing it using the provided tracing options. + /// + /// This function returns an error if the tracing options are not supported or if there is an issue + /// with the EVM environment or transaction execution. + pub fn debug_transaction_request(self, request: &TransactionRequest) -> TracerResult { + // Attempt to get Geth tracing options from the provided tracing options. + let opts = self + .tracing_options + .as_geth_call() + .ok_or_else(|| { + // Return an error if the tracing options are not supported. + EthApiError::Transaction(TransactionError::Tracing( + eyre!("only `GethDebugTracingCallOptions` tracing options are supported for call tracing").into(), + )) + })? + .clone(); + + // Extract the tracing options from the obtained Geth tracing options. + let GethDebugTracingCallOptions { tracing_options, .. } = opts; + let GethDebugTracingOptions { tracer, tracer_config, .. } = tracing_options; + + // Check if a tracer is provided. + if let Some(tracer) = tracer { + match tracer { + // Only support CallTracer for now. + GethDebugTracerType::BuiltInTracer(GethDebugBuiltInTracerType::CallTracer) => { + // Build the EVM environment using the provided configuration and request. + + let env = build_call_evm_env( + CfgEnvWithHandlerCfg { cfg_env: self.env.cfg.clone(), handler_cfg: self.env.handler_cfg }, + self.env.block.clone(), + request.clone(), + )?; + + // Convert the tracer configuration into call configuration. + let call_config = + tracer_config.into_call_config().map_err(|err| TransactionError::Tracing(err.into()))?; + + // Create a new tracing inspector with the call configuration. + let mut inspector = + TracingInspector::new(TracingInspectorConfig::from_geth_call_config(&call_config)); + + // Build EVM with environment and inspector. + let eth_evm_config = EthEvmConfig::default(); + let evm = eth_evm_config.evm_with_env_and_inspector(self.db, env, &mut inspector); + + // Execute the transaction. + let res = transact_in_place(evm)?; + + // Get the call traces from the inspector. + let frame = inspector.into_geth_builder().geth_call_traces(call_config, res.result.gas_used()); + + // Return the obtained call traces. + return Ok(frame.into()); + } + + // Return an error for unsupported tracers. + _ => { + return Err(EthApiError::Transaction(TransactionError::Tracing( + eyre!("only call tracer is currently supported").into(), + ))) + } + } + } + + // Return a default Geth trace if no tracer is provided. + Ok(GethTrace::Default(Default::default())) + } + /// Traces the provided transactions using the given closure. /// The `convert_result` closure takes the resulting tracing result /// and converts it into the desired type. - fn trace_transactions( + fn trace_transactions( self, - convert_result: fn(TracingResult) -> Option>, + convert_result: fn(&TracingResult) -> Option<&Vec>, transactions: &[reth_rpc_types::Transaction], ) -> TracerResult> { - let mut traces = Vec::with_capacity(self.transactions.len()); + let mut traces: Vec = Vec::with_capacity(self.transactions.len()); let mut transactions = transactions.iter().peekable(); let mut db = self.db; @@ -253,10 +325,18 @@ impl Tracer

{ TracingOptions::Parity(tracing_config) => { Self::trace_parity(env, &mut db, tx, *tracing_config)? } + TracingOptions::GethCall(_) => { + return Err(EthApiError::Transaction(TransactionError::Tracing( + eyre!("`TracingOptions::GethCall` is not supported in `trace_transactions` context") + .into(), + ))) + } } }; - traces.extend(convert_result(res).unwrap_or_default()); + if let Some(result) = convert_result(&res) { + traces.append(&mut result.clone()); + } // Only commit to the database if there are more transactions to process. if transactions.peek().is_some() { diff --git a/tests/tests/trace_api.rs b/tests/tests/trace_api.rs index 2596b6ef4..d60584fcf 100644 --- a/tests/tests/trace_api.rs +++ b/tests/tests/trace_api.rs @@ -1,6 +1,7 @@ #![allow(clippy::used_underscore_binding)] #![cfg(feature = "testing")] use alloy_dyn_abi::DynSolValue; +use alloy_sol_types::{sol, SolCall}; use kakarot_rpc::{ eth_provider::provider::EthereumProvider, test_utils::{ @@ -11,13 +12,17 @@ use kakarot_rpc::{ rpc::{start_kakarot_rpc_server, RawRpcParamsBuilder}, }, }; -use reth_primitives::{Address, Bytes, B256, U256}; +use reth_primitives::{Address, BlockId, Bytes, TxKind, B256, U256}; use reth_rpc_types::{ + request::TransactionInput, trace::{ - geth::{GethTrace, TraceResult}, + geth::{ + CallFrame, GethDebugBuiltInTracerType, GethDebugTracerType, GethDebugTracingCallOptions, + GethDebugTracingOptions, GethTrace, TraceResult, + }, parity::{Action, CallAction, CallOutput, CallType, LocalizedTransactionTrace, TraceOutput, TransactionTrace}, }, - OtherFields, + OtherFields, TransactionRequest, }; use rstest::*; use serde_json::{json, Value}; @@ -301,3 +306,163 @@ async fn test_debug_trace_transaction(#[future] plain_opcodes: (Katana, KakarotE drop(server_handle); } + +#[rstest] +#[awt] +#[tokio::test(flavor = "multi_thread")] +async fn test_trace_call(#[future] plain_opcodes: (Katana, KakarotEvmContract), _setup: ()) { + // Setup the Kakarot RPC server. + let katana = plain_opcodes.0; + let plain_opcodes = plain_opcodes.1; + tracing(&katana, &plain_opcodes, "createCounterAndInvoke", Box::new(|_| vec![])).await; + + let (server_addr, server_handle) = + start_kakarot_rpc_server(&katana).await.expect("Error setting up Kakarot RPC server"); + + // Create the transaction request + let request = TransactionRequest { + from: Some(katana.eoa().evm_address().expect("Failed to get eoa address")), + to: Some(TxKind::Call(Address::ZERO)), + gas: Some(21000), + gas_price: Some(10), + value: Some(U256::ZERO), + nonce: Some(2), + ..Default::default() + }; + + // Define the call options + let call_opts = GethDebugTracingCallOptions { + tracing_options: GethDebugTracingOptions::default() + .with_tracer(GethDebugTracerType::BuiltInTracer(GethDebugBuiltInTracerType::CallTracer)), + state_overrides: Default::default(), + block_overrides: Default::default(), + }; + + // Send the trace_call RPC request. + let reqwest_client = reqwest::Client::new(); + let res = reqwest_client + .post(format!("http://localhost:{}", server_addr.port())) + .header("Content-Type", "application/json") + .body( + RawRpcParamsBuilder::new("debug_traceCall") + .add_param(request) + .add_param(Some(BlockId::Number(TRACING_BLOCK_NUMBER.into()))) + .add_param(call_opts) + .build(), + ) + .send() + .await + .expect("Failed to call Debug RPC"); + let response = res.text().await.expect("Failed to get response body"); + let raw: Value = serde_json::from_str(&response).expect("Failed to deserialize response body"); + let trace: GethTrace = serde_json::from_value(raw["result"].clone()).expect("Failed to deserialize result"); + + // Assert that the trace contains expected data + assert_eq!( + trace, + GethTrace::CallTracer(CallFrame { + from: katana.eoa().evm_address().expect("Failed to get eoa address"), + gas: U256::from(21000), + gas_used: U256::from(21000), + to: Some(Address::ZERO), + value: Some(U256::ZERO), + typ: "CALL".to_string(), + ..Default::default() + }) + ); + + drop(server_handle); +} + +#[rstest] +#[awt] +#[tokio::test(flavor = "multi_thread")] +async fn test_trace_call_counter(#[future] plain_opcodes: (Katana, KakarotEvmContract), _setup: ()) { + // Test function for tracing a call to a counter contract + + // Extract Katana instance and get the EOA's EVM address + let katana = plain_opcodes.0; + let evm_address = katana.eoa().evm_address().expect("Failed to get eoa address"); + let plain_opcodes = plain_opcodes.1; + + // Perform tracing setup + tracing(&katana, &plain_opcodes, "createCounterAndInvoke", Box::new(|_| vec![])).await; + + // Start the Kakarot RPC server + let (server_addr, server_handle) = + start_kakarot_rpc_server(&katana).await.expect("Error setting up Kakarot RPC server"); + + // Define a Solidity contract interface for the counter + sol! { + #[sol(rpc)] + contract CounterContract { + function incForLoop(uint256 iterations) external; + } + } + + // Prepare the calldata for invoking the incForLoop function with 5 iterations + let calldata = CounterContract::incForLoopCall { iterations: U256::from(5) }.abi_encode(); + let contract_address = Address::from_slice(&plain_opcodes.evm_address.to_bytes_be()[12..]); + + // Define the transaction request + let request = TransactionRequest { + from: Some(evm_address), + to: Some(TxKind::Call(contract_address)), + gas: Some(210_000), + gas_price: Some(1_000_000_000_000_000_000_000), + value: Some(U256::ZERO), + nonce: Some(2), + input: TransactionInput { input: Some(calldata.clone().into()), data: None }, + ..Default::default() + }; + + // Configure tracing options + let call_opts = GethDebugTracingCallOptions { + tracing_options: GethDebugTracingOptions::default() + .with_tracer(GethDebugTracerType::BuiltInTracer(GethDebugBuiltInTracerType::CallTracer)) + .with_timeout(std::time::Duration::from_secs(300)) + .with_call_config(reth_rpc_types::trace::geth::CallConfig { only_top_call: Some(false), with_log: None }), + state_overrides: Default::default(), + block_overrides: Default::default(), + }; + + // Send a trace_call RPC request + let reqwest_client = reqwest::Client::new(); + let res = reqwest_client + .post(format!("http://localhost:{}", server_addr.port())) + .header("Content-Type", "application/json") + .body( + RawRpcParamsBuilder::new("debug_traceCall") + .add_param(request) + .add_param(Some(BlockId::Number(TRACING_BLOCK_NUMBER.into()))) + .add_param(call_opts) + .build(), + ) + .send() + .await + .expect("Failed to call Debug RPC"); + + // Process the response + let response = res.text().await.expect("Failed to get response body"); + let raw: Value = serde_json::from_str(&response).expect("Failed to deserialize response body"); + let trace: GethTrace = + serde_json::from_value(raw["result"].clone()).expect("Failed to deserialize result from trace"); + + // Assert that the trace result matches expectations + assert_eq!( + trace, + GethTrace::CallTracer(CallFrame { + from: evm_address, + gas: U256::from(210_000), + gas_used: U256::from(21410), + to: Some(contract_address), + value: Some(U256::ZERO), + typ: "CALL".to_string(), + input: calldata.into(), + ..Default::default() + }) + ); + + // Clean up by dropping the server handle + drop(server_handle); +}