referrerpolicy=no-referrer-when-downgrade

pallet_revive/evm/api/
debug_rpc_types.rs

1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// 	http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18use crate::{Weight, evm::Bytes};
19use alloc::{collections::BTreeMap, string::String, vec::Vec};
20use derive_more::From;
21use pallet_revive_types::runtime_api::*;
22use sp_core::{H160, H256, U256};
23use sp_runtime::ApplyExtrinsicResult;
24
25/// The type of tracer to use.
26#[derive(Debug, Clone, PartialEq, From)]
27pub enum TracerType {
28	/// A tracer that traces calls.
29	CallTracer(Option<CallTracerConfig>),
30
31	/// A tracer that traces the prestate.
32	PrestateTracer(Option<PrestateTracerConfig>),
33
34	/// A tracer that traces opcodes and syscalls.
35	ExecutionTracer(Option<ExecutionTracerConfig>),
36}
37
38impl Default for TracerType {
39	fn default() -> Self {
40		TracerType::ExecutionTracer(Some(ExecutionTracerConfig::default()))
41	}
42}
43
44impl From<TracerTypeV1> for TracerType {
45	fn from(value: TracerTypeV1) -> Self {
46		match value {
47			TracerTypeV1::CallTracer(config) => Self::CallTracer(config.map(Into::into)),
48			TracerTypeV1::PrestateTracer(config) => Self::PrestateTracer(config.map(Into::into)),
49			TracerTypeV1::ExecutionTracer(config) => Self::ExecutionTracer(config.map(Into::into)),
50		}
51	}
52}
53
54/// The configuration for the call tracer.
55#[derive(Clone, Debug, PartialEq)]
56pub struct CallTracerConfig {
57	/// Whether to include logs in the trace.
58	pub with_logs: bool,
59
60	/// Whether to only include the top-level calls in the trace.
61	pub only_top_call: bool,
62}
63
64impl Default for CallTracerConfig {
65	fn default() -> Self {
66		Self { with_logs: true, only_top_call: false }
67	}
68}
69
70impl From<CallTracerConfigV1> for CallTracerConfig {
71	fn from(value: CallTracerConfigV1) -> Self {
72		Self { with_logs: value.with_logs, only_top_call: value.only_top_call }
73	}
74}
75
76/// The configuration for the prestate tracer.
77#[derive(Clone, Debug, PartialEq)]
78pub struct PrestateTracerConfig {
79	/// Whether to include the diff mode in the trace.
80	pub diff_mode: bool,
81
82	/// Whether to include storage in the trace.
83	pub disable_storage: bool,
84
85	/// Whether to include code in the trace.
86	pub disable_code: bool,
87}
88
89impl Default for PrestateTracerConfig {
90	fn default() -> Self {
91		Self { diff_mode: false, disable_storage: false, disable_code: false }
92	}
93}
94
95impl From<PrestateTracerConfigV1> for PrestateTracerConfig {
96	fn from(value: PrestateTracerConfigV1) -> Self {
97		Self {
98			diff_mode: value.diff_mode,
99			disable_storage: value.disable_storage,
100			disable_code: value.disable_code,
101		}
102	}
103}
104
105/// The configuration for the execution tracer.
106#[derive(Clone, Debug, PartialEq)]
107pub struct ExecutionTracerConfig {
108	/// Whether to enable memory capture
109	pub enable_memory: bool,
110
111	/// Whether to disable stack capture
112	pub disable_stack: bool,
113
114	/// Whether to disable storage capture
115	pub disable_storage: bool,
116
117	/// Whether to enable return data capture
118	pub enable_return_data: bool,
119
120	/// Whether to disable syscall details capture, including arguments and return value (PVM only)
121	pub disable_syscall_details: bool,
122
123	/// Limit number of steps captured
124	pub limit: Option<u64>,
125
126	/// Maximum number of memory words to capture per step (default: 16)
127	pub memory_word_limit: u32,
128}
129
130impl Default for ExecutionTracerConfig {
131	fn default() -> Self {
132		Self {
133			enable_memory: false,
134			disable_stack: false,
135			disable_storage: false,
136			enable_return_data: false,
137			disable_syscall_details: false,
138			limit: None,
139			memory_word_limit: 16,
140		}
141	}
142}
143
144impl From<ExecutionTracerConfigV1> for ExecutionTracerConfig {
145	fn from(value: ExecutionTracerConfigV1) -> Self {
146		Self {
147			enable_memory: value.enable_memory,
148			disable_stack: value.disable_stack,
149			disable_storage: value.disable_storage,
150			enable_return_data: value.enable_return_data,
151			disable_syscall_details: value.disable_syscall_details,
152			limit: value.limit,
153			memory_word_limit: value.memory_word_limit,
154		}
155	}
156}
157
158/// The type of call that was executed.
159#[derive(Default, Eq, PartialEq, Clone, Debug)]
160pub enum CallType {
161	/// A regular call.
162	#[default]
163	Call,
164	/// A read-only call.
165	StaticCall,
166	/// A delegate call.
167	DelegateCall,
168	/// A create call.
169	Create,
170	/// A create2 call.
171	Create2,
172	/// A selfdestruct call.
173	Selfdestruct,
174}
175
176impl From<CallType> for CallTypeV1 {
177	fn from(value: CallType) -> Self {
178		match value {
179			CallType::Call => Self::Call,
180			CallType::StaticCall => Self::StaticCall,
181			CallType::DelegateCall => Self::DelegateCall,
182			CallType::Create => Self::Create,
183			CallType::Create2 => Self::Create2,
184			CallType::Selfdestruct => Self::Selfdestruct,
185		}
186	}
187}
188
189/// A Trace
190#[derive(From, Clone, Debug, Eq, PartialEq)]
191pub enum Trace {
192	/// A call trace.
193	Call(CallTrace),
194	/// A prestate trace.
195	Prestate(PrestateTrace),
196	/// An execution trace (opcodes and syscalls).
197	Execution(ExecutionTrace),
198}
199
200impl From<Trace> for TraceV1 {
201	fn from(value: Trace) -> Self {
202		match value {
203			Trace::Call(value) => Self::Call(value.into()),
204			Trace::Prestate(value) => Self::Prestate(value.into()),
205			Trace::Execution(value) => Self::Execution(value.into()),
206		}
207	}
208}
209
210impl From<Trace> for TraceV2 {
211	fn from(value: Trace) -> Self {
212		match value {
213			Trace::Call(value) => Self::Call(value.into()),
214			Trace::Prestate(value) => Self::Prestate(value.into()),
215			Trace::Execution(value) => Self::Execution(value.into()),
216		}
217	}
218}
219
220/// A single extrinsic's trace, or a signal that it could not be traced.
221pub enum TraceEntry {
222	/// The extrinsic's trace.
223	Traced(Trace),
224	/// The extrinsic could not be traced.
225	NotTraced,
226}
227
228impl TraceEntry {
229	/// The entry for an extrinsic that produced no trace: `NotTraced` if the replay dropped it,
230	/// `None` if there was nothing to trace. `ExhaustsResources` is the only spurious failure a
231	/// faithful replay introduces.
232	pub fn for_untraced(result: &ApplyExtrinsicResult) -> Option<Self> {
233		matches!(result, Err(err) if err.exhausted_resources()).then_some(Self::NotTraced)
234	}
235}
236
237impl From<TraceEntry> for TraceEntryV1 {
238	fn from(value: TraceEntry) -> Self {
239		match value {
240			TraceEntry::Traced(trace) => TraceEntryV1::Traced(trace.into()),
241			TraceEntry::NotTraced => TraceEntryV1::NotTraced,
242		}
243	}
244}
245
246/// A prestate Trace
247#[derive(Clone, Debug, Eq, PartialEq)]
248pub enum PrestateTrace {
249	/// The Prestate mode returns the accounts necessary to execute a given transaction
250	Prestate(BTreeMap<H160, PrestateTraceInfo>),
251
252	/// The diff mode returns the differences between the transaction's pre and post-state
253	/// The result only contains the accounts that were modified by the transaction
254	DiffMode {
255		/// The state before the call.
256		/// The accounts in the `pre` field will contain all of their basic fields, even if those
257		/// fields have not been modified. For `storage` however, only non-empty slots that have
258		/// been modified will be included
259		pre: BTreeMap<H160, PrestateTraceInfo>,
260		/// The state after the call.
261		/// It only contains the specific fields that were actually modified during the transaction
262		post: BTreeMap<H160, PrestateTraceInfo>,
263	},
264}
265
266impl PrestateTrace {
267	/// Returns the pre and post trace info.
268	pub fn state_mut(
269		&mut self,
270	) -> (&mut BTreeMap<H160, PrestateTraceInfo>, Option<&mut BTreeMap<H160, PrestateTraceInfo>>) {
271		match self {
272			PrestateTrace::Prestate(pre) => (pre, None),
273			PrestateTrace::DiffMode { pre, post } => (pre, Some(post)),
274		}
275	}
276}
277
278impl From<PrestateTrace> for PrestateTraceV1 {
279	fn from(value: PrestateTrace) -> Self {
280		let convert = |v: BTreeMap<H160, PrestateTraceInfo>| {
281			v.into_iter().map(|(k, v)| (k, v.into())).collect()
282		};
283
284		match value {
285			PrestateTrace::Prestate(accounts) => Self::Prestate(convert(accounts)),
286			PrestateTrace::DiffMode { pre, post } => {
287				Self::DiffMode { pre: convert(pre), post: convert(post) }
288			},
289		}
290	}
291}
292
293/// The info of a prestate trace.
294#[derive(Default, Clone, Debug, Eq, PartialEq)]
295pub struct PrestateTraceInfo {
296	/// The balance of the account.
297	pub balance: Option<U256>,
298	/// The nonce of the account.
299	pub nonce: Option<u32>,
300	/// The code of the contract account.
301	pub code: Option<Bytes>,
302	/// The storage of the contract account.
303	pub storage: BTreeMap<Bytes, Option<Bytes>>,
304}
305
306impl From<PrestateTraceInfo> for PrestateTraceInfoV1 {
307	fn from(value: PrestateTraceInfo) -> Self {
308		Self {
309			balance: value.balance,
310			nonce: value.nonce,
311			code: value.code,
312			storage: value.storage,
313		}
314	}
315}
316
317/// An execution trace containing the step-by-step execution of EVM opcodes and PVM syscalls.
318/// This matches Geth's structLogger output format.
319#[derive(Default, Clone, Debug, Eq, PartialEq)]
320pub struct ExecutionTrace {
321	/// Total gas used by the transaction.
322	pub gas: u64,
323	/// The weight consumed by the transaction meter.
324	pub weight_consumed: Weight,
325	/// The base call weight of the transaction.
326	pub base_call_weight: Weight,
327	/// Whether the transaction failed.
328	pub failed: bool,
329	/// The return value of the transaction.
330	pub return_value: Bytes,
331	/// The list of execution steps (structLogs in Geth).
332	pub struct_logs: Vec<ExecutionStep>,
333}
334
335impl From<ExecutionTrace> for ExecutionTraceV1 {
336	fn from(value: ExecutionTrace) -> Self {
337		Self {
338			gas: value.gas,
339			weight_consumed: value.weight_consumed,
340			base_call_weight: value.base_call_weight,
341			failed: value.failed,
342			return_value: value.return_value,
343			struct_logs: value.struct_logs.into_iter().map(Into::into).collect(),
344		}
345	}
346}
347
348/// An execution step which can be either an EVM opcode or a PVM syscall.
349#[derive(Clone, Debug, Eq, PartialEq, Default)]
350pub struct ExecutionStep {
351	/// Remaining gas before executing this step.
352	pub gas: u64,
353	/// Gas Cost of executing this step.
354	pub gas_cost: u64,
355	/// Weight cost of executing this step.
356	pub weight_cost: Weight,
357	/// Current call depth.
358	pub depth: u16,
359	/// Return data from last frame output.
360	pub return_data: Bytes,
361	/// Any error that occurred during execution.
362	pub error: Option<String>,
363	/// The kind of execution step (EVM opcode or PVM syscall).
364	pub kind: ExecutionStepKind,
365}
366
367impl From<ExecutionStep> for ExecutionStepV1 {
368	fn from(value: ExecutionStep) -> Self {
369		Self {
370			gas: value.gas,
371			gas_cost: value.gas_cost,
372			weight_cost: value.weight_cost,
373			depth: value.depth,
374			return_data: value.return_data,
375			error: value.error,
376			kind: value.kind.into(),
377		}
378	}
379}
380
381/// The kind of execution step.
382#[derive(Clone, Debug, Eq, PartialEq)]
383pub enum ExecutionStepKind {
384	/// An EVM opcode execution.
385	EVMOpcode {
386		/// The program counter.
387		pc: u32,
388		/// The opcode being executed.
389		op: u8,
390		/// EVM stack contents.
391		stack: Vec<Bytes>,
392		/// EVM memory contents.
393		memory: Vec<Bytes>,
394		/// Contract storage changes.
395		storage: Option<alloc::collections::BTreeMap<Bytes, Bytes>>,
396	},
397	/// A PVM syscall execution.
398	PVMSyscall {
399		/// The executed syscall.
400		op: u8,
401		/// The syscall arguments (register values a0-a5).
402		/// Omitted when `disable_syscall_details` is true in ExecutionTracerConfig.
403		args: Vec<u64>,
404		/// The syscall return value.
405		/// Omitted when `disable_syscall_details` is true in ExecutionTracerConfig.
406		returned: Option<u64>,
407	},
408}
409
410impl Default for ExecutionStepKind {
411	fn default() -> Self {
412		Self::EVMOpcode { pc: 0, op: 0, stack: Vec::new(), memory: Vec::new(), storage: None }
413	}
414}
415
416impl From<ExecutionStepKind> for ExecutionStepKindV1 {
417	fn from(value: ExecutionStepKind) -> Self {
418		match value {
419			ExecutionStepKind::EVMOpcode { pc, op, stack, memory, storage } => {
420				Self::EVMOpcode { pc, op: EvmOpcodeV1(op), stack, memory, storage }
421			},
422			ExecutionStepKind::PVMSyscall { op, args, returned } => Self::PVMSyscall {
423				op: op
424					.try_into()
425					.expect("all sys calls produced by revive are valid. Tested in env.rs; qed"),
426				args,
427				returned,
428			},
429		}
430	}
431}
432
433/// A smart contract execution call trace.
434#[derive(Default, Clone, Debug, Eq, PartialEq)]
435pub struct CallTrace {
436	/// Address of the sender.
437	pub from: H160,
438	/// Amount of gas provided for the call.
439	pub gas: u64,
440	/// Amount of gas used.
441	pub gas_used: u64,
442	/// Address of the receiver.
443	pub to: H160,
444	/// Call input data.
445	pub input: Bytes,
446	/// Return data.
447	pub output: Bytes,
448	/// The error message if the call failed.
449	pub error: Option<String>,
450	/// The revert reason, if the call reverted.
451	pub revert_reason: Option<String>,
452	/// List of sub-calls.
453	pub calls: Vec<CallTrace>,
454	/// List of logs emitted during the call.
455	pub logs: Vec<CallLog>,
456	/// Amount of value transferred.
457	pub value: Option<U256>,
458	/// Type of call.
459	pub call_type: CallType,
460	/// Number of child calls entered (for log position calculation)
461	pub child_call_count: u32,
462}
463
464impl From<CallTrace> for CallTraceV1 {
465	fn from(value: CallTrace) -> Self {
466		Self {
467			from: value.from,
468			gas: value.gas,
469			gas_used: value.gas_used,
470			to: value.to,
471			input: value.input,
472			output: value.output,
473			error: value.error,
474			revert_reason: value.revert_reason,
475			calls: value.calls.into_iter().map(Into::into).collect(),
476			logs: value.logs.into_iter().map(Into::into).collect(),
477			value: value.value,
478			call_type: value.call_type.into(),
479			child_call_count: value.child_call_count,
480		}
481	}
482}
483
484impl From<CallTrace> for CallTraceV2 {
485	fn from(value: CallTrace) -> Self {
486		Self {
487			from: value.from,
488			gas: value.gas,
489			gas_used: value.gas_used,
490			to: value.to,
491			input: value.input,
492			output: value.output,
493			error: value.error,
494			revert_reason: value.revert_reason,
495			calls: value.calls.into_iter().map(Into::into).collect(),
496			logs: value.logs.into_iter().map(Into::into).collect(),
497			value: value.value,
498			call_type: value.call_type.into(),
499		}
500	}
501}
502
503/// A log emitted during a call.
504#[derive(Debug, Default, Clone, Eq, PartialEq)]
505pub struct CallLog {
506	/// The address of the contract that emitted the log.
507	pub address: H160,
508	/// The topics used to index the log.
509	pub topics: Vec<H256>,
510	/// The log's data.
511	pub data: Bytes,
512	/// Position of the log relative to subcalls within the same trace
513	/// See <https://github.com/ethereum/go-ethereum/pull/28389> for details
514	pub position: u32,
515	/// The block-wide index of the log, matching the `logIndex` in receipts and Geth's call
516	/// tracer. Distinct from `position`, which tracks ordering relative to sub-calls within the
517	/// same trace frame.
518	pub index: u32,
519}
520
521impl From<CallLog> for CallLogV1 {
522	fn from(value: CallLog) -> Self {
523		Self {
524			address: value.address,
525			topics: value.topics,
526			data: value.data,
527			position: value.position,
528		}
529	}
530}
531
532impl From<CallLog> for CallLogV2 {
533	fn from(value: CallLog) -> Self {
534		Self {
535			address: value.address,
536			topics: value.topics,
537			data: value.data,
538			position: value.position,
539			index: value.index,
540		}
541	}
542}