1use crate::inspector::Inspector;
3use interpreter::{interpreter_types::Jumps, InterpreterTypes};
4use primitives::{HashMap, Log};
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(&mut self, _context: &mut CTX, _log: Log) {
137 self.log_count += 1;
138 }
139
140 fn call(
141 &mut self,
142 _context: &mut CTX,
143 _inputs: &mut interpreter::CallInputs,
144 ) -> Option<interpreter::CallOutcome> {
145 self.call_count += 1;
146 None
147 }
148
149 fn call_end(
150 &mut self,
151 _context: &mut CTX,
152 _inputs: &interpreter::CallInputs,
153 _outcome: &mut interpreter::CallOutcome,
154 ) {
155 self.call_end_count += 1;
156 }
157
158 fn create(
159 &mut self,
160 _context: &mut CTX,
161 _inputs: &mut interpreter::CreateInputs,
162 ) -> Option<interpreter::CreateOutcome> {
163 self.create_count += 1;
164 None
165 }
166
167 fn create_end(
168 &mut self,
169 _context: &mut CTX,
170 _inputs: &interpreter::CreateInputs,
171 _outcome: &mut interpreter::CreateOutcome,
172 ) {
173 self.create_end_count += 1;
174 }
175
176 fn selfdestruct(
177 &mut self,
178 _contract: primitives::Address,
179 _target: primitives::Address,
180 _value: primitives::U256,
181 ) {
182 self.selfdestruct_count += 1;
183 }
184}
185
186#[cfg(test)]
187mod tests {
188 use super::*;
189 use crate::InspectEvm;
190 use context::Context;
191 use database::BenchmarkDB;
192 use handler::{MainBuilder, MainContext};
193 use primitives::{Bytes, TxKind};
194 use state::bytecode::{opcode, Bytecode};
195
196 #[test]
197 fn test_count_inspector() {
198 let contract_data: Bytes = Bytes::from(vec![
200 opcode::PUSH1,
201 0x10, opcode::PUSH1,
203 0x20, opcode::ADD, opcode::DUP1, opcode::PUSH1,
207 0x00, opcode::MSTORE, opcode::STOP, ]);
211 let bytecode = Bytecode::new_raw(contract_data);
212
213 let ctx = Context::mainnet().with_db(BenchmarkDB::new_bytecode(bytecode.clone()));
214 let mut count_inspector = CountInspector::new();
215
216 let mut evm = ctx.build_mainnet_with_inspector(&mut count_inspector);
217
218 evm.inspect_one_tx(
220 context::TxEnv::builder()
221 .kind(TxKind::Call(database::BENCH_TARGET))
222 .gas_limit(30000)
223 .build()
224 .unwrap(),
225 )
226 .unwrap();
227
228 assert_eq!(count_inspector.get_count(opcode::PUSH1), 3);
230 assert_eq!(count_inspector.get_count(opcode::ADD), 1);
231 assert_eq!(count_inspector.get_count(opcode::DUP1), 1);
232 assert_eq!(count_inspector.get_count(opcode::MSTORE), 1);
233 assert_eq!(count_inspector.get_count(opcode::STOP), 1);
234
235 assert_eq!(count_inspector.total_opcodes(), 7);
237 assert_eq!(count_inspector.unique_opcodes(), 5);
238
239 assert_eq!(count_inspector.initialize_interp_count(), 1);
241 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);
246 assert_eq!(count_inspector.create_count(), 0); assert_eq!(count_inspector.create_end_count(), 0);
248 assert_eq!(count_inspector.selfdestruct_count(), 0); }
250
251 #[test]
252 fn test_count_inspector_clear() {
253 let mut inspector = CountInspector::new();
254
255 *inspector.opcode_counts.entry(opcode::PUSH1).or_insert(0) += 5;
257 *inspector.opcode_counts.entry(opcode::ADD).or_insert(0) += 3;
258 inspector.initialize_interp_count = 2;
259 inspector.step_count = 10;
260 inspector.step_end_count = 10;
261 inspector.log_count = 1;
262 inspector.call_count = 3;
263 inspector.call_end_count = 3;
264 inspector.create_count = 1;
265 inspector.create_end_count = 1;
266 inspector.selfdestruct_count = 1;
267
268 assert_eq!(inspector.total_opcodes(), 8);
269 assert_eq!(inspector.unique_opcodes(), 2);
270 assert_eq!(inspector.initialize_interp_count(), 2);
271 assert_eq!(inspector.step_count(), 10);
272
273 inspector.clear();
275 assert_eq!(inspector.total_opcodes(), 0);
276 assert_eq!(inspector.unique_opcodes(), 0);
277 assert!(inspector.opcode_counts().is_empty());
278 assert_eq!(inspector.initialize_interp_count(), 0);
279 assert_eq!(inspector.step_count(), 0);
280 assert_eq!(inspector.step_end_count(), 0);
281 assert_eq!(inspector.log_count(), 0);
282 assert_eq!(inspector.call_count(), 0);
283 assert_eq!(inspector.call_end_count(), 0);
284 assert_eq!(inspector.create_count(), 0);
285 assert_eq!(inspector.create_end_count(), 0);
286 assert_eq!(inspector.selfdestruct_count(), 0);
287 }
288
289 #[test]
290 fn test_count_inspector_with_logs() {
291 let contract_data: Bytes = Bytes::from(vec![
293 opcode::PUSH1,
294 0x20, opcode::PUSH1,
296 0x00, opcode::LOG0, opcode::STOP, ]);
300 let bytecode = Bytecode::new_raw(contract_data);
301
302 let ctx = Context::mainnet().with_db(BenchmarkDB::new_bytecode(bytecode.clone()));
303 let mut count_inspector = CountInspector::new();
304
305 let mut evm = ctx.build_mainnet_with_inspector(&mut count_inspector);
306
307 evm.inspect_one_tx(
309 context::TxEnv::builder()
310 .kind(TxKind::Call(database::BENCH_TARGET))
311 .gas_limit(30000)
312 .build()
313 .unwrap(),
314 )
315 .unwrap();
316
317 assert_eq!(count_inspector.log_count(), 1);
319 assert_eq!(count_inspector.step_count(), 4); }
321}