1use crate::inspector::Inspector;
3use interpreter::{interpreter_types::Jumps, InterpreterTypes};
4use primitives::Log;
5
6#[derive(Clone, Debug)]
8pub struct CountInspector {
9 opcode_counts: [u64; 256],
11 initialize_interp_count: u64,
13 step_count: u64,
15 step_end_count: u64,
17 log_count: u64,
19 call_count: u64,
21 call_end_count: u64,
23 create_count: u64,
25 create_end_count: u64,
27 selfdestruct_count: u64,
29}
30
31impl Default for CountInspector {
32 fn default() -> Self {
33 Self {
34 opcode_counts: [0; 256],
35 initialize_interp_count: 0,
36 step_count: 0,
37 step_end_count: 0,
38 log_count: 0,
39 call_count: 0,
40 call_end_count: 0,
41 create_count: 0,
42 create_end_count: 0,
43 selfdestruct_count: 0,
44 }
45 }
46}
47
48impl CountInspector {
49 pub fn new() -> Self {
51 Self::default()
52 }
53
54 pub fn get_count(&self, opcode: u8) -> u64 {
56 self.opcode_counts[opcode as usize]
57 }
58
59 pub fn opcode_counts(&self) -> &[u64; 256] {
61 &self.opcode_counts
62 }
63
64 pub fn total_opcodes(&self) -> u64 {
66 self.opcode_counts.iter().copied().sum()
67 }
68
69 pub fn unique_opcodes(&self) -> usize {
71 self.opcode_counts
72 .iter()
73 .filter(|&&count| count > 0)
74 .count()
75 }
76
77 pub fn clear(&mut self) {
79 self.opcode_counts = [0; 256];
80 self.initialize_interp_count = 0;
81 self.step_count = 0;
82 self.step_end_count = 0;
83 self.log_count = 0;
84 self.call_count = 0;
85 self.call_end_count = 0;
86 self.create_count = 0;
87 self.create_end_count = 0;
88 self.selfdestruct_count = 0;
89 }
90
91 pub fn initialize_interp_count(&self) -> u64 {
93 self.initialize_interp_count
94 }
95
96 pub fn step_count(&self) -> u64 {
98 self.step_count
99 }
100
101 pub fn step_end_count(&self) -> u64 {
103 self.step_end_count
104 }
105
106 pub fn log_count(&self) -> u64 {
108 self.log_count
109 }
110
111 pub fn call_count(&self) -> u64 {
113 self.call_count
114 }
115
116 pub fn call_end_count(&self) -> u64 {
118 self.call_end_count
119 }
120
121 pub fn create_count(&self) -> u64 {
123 self.create_count
124 }
125
126 pub fn create_end_count(&self) -> u64 {
128 self.create_end_count
129 }
130
131 pub fn selfdestruct_count(&self) -> u64 {
133 self.selfdestruct_count
134 }
135}
136
137impl<CTX, INTR: InterpreterTypes> Inspector<CTX, INTR> for CountInspector {
138 fn initialize_interp(
139 &mut self,
140 _interp: &mut interpreter::Interpreter<INTR>,
141 _context: &mut CTX,
142 ) {
143 self.initialize_interp_count += 1;
144 }
145
146 fn step(&mut self, interp: &mut interpreter::Interpreter<INTR>, _context: &mut CTX) {
147 self.step_count += 1;
148 let opcode = interp.bytecode.opcode();
149 self.opcode_counts[opcode as usize] += 1;
150 }
151
152 fn step_end(&mut self, _interp: &mut interpreter::Interpreter<INTR>, _context: &mut CTX) {
153 self.step_end_count += 1;
154 }
155
156 fn log(&mut self, _context: &mut CTX, _log: Log) {
157 self.log_count += 1;
158 }
159
160 fn call(
161 &mut self,
162 _context: &mut CTX,
163 _inputs: &mut interpreter::CallInputs,
164 ) -> Option<interpreter::CallOutcome> {
165 self.call_count += 1;
166 None
167 }
168
169 fn call_end(
170 &mut self,
171 _context: &mut CTX,
172 _inputs: &interpreter::CallInputs,
173 _outcome: &mut interpreter::CallOutcome,
174 ) {
175 self.call_end_count += 1;
176 }
177
178 fn create(
179 &mut self,
180 _context: &mut CTX,
181 _inputs: &mut interpreter::CreateInputs,
182 ) -> Option<interpreter::CreateOutcome> {
183 self.create_count += 1;
184 None
185 }
186
187 fn create_end(
188 &mut self,
189 _context: &mut CTX,
190 _inputs: &interpreter::CreateInputs,
191 _outcome: &mut interpreter::CreateOutcome,
192 ) {
193 self.create_end_count += 1;
194 }
195
196 fn selfdestruct(
197 &mut self,
198 _contract: primitives::Address,
199 _target: primitives::Address,
200 _value: primitives::U256,
201 ) {
202 self.selfdestruct_count += 1;
203 }
204}
205
206#[cfg(test)]
207mod tests {
208 use super::*;
209 use crate::InspectEvm;
210 use context::Context;
211 use database::BenchmarkDB;
212 use handler::{MainBuilder, MainContext};
213 use primitives::{Bytes, TxKind};
214 use state::bytecode::{opcode, Bytecode};
215
216 #[test]
217 fn test_count_inspector() {
218 let contract_data: Bytes = Bytes::from(vec![
220 opcode::PUSH1,
221 0x10, opcode::PUSH1,
223 0x20, opcode::ADD, opcode::DUP1, opcode::PUSH1,
227 0x00, opcode::MSTORE, opcode::STOP, ]);
231 let bytecode = Bytecode::new_raw(contract_data);
232
233 let ctx = Context::mainnet().with_db(BenchmarkDB::new_bytecode(bytecode.clone()));
234 let mut count_inspector = CountInspector::new();
235
236 let mut evm = ctx.build_mainnet_with_inspector(&mut count_inspector);
237
238 evm.inspect_one_tx(
240 context::TxEnv::builder()
241 .kind(TxKind::Call(database::BENCH_TARGET))
242 .gas_limit(30000)
243 .build()
244 .unwrap(),
245 )
246 .unwrap();
247
248 assert_eq!(count_inspector.get_count(opcode::PUSH1), 3);
250 assert_eq!(count_inspector.get_count(opcode::ADD), 1);
251 assert_eq!(count_inspector.get_count(opcode::DUP1), 1);
252 assert_eq!(count_inspector.get_count(opcode::MSTORE), 1);
253 assert_eq!(count_inspector.get_count(opcode::STOP), 1);
254
255 assert_eq!(count_inspector.total_opcodes(), 7);
257 assert_eq!(count_inspector.unique_opcodes(), 5);
258
259 assert_eq!(count_inspector.initialize_interp_count(), 1);
261 assert_eq!(count_inspector.step_count(), 7); assert_eq!(count_inspector.step_end_count(), 7); assert_eq!(count_inspector.log_count(), 0); assert_eq!(count_inspector.call_count(), 1); assert_eq!(count_inspector.call_end_count(), 1);
266 assert_eq!(count_inspector.create_count(), 0); assert_eq!(count_inspector.create_end_count(), 0);
268 assert_eq!(count_inspector.selfdestruct_count(), 0); }
270
271 #[test]
272 fn test_count_inspector_clear() {
273 let mut inspector = CountInspector::new();
274
275 inspector.opcode_counts[opcode::PUSH1 as usize] += 5;
277 inspector.opcode_counts[opcode::ADD as usize] += 3;
278 inspector.initialize_interp_count = 2;
279 inspector.step_count = 10;
280 inspector.step_end_count = 10;
281 inspector.log_count = 1;
282 inspector.call_count = 3;
283 inspector.call_end_count = 3;
284 inspector.create_count = 1;
285 inspector.create_end_count = 1;
286 inspector.selfdestruct_count = 1;
287
288 assert_eq!(inspector.total_opcodes(), 8);
289 assert_eq!(inspector.unique_opcodes(), 2);
290 assert_eq!(inspector.initialize_interp_count(), 2);
291 assert_eq!(inspector.step_count(), 10);
292
293 inspector.clear();
295 assert_eq!(inspector.total_opcodes(), 0);
296 assert_eq!(inspector.unique_opcodes(), 0);
297 assert_eq!(inspector.initialize_interp_count(), 0);
298 assert_eq!(inspector.step_count(), 0);
299 assert_eq!(inspector.step_end_count(), 0);
300 assert_eq!(inspector.log_count(), 0);
301 assert_eq!(inspector.call_count(), 0);
302 assert_eq!(inspector.call_end_count(), 0);
303 assert_eq!(inspector.create_count(), 0);
304 assert_eq!(inspector.create_end_count(), 0);
305 assert_eq!(inspector.selfdestruct_count(), 0);
306 assert!(inspector.opcode_counts().iter().all(|&count| count == 0));
307 }
308
309 #[test]
310 fn test_count_inspector_with_logs() {
311 let contract_data: Bytes = Bytes::from(vec![
313 opcode::PUSH1,
314 0x20, opcode::PUSH1,
316 0x00, opcode::LOG0, opcode::STOP, ]);
320 let bytecode = Bytecode::new_raw(contract_data);
321
322 let ctx = Context::mainnet().with_db(BenchmarkDB::new_bytecode(bytecode.clone()));
323 let mut count_inspector = CountInspector::new();
324
325 let mut evm = ctx.build_mainnet_with_inspector(&mut count_inspector);
326
327 evm.inspect_one_tx(
329 context::TxEnv::builder()
330 .kind(TxKind::Call(database::BENCH_TARGET))
331 .gas_limit(30000)
332 .build()
333 .unwrap(),
334 )
335 .unwrap();
336
337 assert_eq!(count_inspector.log_count(), 1);
339 assert_eq!(count_inspector.step_count(), 4); }
341}