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::evm::Bytes;
19use alloc::{collections::BTreeMap, string::String, vec::Vec};
20use codec::{Decode, Encode};
21use derive_more::From;
22use scale_info::TypeInfo;
23use serde::{
24	ser::{SerializeMap, Serializer},
25	Deserialize, Serialize,
26};
27use sp_core::{H160, H256, U256};
28
29/// The type of tracer to use.
30/// Only "callTracer" is supported for now.
31#[derive(TypeInfo, Debug, Clone, Encode, Decode, Serialize, Deserialize, PartialEq)]
32#[serde(tag = "tracer", content = "tracerConfig", rename_all = "camelCase")]
33pub enum TracerType {
34	/// A tracer that traces calls.
35	CallTracer(Option<CallTracerConfig>),
36
37	/// A tracer that traces the prestate.
38	PrestateTracer(Option<PrestateTracerConfig>),
39}
40
41impl From<CallTracerConfig> for TracerType {
42	fn from(config: CallTracerConfig) -> Self {
43		TracerType::CallTracer(Some(config))
44	}
45}
46
47impl Default for TracerType {
48	fn default() -> Self {
49		TracerType::CallTracer(Some(CallTracerConfig::default()))
50	}
51}
52
53/// Tracer configuration used to trace calls.
54#[derive(TypeInfo, Debug, Clone, Default, PartialEq)]
55#[cfg_attr(feature = "std", derive(Deserialize, Serialize), serde(rename_all = "camelCase"))]
56pub struct TracerConfig {
57	/// The tracer type.
58	#[cfg_attr(feature = "std", serde(flatten, default))]
59	pub config: TracerType,
60
61	/// Timeout for the tracer.
62	#[cfg_attr(feature = "std", serde(with = "humantime_serde", default))]
63	pub timeout: Option<core::time::Duration>,
64}
65
66/// The configuration for the call tracer.
67#[derive(Clone, Debug, Decode, Serialize, Deserialize, Encode, PartialEq, TypeInfo)]
68#[serde(default, rename_all = "camelCase")]
69pub struct CallTracerConfig {
70	/// Whether to include logs in the trace.
71	pub with_logs: bool,
72
73	/// Whether to only include the top-level calls in the trace.
74	pub only_top_call: bool,
75}
76
77impl Default for CallTracerConfig {
78	fn default() -> Self {
79		Self { with_logs: true, only_top_call: false }
80	}
81}
82
83/// The configuration for the prestate tracer.
84#[derive(Clone, Debug, Decode, Serialize, Deserialize, Encode, PartialEq, TypeInfo)]
85#[serde(default, rename_all = "camelCase")]
86pub struct PrestateTracerConfig {
87	/// Whether to include the diff mode in the trace.
88	pub diff_mode: bool,
89
90	/// Whether to include storage in the trace.
91	pub disable_storage: bool,
92
93	/// Whether to include code in the trace.
94	pub disable_code: bool,
95}
96
97impl Default for PrestateTracerConfig {
98	fn default() -> Self {
99		Self { diff_mode: false, disable_storage: false, disable_code: false }
100	}
101}
102
103/// Serialization should support the following JSON format:
104///
105/// ```json
106/// { "tracer": "callTracer", "tracerConfig": { "withLogs": false } }
107/// ```
108///
109/// ```json
110/// { "tracer": "callTracer" }
111/// ```
112#[test]
113fn test_tracer_config_serialization() {
114	let tracers = vec![
115		(
116			r#"{"tracer": "callTracer"}"#,
117			TracerConfig { config: TracerType::CallTracer(None), timeout: None },
118		),
119		(
120			r#"{"tracer": "callTracer", "tracerConfig": { "withLogs": false }}"#,
121			TracerConfig {
122				config: CallTracerConfig { with_logs: false, only_top_call: false }.into(),
123				timeout: None,
124			},
125		),
126		(
127			r#"{"tracer": "callTracer", "tracerConfig": { "onlyTopCall": true }}"#,
128			TracerConfig {
129				config: CallTracerConfig { with_logs: true, only_top_call: true }.into(),
130				timeout: None,
131			},
132		),
133		(
134			r#"{"tracer": "callTracer", "tracerConfig": { "onlyTopCall": true }, "timeout": "10ms"}"#,
135			TracerConfig {
136				config: CallTracerConfig { with_logs: true, only_top_call: true }.into(),
137				timeout: Some(core::time::Duration::from_millis(10)),
138			},
139		),
140	];
141
142	for (json_data, expected) in tracers {
143		let result: TracerConfig =
144			serde_json::from_str(json_data).expect("Deserialization should succeed");
145		assert_eq!(result, expected);
146	}
147}
148
149/// The type of call that was executed.
150#[derive(
151	Default, TypeInfo, Encode, Decode, Serialize, Deserialize, Eq, PartialEq, Clone, Debug,
152)]
153#[serde(rename_all = "UPPERCASE")]
154pub enum CallType {
155	/// A regular call.
156	#[default]
157	Call,
158	/// A read-only call.
159	StaticCall,
160	/// A delegate call.
161	DelegateCall,
162	/// A create call.
163	Create,
164	/// A create2 call.
165	Create2,
166}
167
168/// A Trace
169#[derive(TypeInfo, From, Encode, Decode, Serialize, Deserialize, Clone, Debug, Eq, PartialEq)]
170#[serde(untagged)]
171pub enum Trace {
172	/// A call trace.
173	Call(CallTrace),
174	/// A prestate trace.
175	Prestate(PrestateTrace),
176}
177
178/// A prestate Trace
179#[derive(TypeInfo, Encode, Decode, Serialize, Deserialize, Clone, Debug, Eq, PartialEq)]
180#[serde(untagged)]
181pub enum PrestateTrace {
182	/// The Prestate mode returns the accounts necessary to execute a given transaction
183	Prestate(BTreeMap<H160, PrestateTraceInfo>),
184
185	/// The diff mode returns the differences between the transaction's pre and post-state
186	/// The result only contains the accounts that were modified by the transaction
187	DiffMode {
188		/// The state before the call.
189		///  The accounts in the `pre` field will contain all of their basic fields, even if those
190		/// fields have not been modified. For `storage` however, only non-empty slots that have
191		/// been modified will be included
192		pre: BTreeMap<H160, PrestateTraceInfo>,
193		/// The state after the call.
194		/// It only contains the specific fields that were actually modified during the transaction
195		post: BTreeMap<H160, PrestateTraceInfo>,
196	},
197}
198
199impl PrestateTrace {
200	/// Returns the pre and post trace info.
201	pub fn state_mut(
202		&mut self,
203	) -> (&mut BTreeMap<H160, PrestateTraceInfo>, Option<&mut BTreeMap<H160, PrestateTraceInfo>>) {
204		match self {
205			PrestateTrace::Prestate(pre) => (pre, None),
206			PrestateTrace::DiffMode { pre, post } => (pre, Some(post)),
207		}
208	}
209}
210
211/// The info of a prestate trace.
212#[derive(
213	TypeInfo, Default, Encode, Decode, Serialize, Deserialize, Clone, Debug, Eq, PartialEq,
214)]
215pub struct PrestateTraceInfo {
216	/// The balance of the account.
217	#[serde(skip_serializing_if = "Option::is_none")]
218	pub balance: Option<U256>,
219	/// The nonce of the account.
220	#[serde(skip_serializing_if = "Option::is_none")]
221	pub nonce: Option<u32>,
222	/// The code of the contract account.
223	#[serde(skip_serializing_if = "Option::is_none")]
224	pub code: Option<Bytes>,
225	/// The storage of the contract account.
226	#[serde(skip_serializing_if = "is_empty", serialize_with = "serialize_map_skip_none")]
227	pub storage: BTreeMap<Bytes, Option<Bytes>>,
228}
229
230/// Returns true if the map has no `Some` element
231pub fn is_empty<K, V>(map: &BTreeMap<K, Option<V>>) -> bool {
232	!map.values().any(|v| v.is_some())
233}
234
235/// Serializes a map, skipping `None` values.
236pub fn serialize_map_skip_none<S, K, V>(
237	map: &BTreeMap<K, Option<V>>,
238	serializer: S,
239) -> Result<S::Ok, S::Error>
240where
241	S: Serializer,
242	K: serde::Serialize,
243	V: serde::Serialize,
244{
245	let len = map.values().filter(|v| v.is_some()).count();
246	let mut ser_map = serializer.serialize_map(Some(len))?;
247
248	for (key, opt_val) in map {
249		if let Some(val) = opt_val {
250			ser_map.serialize_entry(key, val)?;
251		}
252	}
253
254	ser_map.end()
255}
256
257/// A smart contract execution call trace.
258#[derive(
259	TypeInfo, Default, Encode, Decode, Serialize, Deserialize, Clone, Debug, Eq, PartialEq,
260)]
261#[serde(rename_all = "camelCase")]
262pub struct CallTrace<Gas = U256> {
263	/// Address of the sender.
264	pub from: H160,
265	/// Amount of gas provided for the call.
266	pub gas: Gas,
267	/// Amount of gas used.
268	pub gas_used: Gas,
269	/// Address of the receiver.
270	pub to: H160,
271	/// Call input data.
272	pub input: Bytes,
273	/// Return data.
274	#[serde(skip_serializing_if = "Bytes::is_empty")]
275	pub output: Bytes,
276	/// The error message if the call failed.
277	#[serde(skip_serializing_if = "Option::is_none")]
278	pub error: Option<String>,
279	/// The revert reason, if the call reverted.
280	#[serde(skip_serializing_if = "Option::is_none")]
281	pub revert_reason: Option<String>,
282	/// List of sub-calls.
283	#[serde(skip_serializing_if = "Vec::is_empty")]
284	pub calls: Vec<CallTrace<Gas>>,
285	/// List of logs emitted during the call.
286	#[serde(skip_serializing_if = "Vec::is_empty")]
287	pub logs: Vec<CallLog>,
288	/// Amount of value transferred.
289	#[serde(skip_serializing_if = "Option::is_none")]
290	pub value: Option<U256>,
291	/// Type of call.
292	#[serde(rename = "type")]
293	pub call_type: CallType,
294	/// Number of child calls entered (for log position calculation)
295	#[serde(skip)]
296	pub child_call_count: u32,
297}
298
299/// A log emitted during a call.
300#[derive(
301	Debug, Default, Clone, Encode, Decode, TypeInfo, Serialize, Deserialize, Eq, PartialEq,
302)]
303pub struct CallLog {
304	/// The address of the contract that emitted the log.
305	pub address: H160,
306	/// The topics used to index the log.
307	#[serde(default, skip_serializing_if = "Vec::is_empty")]
308	pub topics: Vec<H256>,
309	/// The log's data.
310	pub data: Bytes,
311	/// Position of the log relative to subcalls within the same trace
312	/// See <https://github.com/ethereum/go-ethereum/pull/28389> for details
313	#[serde(with = "super::hex_serde")]
314	pub position: u32,
315}
316
317/// A transaction trace
318#[derive(Serialize, Deserialize, Clone, Debug)]
319#[serde(rename_all = "camelCase")]
320pub struct TransactionTrace {
321	/// The transaction hash.
322	pub tx_hash: H256,
323	/// The trace of the transaction.
324	#[serde(rename = "result")]
325	pub trace: Trace,
326}