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