reth_rpc_api/debug.rs
1use alloy_eips::{BlockId, BlockNumberOrTag};
2use alloy_genesis::ChainConfig;
3use alloy_json_rpc::RpcObject;
4use alloy_primitives::{Address, Bytes, B256};
5use alloy_rpc_types_debug::ExecutionWitness;
6use alloy_rpc_types_eth::{Block, Bundle, StateContext};
7use alloy_rpc_types_trace::geth::{
8 BlockTraceResult, GethDebugTracingCallOptions, GethDebugTracingOptions, GethTrace, TraceResult,
9};
10use jsonrpsee::{core::RpcResult, proc_macros::rpc};
11use reth_trie_common::{updates::TrieUpdates, HashedPostState};
12
13/// Debug rpc interface.
14#[cfg_attr(not(feature = "client"), rpc(server, namespace = "debug"))]
15#[cfg_attr(feature = "client", rpc(server, client, namespace = "debug"))]
16pub trait DebugApi<TxReq: RpcObject> {
17 /// Returns an RLP-encoded header.
18 #[method(name = "getRawHeader")]
19 async fn raw_header(&self, block_id: BlockId) -> RpcResult<Bytes>;
20
21 /// Returns an RLP-encoded block.
22 #[method(name = "getRawBlock")]
23 async fn raw_block(&self, block_id: BlockId) -> RpcResult<Bytes>;
24
25 /// Returns a EIP-2718 binary-encoded transaction.
26 ///
27 /// If this is a pooled EIP-4844 transaction, the blob sidecar is included.
28 #[method(name = "getRawTransaction")]
29 async fn raw_transaction(&self, hash: B256) -> RpcResult<Option<Bytes>>;
30
31 /// Returns an array of EIP-2718 binary-encoded transactions for the given [`BlockId`].
32 #[method(name = "getRawTransactions")]
33 async fn raw_transactions(&self, block_id: BlockId) -> RpcResult<Vec<Bytes>>;
34
35 /// Returns an array of EIP-2718 binary-encoded receipts.
36 #[method(name = "getRawReceipts")]
37 async fn raw_receipts(&self, block_id: BlockId) -> RpcResult<Vec<Bytes>>;
38
39 /// Returns an array of recent bad blocks that the client has seen on the network.
40 #[method(name = "getBadBlocks")]
41 async fn bad_blocks(&self) -> RpcResult<Vec<Block>>;
42
43 /// Returns the structured logs created during the execution of EVM between two blocks
44 /// (excluding start) as a JSON object.
45 #[method(name = "traceChain")]
46 async fn debug_trace_chain(
47 &self,
48 start_exclusive: BlockNumberOrTag,
49 end_inclusive: BlockNumberOrTag,
50 ) -> RpcResult<Vec<BlockTraceResult>>;
51
52 /// The `debug_traceBlock` method will return a full stack trace of all invoked opcodes of all
53 /// transaction that were included in this block.
54 ///
55 /// This expects an rlp encoded block
56 ///
57 /// Note, the parent of this block must be present, or it will fail. For the second parameter
58 /// see [`GethDebugTracingOptions`] reference.
59 #[method(name = "traceBlock")]
60 async fn debug_trace_block(
61 &self,
62 rlp_block: Bytes,
63 opts: Option<GethDebugTracingOptions>,
64 ) -> RpcResult<Vec<TraceResult>>;
65
66 /// Similar to `debug_traceBlock`, `debug_traceBlockByHash` accepts a block hash and will replay
67 /// the block that is already present in the database. For the second parameter see
68 /// [`GethDebugTracingOptions`].
69 #[method(name = "traceBlockByHash")]
70 async fn debug_trace_block_by_hash(
71 &self,
72 block: B256,
73 opts: Option<GethDebugTracingOptions>,
74 ) -> RpcResult<Vec<TraceResult>>;
75
76 /// Similar to `debug_traceBlockByHash`, `debug_traceBlockByNumber` accepts a block number
77 /// [`BlockNumberOrTag`] and will replay the block that is already present in the database.
78 /// For the second parameter see [`GethDebugTracingOptions`].
79 #[method(name = "traceBlockByNumber")]
80 async fn debug_trace_block_by_number(
81 &self,
82 block: BlockNumberOrTag,
83 opts: Option<GethDebugTracingOptions>,
84 ) -> RpcResult<Vec<TraceResult>>;
85
86 /// The `debug_traceTransaction` debugging method will attempt to run the transaction in the
87 /// exact same manner as it was executed on the network. It will replay any transaction that
88 /// may have been executed prior to this one before it will finally attempt to execute the
89 /// transaction that corresponds to the given hash.
90 #[method(name = "traceTransaction")]
91 async fn debug_trace_transaction(
92 &self,
93 tx_hash: B256,
94 opts: Option<GethDebugTracingOptions>,
95 ) -> RpcResult<GethTrace>;
96
97 /// The `debug_traceCall` method lets you run an `eth_call` within the context of the given
98 /// block execution using the final state of parent block as the base.
99 ///
100 /// The first argument (just as in `eth_call`) is a transaction request.
101 /// The block can optionally be specified either by hash or by number as
102 /// the second argument.
103 /// The trace can be configured similar to `debug_traceTransaction`,
104 /// see [`GethDebugTracingOptions`]. The method returns the same output as
105 /// `debug_traceTransaction`.
106 #[method(name = "traceCall")]
107 async fn debug_trace_call(
108 &self,
109 request: TxReq,
110 block_id: Option<BlockId>,
111 opts: Option<GethDebugTracingCallOptions>,
112 ) -> RpcResult<GethTrace>;
113
114 /// The `debug_traceCallMany` method lets you run an `eth_callMany` within the context of the
115 /// given block execution using the final state of parent block as the base followed by n
116 /// transactions.
117 ///
118 /// The first argument is a list of bundles. Each bundle can overwrite the block headers. This
119 /// will affect all transaction in that bundle.
120 /// `BlockNumber` and `transaction_index` are optional. `Transaction_index`
121 /// specifies the number of tx in the block to replay and -1 means all transactions should be
122 /// replayed.
123 /// The trace can be configured similar to `debug_traceTransaction`.
124 /// State override apply to all bundles.
125 ///
126 /// This methods is similar to many `eth_callMany`, hence this returns nested lists of traces.
127 /// Where the length of the outer list is the number of bundles and the length of the inner list
128 /// (`Vec<GethTrace>`) is the number of transactions in the bundle.
129 #[method(name = "traceCallMany")]
130 async fn debug_trace_call_many(
131 &self,
132 bundles: Vec<Bundle<TxReq>>,
133 state_context: Option<StateContext>,
134 opts: Option<GethDebugTracingCallOptions>,
135 ) -> RpcResult<Vec<Vec<GethTrace>>>;
136
137 /// The `debug_executionWitness` method allows for re-execution of a block with the purpose of
138 /// generating an execution witness. The witness comprises of a map of all hashed trie nodes
139 /// to their preimages that were required during the execution of the block, including during
140 /// state root recomputation.
141 ///
142 /// The first argument is the block number or tag.
143 #[method(name = "executionWitness")]
144 async fn debug_execution_witness(&self, block: BlockNumberOrTag)
145 -> RpcResult<ExecutionWitness>;
146
147 /// The `debug_executionWitnessByBlockHash` method allows for re-execution of a block with the
148 /// purpose of generating an execution witness. The witness comprises of a map of all hashed
149 /// trie nodes to their preimages that were required during the execution of the block,
150 /// including during state root recomputation.
151 ///
152 /// The first argument is the block hash.
153 #[method(name = "executionWitnessByBlockHash")]
154 async fn debug_execution_witness_by_block_hash(
155 &self,
156 hash: B256,
157 ) -> RpcResult<ExecutionWitness>;
158
159 /// Sets the logging backtrace location. When a backtrace location is set and a log message is
160 /// emitted at that location, the stack of the goroutine executing the log statement will
161 /// be printed to stderr.
162 #[method(name = "backtraceAt")]
163 async fn debug_backtrace_at(&self, location: &str) -> RpcResult<()>;
164
165 /// Enumerates all accounts at a given block with paging capability. `maxResults` are returned
166 /// in the page and the items have keys that come after the `start` key (hashed address).
167 ///
168 /// If incompletes is false, then accounts for which the key preimage (i.e: the address) doesn't
169 /// exist in db are skipped. NB: geth by default does not store preimages.
170 #[method(name = "accountRange")]
171 async fn debug_account_range(
172 &self,
173 block_number: BlockNumberOrTag,
174 start: Bytes,
175 max_results: u64,
176 nocode: bool,
177 nostorage: bool,
178 incompletes: bool,
179 ) -> RpcResult<()>;
180
181 /// Turns on block profiling for the given duration and writes profile data to disk. It uses a
182 /// profile rate of 1 for most accurate information. If a different rate is desired, set the
183 /// rate and write the profile manually using `debug_writeBlockProfile`.
184 #[method(name = "blockProfile")]
185 async fn debug_block_profile(&self, file: String, seconds: u64) -> RpcResult<()>;
186
187 /// Flattens the entire key-value database into a single level, removing all unused slots and
188 /// merging all keys.
189 #[method(name = "chaindbCompact")]
190 async fn debug_chaindb_compact(&self) -> RpcResult<()>;
191
192 /// Returns the current chain config.
193 #[method(name = "chainConfig")]
194 async fn debug_chain_config(&self) -> RpcResult<ChainConfig>;
195
196 /// Returns leveldb properties of the key-value database.
197 #[method(name = "chaindbProperty")]
198 async fn debug_chaindb_property(&self, property: String) -> RpcResult<()>;
199
200 /// Returns the code associated with a given hash at the specified block ID.
201 /// If no block ID is provided, it defaults to the latest block.
202 #[method(name = "codeByHash")]
203 async fn debug_code_by_hash(
204 &self,
205 hash: B256,
206 block_id: Option<BlockId>,
207 ) -> RpcResult<Option<Bytes>>;
208
209 /// Turns on CPU profiling for the given duration and writes profile data to disk.
210 #[method(name = "cpuProfile")]
211 async fn debug_cpu_profile(&self, file: String, seconds: u64) -> RpcResult<()>;
212
213 /// Retrieves an ancient binary blob from the freezer. The freezer is a collection of
214 /// append-only immutable files. The first argument `kind` specifies which table to look up data
215 /// from. The list of all table kinds are as follows:
216 #[method(name = "dbAncient")]
217 async fn debug_db_ancient(&self, kind: String, number: u64) -> RpcResult<()>;
218
219 /// Returns the number of ancient items in the ancient store.
220 #[method(name = "dbAncients")]
221 async fn debug_db_ancients(&self) -> RpcResult<()>;
222
223 /// Returns the raw value of a key stored in the database.
224 #[method(name = "dbGet")]
225 async fn debug_db_get(&self, key: String) -> RpcResult<()>;
226
227 /// Retrieves the state that corresponds to the block number and returns a list of accounts
228 /// (including storage and code).
229 #[method(name = "dumpBlock")]
230 async fn debug_dump_block(&self, number: BlockId) -> RpcResult<()>;
231
232 /// Forces garbage collection.
233 #[method(name = "freeOSMemory")]
234 async fn debug_free_os_memory(&self) -> RpcResult<()>;
235
236 /// Forces a temporary client freeze, normally when the server is overloaded.
237 #[method(name = "freezeClient")]
238 async fn debug_freeze_client(&self, node: String) -> RpcResult<()>;
239
240 /// Returns garbage collection statistics.
241 #[method(name = "gcStats")]
242 async fn debug_gc_stats(&self) -> RpcResult<()>;
243
244 /// Returns the first number where the node has accessible state on disk. This is the
245 /// post-state of that block and the pre-state of the next block. The (from, to) parameters
246 /// are the sequence of blocks to search, which can go either forwards or backwards.
247 ///
248 /// Note: to get the last state pass in the range of blocks in reverse, i.e. (last, first).
249 #[method(name = "getAccessibleState")]
250 async fn debug_get_accessible_state(
251 &self,
252 from: BlockNumberOrTag,
253 to: BlockNumberOrTag,
254 ) -> RpcResult<()>;
255
256 /// Returns all accounts that have changed between the two blocks specified. A change is defined
257 /// as a difference in nonce, balance, code hash, or storage hash. With one parameter, returns
258 /// the list of accounts modified in the specified block.
259 #[method(name = "getModifiedAccountsByHash")]
260 async fn debug_get_modified_accounts_by_hash(
261 &self,
262 start_hash: B256,
263 end_hash: B256,
264 ) -> RpcResult<()>;
265
266 /// Returns all accounts that have changed between the two blocks specified. A change is defined
267 /// as a difference in nonce, balance, code hash or storage hash.
268 #[method(name = "getModifiedAccountsByNumber")]
269 async fn debug_get_modified_accounts_by_number(
270 &self,
271 start_number: u64,
272 end_number: u64,
273 ) -> RpcResult<()>;
274
275 /// Turns on Go runtime tracing for the given duration and writes trace data to disk.
276 #[method(name = "goTrace")]
277 async fn debug_go_trace(&self, file: String, seconds: u64) -> RpcResult<()>;
278
279 /// Executes a block (bad- or canon- or side-), and returns a list of intermediate roots: the
280 /// stateroot after each transaction.
281 #[method(name = "intermediateRoots")]
282 async fn debug_intermediate_roots(
283 &self,
284 block_hash: B256,
285 opts: Option<GethDebugTracingCallOptions>,
286 ) -> RpcResult<()>;
287
288 /// Returns detailed runtime memory statistics.
289 #[method(name = "memStats")]
290 async fn debug_mem_stats(&self) -> RpcResult<()>;
291
292 /// Turns on mutex profiling for `nsec` seconds and writes profile data to file. It uses a
293 /// profile rate of 1 for most accurate information. If a different rate is desired, set the
294 /// rate and write the profile manually.
295 #[method(name = "mutexProfile")]
296 async fn debug_mutex_profile(&self, file: String, nsec: u64) -> RpcResult<()>;
297
298 /// Returns the preimage for a sha3 hash, if known.
299 #[method(name = "preimage")]
300 async fn debug_preimage(&self, hash: B256) -> RpcResult<()>;
301
302 /// Retrieves a block and returns its pretty printed form.
303 #[method(name = "printBlock")]
304 async fn debug_print_block(&self, number: u64) -> RpcResult<()>;
305
306 /// Fetches and retrieves the seed hash of the block by number.
307 #[method(name = "seedHash")]
308 async fn debug_seed_hash(&self, number: u64) -> RpcResult<B256>;
309
310 /// Sets the rate (in samples/sec) of goroutine block profile data collection. A non-zero rate
311 /// enables block profiling, setting it to zero stops the profile. Collected profile data can be
312 /// written using `debug_writeBlockProfile`.
313 #[method(name = "setBlockProfileRate")]
314 async fn debug_set_block_profile_rate(&self, rate: u64) -> RpcResult<()>;
315
316 /// Sets the garbage collection target percentage. A negative value disables garbage collection.
317 #[method(name = "setGCPercent")]
318 async fn debug_set_gc_percent(&self, v: i32) -> RpcResult<()>;
319
320 /// Sets the current head of the local chain by block number. Note, this is a destructive action
321 /// and may severely damage your chain. Use with extreme caution.
322 #[method(name = "setHead")]
323 async fn debug_set_head(&self, number: u64) -> RpcResult<()>;
324
325 /// Sets the rate of mutex profiling.
326 #[method(name = "setMutexProfileFraction")]
327 async fn debug_set_mutex_profile_fraction(&self, rate: i32) -> RpcResult<()>;
328
329 /// Configures how often in-memory state tries are persisted to disk. The interval needs to be
330 /// in a format parsable by a time.Duration. Note that the interval is not wall-clock time.
331 /// Rather it is accumulated block processing time after which the state should be flushed.
332 #[method(name = "setTrieFlushInterval")]
333 async fn debug_set_trie_flush_interval(&self, interval: String) -> RpcResult<()>;
334
335 /// Returns a printed representation of the stacks of all goroutines.
336 #[method(name = "stacks")]
337 async fn debug_stacks(&self) -> RpcResult<()>;
338
339 /// Used to obtain info about a block.
340 #[method(name = "standardTraceBadBlockToFile")]
341 async fn debug_standard_trace_bad_block_to_file(
342 &self,
343 block: BlockNumberOrTag,
344 opts: Option<GethDebugTracingCallOptions>,
345 ) -> RpcResult<()>;
346
347 /// This method is similar to `debug_standardTraceBlockToFile`, but can be used to obtain info
348 /// about a block which has been rejected as invalid (for some reason).
349 #[method(name = "standardTraceBlockToFile")]
350 async fn debug_standard_trace_block_to_file(
351 &self,
352 block: BlockNumberOrTag,
353 opts: Option<GethDebugTracingCallOptions>,
354 ) -> RpcResult<()>;
355
356 /// Turns on CPU profiling indefinitely, writing to the given file.
357 #[method(name = "startCPUProfile")]
358 async fn debug_start_cpu_profile(&self, file: String) -> RpcResult<()>;
359
360 /// Starts writing a Go runtime trace to the given file.
361 #[method(name = "startGoTrace")]
362 async fn debug_start_go_trace(&self, file: String) -> RpcResult<()>;
363
364 /// Returns the state root of the `HashedPostState` on top of the state for the given block with
365 /// trie updates.
366 #[method(name = "stateRootWithUpdates")]
367 async fn debug_state_root_with_updates(
368 &self,
369 hashed_state: HashedPostState,
370 block_id: Option<BlockId>,
371 ) -> RpcResult<(B256, TrieUpdates)>;
372
373 /// Stops an ongoing CPU profile.
374 #[method(name = "stopCPUProfile")]
375 async fn debug_stop_cpu_profile(&self) -> RpcResult<()>;
376
377 /// Stops writing the Go runtime trace.
378 #[method(name = "stopGoTrace")]
379 async fn debug_stop_go_trace(&self) -> RpcResult<()>;
380
381 /// Returns the storage at the given block height and transaction index. The result can be
382 /// paged by providing a `maxResult` to cap the number of storage slots returned as well as
383 /// specifying the offset via `keyStart` (hash of storage key).
384 #[method(name = "storageRangeAt")]
385 async fn debug_storage_range_at(
386 &self,
387 block_hash: B256,
388 tx_idx: usize,
389 contract_address: Address,
390 key_start: B256,
391 max_result: u64,
392 ) -> RpcResult<()>;
393
394 /// Returns the structured logs created during the execution of EVM against a block pulled
395 /// from the pool of bad ones and returns them as a JSON object. For the second parameter see
396 /// `TraceConfig` reference.
397 #[method(name = "traceBadBlock")]
398 async fn debug_trace_bad_block(
399 &self,
400 block_hash: B256,
401 opts: Option<GethDebugTracingCallOptions>,
402 ) -> RpcResult<()>;
403
404 /// Sets the logging verbosity ceiling. Log messages with level up to and including the given
405 /// level will be printed.
406 #[method(name = "verbosity")]
407 async fn debug_verbosity(&self, level: usize) -> RpcResult<()>;
408
409 /// Sets the logging verbosity pattern.
410 #[method(name = "vmodule")]
411 async fn debug_vmodule(&self, pattern: String) -> RpcResult<()>;
412
413 /// Writes a goroutine blocking profile to the given file.
414 #[method(name = "writeBlockProfile")]
415 async fn debug_write_block_profile(&self, file: String) -> RpcResult<()>;
416
417 /// Writes an allocation profile to the given file.
418 #[method(name = "writeMemProfile")]
419 async fn debug_write_mem_profile(&self, file: String) -> RpcResult<()>;
420
421 /// Writes a goroutine blocking profile to the given file.
422 #[method(name = "writeMutexProfile")]
423 async fn debug_write_mutex_profile(&self, file: String) -> RpcResult<()>;
424}
425
426/// An extension to the `debug_` namespace that provides additional methods for retrieving
427/// witnesses.
428///
429/// This is separate from the regular `debug_` api, because this depends on the network specific
430/// params. For optimism this will expect the optimism specific payload attributes
431#[cfg_attr(not(feature = "client"), rpc(server, namespace = "debug"))]
432#[cfg_attr(feature = "client", rpc(server, client, namespace = "debug"))]
433pub trait DebugExecutionWitnessApi<Attributes> {
434 /// The `debug_executePayload` method allows for re-execution of a group of transactions with
435 /// the purpose of generating an execution witness. The witness comprises of a map of all
436 /// hashed trie nodes to their preimages that were required during the execution of the block,
437 /// including during state root recomputation.
438 ///
439 /// The first argument is the parent block hash. The second argument is the payload
440 /// attributes for the new block.
441 #[method(name = "executePayload")]
442 async fn execute_payload(
443 &self,
444 parent_block_hash: B256,
445 attributes: Attributes,
446 ) -> RpcResult<ExecutionWitness>;
447}