pallet_revive/evm/tracing/
prestate_tracing.rs1use crate::{
18 AccountInfo, Code, Config, ExecReturnValue, Key, Pallet, PristineCode, Weight,
19 evm::{Bytes, PrestateTrace, PrestateTraceInfo, PrestateTracerConfig},
20 tracing::Tracing,
21};
22use alloc::{
23 collections::{BTreeMap, BTreeSet},
24 vec::Vec,
25};
26use sp_core::{H160, U256};
27
28#[derive(frame_support::DefaultNoBound, Debug, Clone, PartialEq)]
30pub struct PrestateTracer<T> {
31 config: PrestateTracerConfig,
33
34 calls: Vec<H160>,
36
37 create_code: Option<Code>,
39
40 created_addrs: BTreeSet<H160>,
42
43 destructed_addrs: BTreeSet<H160>,
45
46 trace: (BTreeMap<H160, PrestateTraceInfo>, BTreeMap<H160, PrestateTraceInfo>),
48
49 _phantom: core::marker::PhantomData<T>,
50}
51
52impl<T: Config> PrestateTracer<T>
53where
54 T::Nonce: Into<u32>,
55{
56 pub fn new(config: PrestateTracerConfig) -> Self {
58 Self { config, ..Default::default() }
59 }
60
61 fn current_addr(&self) -> H160 {
62 self.calls.last().copied().unwrap_or_default()
63 }
64
65 pub fn empty_trace(&self) -> PrestateTrace {
67 if self.config.diff_mode {
68 PrestateTrace::DiffMode { pre: Default::default(), post: Default::default() }
69 } else {
70 PrestateTrace::Prestate(Default::default())
71 }
72 }
73
74 pub fn collect_trace(self) -> PrestateTrace {
76 let (mut pre, mut post) = self.trace;
77 let include_code = !self.config.disable_code;
78
79 let is_empty = |info: &PrestateTraceInfo| {
80 !info.storage.values().any(|v| v.is_some()) &&
81 info.balance.is_none() &&
82 info.nonce.is_none() &&
83 info.code.is_none()
84 };
85
86 if self.config.diff_mode {
87 if include_code {
88 for addr in &self.created_addrs {
89 if let Some(info) = post.get_mut(addr) {
90 info.code = Self::bytecode(addr);
91 }
92 }
93 }
94
95 for addr in &self.destructed_addrs {
97 Self::update_prestate_info(post.entry(*addr).or_default(), addr, None);
98 }
99
100 pre.iter_mut().for_each(|(addr, info)| {
102 if let Some(post_info) = post.get(addr) {
103 info.storage.retain(|k, _| post_info.storage.contains_key(k));
104 } else {
105 info.storage.clear();
106 }
107 });
108
109 post.retain(|addr, _| {
111 if self.created_addrs.contains(addr) && self.destructed_addrs.contains(addr) {
112 return false;
113 }
114 true
115 });
116
117 pre.retain(|addr, pre_info| {
118 if is_empty(&pre_info) {
119 return false;
120 }
121
122 let post_info = post.entry(*addr).or_insert_with_key(|addr| {
123 Self::prestate_info(
124 addr,
125 Pallet::<T>::evm_balance(addr),
126 include_code.then(|| Self::bytecode(addr)).flatten(),
127 )
128 });
129
130 if post_info == pre_info {
131 post.remove(addr);
132 return false;
133 }
134
135 if post_info.code == pre_info.code {
136 post_info.code = None;
137 }
138
139 if post_info.balance == pre_info.balance {
140 post_info.balance = None;
141 }
142
143 if post_info.nonce == pre_info.nonce {
144 post_info.nonce = None;
145 }
146
147 if post_info == &Default::default() {
148 post.remove(addr);
149 }
150
151 true
152 });
153
154 post.retain(|_, info| !is_empty(&info));
155 PrestateTrace::DiffMode { pre, post }
156 } else {
157 pre.retain(|_, info| !is_empty(&info));
158 PrestateTrace::Prestate(pre)
159 }
160 }
161}
162
163macro_rules! get_entry {
167 ($self:expr, $addr:expr) => {
168 if $self.created_addrs.contains(&$addr) {
169 if !$self.config.diff_mode {
170 return;
171 }
172 $self.trace.1.entry($addr)
173 } else {
174 $self.trace.0.entry($addr)
175 }
176 };
177}
178
179impl<T: Config> PrestateTracer<T>
180where
181 T::Nonce: Into<u32>,
182{
183 fn bytecode(address: &H160) -> Option<Bytes> {
185 if let Some(target) = AccountInfo::<T>::get_delegation_target(address) {
187 return Some(AccountInfo::<T>::delegation_indicator(&target).to_vec().into());
188 }
189 let code_hash = AccountInfo::<T>::load_contract(address)?.code_hash;
190 let code: Vec<u8> = PristineCode::<T>::get(&code_hash)?.into();
191 return Some(code.into());
192 }
193
194 fn update_prestate_info(entry: &mut PrestateTraceInfo, addr: &H160, code: Option<Bytes>) {
196 let info = Self::prestate_info(addr, Pallet::<T>::evm_balance(addr), code);
197 entry.balance = info.balance;
198 entry.nonce = info.nonce;
199 entry.code = info.code;
200 }
201
202 fn prestate_info(addr: &H160, balance: U256, code: Option<Bytes>) -> PrestateTraceInfo {
204 let mut info = PrestateTraceInfo::default();
205 info.balance = Some(balance);
206 info.code = code;
207 let nonce = Pallet::<T>::evm_nonce(addr);
208 info.nonce = if nonce > 0 { Some(nonce) } else { None };
209 info
210 }
211
212 fn read_account(&mut self, addr: H160) {
214 let include_code = !self.config.disable_code;
215 get_entry!(self, addr).or_insert_with_key(|addr| {
216 Self::prestate_info(
217 addr,
218 Pallet::<T>::evm_balance(addr),
219 include_code.then(|| Self::bytecode(addr)).flatten(),
220 )
221 });
222 }
223}
224
225impl<T: Config> Tracing for PrestateTracer<T>
226where
227 T::Nonce: Into<u32>,
228{
229 fn watch_address(&mut self, addr: &H160) {
230 let include_code = !self.config.disable_code;
231 self.trace.0.entry(*addr).or_insert_with_key(|addr| {
232 Self::prestate_info(
233 addr,
234 Pallet::<T>::evm_balance(addr),
235 include_code.then(|| Self::bytecode(addr)).flatten(),
236 )
237 });
238 }
239
240 fn instantiate_code(&mut self, code: &crate::Code, _salt: Option<&[u8; 32]>) {
241 self.create_code = Some(code.clone());
242 }
243
244 fn terminate(
245 &mut self,
246 contract_address: H160,
247 beneficiary_address: H160,
248 _gas_left: u64,
249 _value: U256,
250 ) {
251 self.destructed_addrs.insert(contract_address);
252 self.trace.0.entry(beneficiary_address).or_insert_with_key(|addr| {
253 Self::prestate_info(addr, Pallet::<T>::evm_balance(addr), None)
254 });
255 }
256
257 fn enter_child_span(
258 &mut self,
259 from: H160,
260 to: H160,
261 code_address: Option<H160>,
262 is_delegate_call: bool,
263 _is_read_only: bool,
264 _value: U256,
265 _input: &[u8],
266 _gas_limit: u64,
267 ) {
268 if is_delegate_call {
269 self.calls.push(self.current_addr());
270 } else {
271 self.calls.push(to);
272 }
273
274 if let Some(code_address) = code_address {
275 self.read_account(code_address);
276 }
277 self.read_account(from);
278
279 if self.create_code.take().is_some() {
280 self.created_addrs.insert(to);
281 } else {
282 self.read_account(to);
283 }
284 }
285
286 fn exit_child_span_with_error(
287 &mut self,
288 _error: crate::DispatchError,
289 _gas_used: u64,
290 _weight_consumed: Weight,
291 ) {
292 self.calls.pop();
293 }
294
295 fn exit_child_span(
296 &mut self,
297 output: &ExecReturnValue,
298 _gas_used: u64,
299 _weight_consumed: Weight,
300 ) {
301 let current_addr = self.calls.pop().unwrap_or_default();
302 if output.did_revert() {
303 return;
304 }
305
306 let code = if self.config.disable_code { None } else { Self::bytecode(¤t_addr) };
307
308 Self::update_prestate_info(
309 self.trace.1.entry(current_addr).or_default(),
310 ¤t_addr,
311 code,
312 );
313 }
314
315 fn storage_write(&mut self, key: &Key, old_value: Option<Vec<u8>>, new_value: Option<&[u8]>) {
316 let current_addr = self.current_addr();
317 let key = Bytes::from(key.unhashed().to_vec());
318
319 let old_value = get_entry!(self, current_addr)
320 .or_default()
321 .storage
322 .entry(key.clone())
323 .or_insert_with(|| old_value.map(Into::into));
324
325 if !self.config.diff_mode {
326 return;
327 }
328
329 if old_value.as_ref().map(|v| v.0.as_ref()) != new_value {
330 self.trace
331 .1
332 .entry(current_addr)
333 .or_default()
334 .storage
335 .insert(key, new_value.map(|v| v.to_vec().into()));
336 } else {
337 self.trace.1.entry(self.current_addr()).or_default().storage.remove(&key);
338 }
339 }
340
341 fn storage_read(&mut self, key: &Key, value: Option<&[u8]>) {
342 let current_addr = self.current_addr();
343
344 get_entry!(self, current_addr)
345 .or_default()
346 .storage
347 .entry(key.unhashed().to_vec().into())
348 .or_insert_with(|| value.map(|v| v.to_vec().into()));
349 }
350
351 fn balance_read(&mut self, addr: &H160, value: U256) {
352 let include_code = !self.config.disable_code;
353 get_entry!(self, *addr).or_insert_with_key(|addr| {
354 Self::prestate_info(addr, value, include_code.then(|| Self::bytecode(addr)).flatten())
355 });
356 }
357}