1616// limitations under the License.
1717
1818use crate :: evm:: Bytes ;
19- use alloc:: { string:: String , vec:: Vec } ;
19+ use alloc:: { collections :: BTreeMap , string:: String , vec:: Vec } ;
2020use codec:: { Decode , Encode } ;
2121use derive_more:: From ;
2222use scale_info:: TypeInfo ;
23- use serde:: { Deserialize , Serialize } ;
23+ use serde:: {
24+ ser:: { SerializeMap , Serializer } ,
25+ Deserialize , Serialize ,
26+ } ;
2427use sp_core:: { H160 , H256 , U256 } ;
2528
2629/// The type of tracer to use.
@@ -30,6 +33,9 @@ use sp_core::{H160, H256, U256};
3033pub enum TracerType {
3134 /// A tracer that traces calls.
3235 CallTracer ( Option < CallTracerConfig > ) ,
36+
37+ /// A tracer that traces the prestate.
38+ PrestateTracer ( Option < PrestateTracerConfig > ) ,
3339}
3440
3541impl From < CallTracerConfig > for TracerType {
@@ -74,6 +80,26 @@ impl Default for CallTracerConfig {
7480 }
7581}
7682
83+ /// The configuration for the prestate tracer.
84+ #[ derive( Clone , Debug , Decode , Serialize , Deserialize , Encode , PartialEq , TypeInfo ) ]
85+ #[ serde( default , rename_all = "camelCase" ) ]
86+ pub 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+
97+ impl Default for PrestateTracerConfig {
98+ fn default ( ) -> Self {
99+ Self { diff_mode : false , disable_storage : false , disable_code : false }
100+ }
101+ }
102+
77103/// Serialization should support the following JSON format:
78104///
79105/// ```json
@@ -141,6 +167,85 @@ pub enum CallType {
141167pub enum Trace {
142168 /// A call trace.
143169 Call ( CallTrace ) ,
170+ /// A prestate trace.
171+ Prestate ( PrestateTrace ) ,
172+ }
173+
174+ /// A prestate Trace
175+ #[ derive( TypeInfo , Encode , Decode , Serialize , Deserialize , Clone , Debug , Eq , PartialEq ) ]
176+ #[ serde( untagged) ]
177+ pub enum PrestateTrace {
178+ /// The Prestate mode returns the accounts necessary to execute a given transaction
179+ Prestate ( BTreeMap < H160 , PrestateTraceInfo > ) ,
180+
181+ /// The diff mode returns the differences between the transaction's pre and post-state
182+ /// The result only contains the accounts that were modified by the transaction
183+ DiffMode {
184+ /// The state before the call.
185+ /// The accounts in the `pre` field will contain all of their basic fields, even if those
186+ /// fields have not been modified. For `storage` however, only non-empty slots that have
187+ /// been modified will be included
188+ pre : BTreeMap < H160 , PrestateTraceInfo > ,
189+ /// The state after the call.
190+ /// It only contains the specific fields that were actually modified during the transaction
191+ post : BTreeMap < H160 , PrestateTraceInfo > ,
192+ } ,
193+ }
194+
195+ impl PrestateTrace {
196+ /// Returns the pre and post trace info.
197+ pub fn state_mut (
198+ & mut self ,
199+ ) -> ( & mut BTreeMap < H160 , PrestateTraceInfo > , Option < & mut BTreeMap < H160 , PrestateTraceInfo > > ) {
200+ match self {
201+ PrestateTrace :: Prestate ( pre) => ( pre, None ) ,
202+ PrestateTrace :: DiffMode { pre, post } => ( pre, Some ( post) ) ,
203+ }
204+ }
205+ }
206+
207+ /// The info of a prestate trace.
208+ #[ derive(
209+ TypeInfo , Default , Encode , Decode , Serialize , Deserialize , Clone , Debug , Eq , PartialEq ,
210+ ) ]
211+ pub struct PrestateTraceInfo {
212+ /// The balance of the account.
213+ #[ serde( skip_serializing_if = "Option::is_none" ) ]
214+ pub balance : Option < U256 > ,
215+ /// The nonce of the account.
216+ #[ serde( skip_serializing_if = "Option::is_none" ) ]
217+ pub nonce : Option < u32 > ,
218+ /// The code of the contract account.
219+ #[ serde( skip_serializing_if = "Option::is_none" ) ]
220+ pub code : Option < Bytes > ,
221+ /// The storage of the contract account.
222+ #[ serde(
223+ skip_serializing_if = "BTreeMap::is_empty" ,
224+ serialize_with = "serialize_map_skip_none"
225+ ) ]
226+ pub storage : BTreeMap < Bytes , Option < Bytes > > ,
227+ }
228+
229+ /// Serializes a map of `K -> Option<V>`, omitting any entries whose value is `None`.
230+ pub fn serialize_map_skip_none < S , K , V > (
231+ map : & BTreeMap < K , Option < V > > ,
232+ serializer : S ,
233+ ) -> Result < S :: Ok , S :: Error >
234+ where
235+ S : Serializer ,
236+ K : serde:: Serialize ,
237+ V : serde:: Serialize ,
238+ {
239+ let len = map. values ( ) . filter ( |v| v. is_some ( ) ) . count ( ) ;
240+ let mut ser_map = serializer. serialize_map ( Some ( len) ) ?;
241+
242+ for ( key, opt_val) in map {
243+ if let Some ( val) = opt_val {
244+ ser_map. serialize_entry ( key, val) ?;
245+ }
246+ }
247+
248+ ser_map. end ( )
144249}
145250
146251/// A smart contract execution call trace.
0 commit comments