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