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