1use crate::{
16 ext::Engine,
17 types::{
18 Balance,
19 BlockNumber,
20 BlockTimestamp,
21 },
22 AccountError,
23 Error,
24};
25use ink_primitives::{
26 AccountId,
27 Address,
28 U256,
29};
30use std::collections::HashMap;
31
32#[derive(Debug, Clone)]
34pub struct EmittedEvent {
35 pub topics: Vec<Vec<u8>>,
37 pub data: Vec<u8>,
39}
40
41pub struct DebugInfo {
43 emitted_events: Vec<EmittedEvent>,
45 count_reads: HashMap<Address, usize>,
47 count_writes: HashMap<Address, usize>,
49 cells_per_contract: HashMap<Address, HashMap<Vec<u8>, bool>>,
51}
52
53impl Default for DebugInfo {
54 fn default() -> Self {
55 Self::new()
56 }
57}
58
59impl DebugInfo {
60 pub fn new() -> Self {
62 Self {
63 emitted_events: Vec::new(),
64 count_reads: HashMap::new(),
65 count_writes: HashMap::new(),
66 cells_per_contract: HashMap::new(),
67 }
68 }
69
70 pub fn reset(&mut self) {
72 self.count_reads.clear();
73 self.count_writes.clear();
74 self.emitted_events.clear();
75 self.cells_per_contract.clear();
76 }
77
78 #[allow(clippy::arithmetic_side_effects)] pub fn inc_writes(&mut self, addr: Address) {
81 self.count_writes
82 .entry(addr)
83 .and_modify(|v| *v += 1)
84 .or_insert(1);
85 }
86
87 #[allow(clippy::arithmetic_side_effects)] pub fn inc_reads(&mut self, addr: Address) {
90 self.count_reads
91 .entry(addr)
92 .and_modify(|v| *v += 1)
93 .or_insert(1);
94 }
95
96 pub fn record_cell_for_account(&mut self, addr: Address, key: Vec<u8>) {
101 self.cells_per_contract
102 .entry(addr)
103 .and_modify(|hm| {
104 let _ = hm.insert(key.clone(), true);
105 })
106 .or_insert({
107 let mut hm = HashMap::new();
108 hm.insert(key, true);
109 hm
110 });
111 }
112
113 pub fn remove_cell_for_account(
117 &mut self,
118 addr: Address,
119 key: Vec<u8>,
120 ) -> Option<bool> {
121 self.cells_per_contract
122 .get_mut(&addr)
123 .map(|hm| hm.remove(&key))
124 .unwrap_or(None)
125 }
126
127 pub fn record_event(&mut self, event: EmittedEvent) {
129 self.emitted_events.push(event);
130 }
131}
132
133impl Engine {
134 pub fn initialize_or_reset(&mut self) {
136 self.exec_context.reset();
137 self.database.clear();
138 self.debug_info.reset();
139 }
140
141 pub fn get_contract_storage_rw(&self, addr: Address) -> (usize, usize) {
143 let reads = self.debug_info.count_reads.get(&addr).unwrap_or(&0);
144 let writes = self.debug_info.count_writes.get(&addr).unwrap_or(&0);
145 (*reads, *writes)
146 }
147
148 pub fn count_reads(&self) -> usize {
150 self.debug_info.count_reads.values().sum()
151 }
152
153 pub fn count_writes(&self) -> usize {
155 self.debug_info.count_writes.values().sum()
156 }
157
158 pub fn set_caller(&mut self, caller: Address) {
160 self.exec_context.caller = caller;
161 }
162
163 pub fn set_contract(&mut self, caller: Address) {
165 self.exec_context.contracts.push(caller);
166 }
167
168 pub fn set_callee(&mut self, callee: Address) {
170 self.exec_context.callee = Some(callee);
171 }
172
173 pub fn count_used_storage_cells(&self, addr: &Address) -> Result<usize, Error> {
177 let cells = self
178 .debug_info
179 .cells_per_contract
180 .get(addr)
181 .ok_or(Error::Account(AccountError::NoContractForId(*addr)))?;
182 Ok(cells.len())
183 }
184
185 pub fn advance_block(&mut self) {
187 self.exec_context.block_number = self
188 .exec_context
189 .block_number
190 .checked_add(1)
191 .expect("failed to add");
192 self.exec_context.block_timestamp = self
193 .exec_context
194 .block_timestamp
195 .checked_add(self.chain_spec.block_time)
196 .expect("failed to add");
197 }
198
199 pub fn get_callee(&self) -> Address {
201 self.exec_context.callee()
202 }
203
204 pub fn is_contract(&self, addr: &Address) -> bool {
206 self.exec_context.contracts.contains(addr)
207 }
208
209 pub fn get_emitted_events(&self) -> impl Iterator<Item = EmittedEvent> {
211 self.debug_info.emitted_events.clone().into_iter()
212 }
213
214 pub fn get_acc_balance(&self, addr: AccountId) -> Result<Balance, Error> {
216 self.database
217 .get_acc_balance(&addr)
218 .ok_or(Error::Account(AccountError::NoAccountForId(addr)))
219 }
220
221 pub fn set_acc_balance(&mut self, addr: AccountId, new_balance: Balance) {
223 self.database.set_acc_balance(&addr, new_balance);
224 }
225
226 pub fn get_balance(&self, addr: Address) -> Result<U256, Error> {
228 self.database
229 .get_balance(&addr)
230 .ok_or(Error::Account(AccountError::NoContractForId(addr)))
231 }
232
233 pub fn set_balance(&mut self, addr: Address, new_balance: U256) {
235 self.database.set_balance(&addr, new_balance);
236 }
237
238 pub fn set_value_transferred(&mut self, value: U256) {
240 self.exec_context.value_transferred = value;
241 }
242
243 pub fn set_block_timestamp(&mut self, new_block_timestamp: BlockTimestamp) {
245 self.exec_context.block_timestamp = new_block_timestamp;
246 }
247
248 pub fn set_block_number(&mut self, new_block_number: BlockNumber) {
250 self.exec_context.block_number = new_block_number;
251 }
252}
253
254#[cfg(test)]
255mod tests {
256 use super::*;
257
258 #[test]
259 fn setting_getting_callee() {
260 let mut engine = Engine::new();
261 let addr = Address::from([1; 20]);
262 engine.set_callee(addr);
263 assert_eq!(engine.get_callee(), addr);
264 }
265
266 #[test]
267 fn count_cells_per_account_must_stay_the_same() {
268 let mut engine = Engine::new();
270 let addr = Address::from([1; 20]);
271 engine.set_callee(addr);
272 let key: &[u8; 32] = &[0x42; 32];
273 engine.set_storage(key, &[0x05_u8; 5]);
274 assert_eq!(engine.count_used_storage_cells(&addr), Ok(1));
275
276 engine.set_storage(key, &[0x05_u8; 6]);
279
280 assert_eq!(engine.count_used_storage_cells(&addr), Ok(1));
283 }
284
285 #[test]
286 fn count_cells_per_account_must_be_reset() {
287 let mut engine = Engine::new();
289 let addr = Address::from([1; 20]);
290 engine.set_callee(addr);
291 let key: &[u8; 32] = &[0x42; 32];
292 engine.set_storage(key, &[0x05_u8; 5]);
293 assert_eq!(engine.count_used_storage_cells(&addr), Ok(1));
294
295 engine.clear_storage(key);
297
298 assert_eq!(engine.count_used_storage_cells(&addr), Ok(0));
300 }
301
302 #[test]
303 fn count_total_writes() {
304 let mut engine = Engine::new();
306 let key: &[u8; 32] = &[0x42; 32];
307
308 engine.set_callee(Address::from([1; 20]));
310 engine.set_storage(key, &[0x05_u8; 5]);
311 engine.set_storage(key, &[0x05_u8; 6]);
312 engine.get_storage(key).unwrap();
313
314 engine.set_callee(Address::from([2; 20]));
315 engine.set_storage(key, &[0x07_u8; 7]);
316 engine.get_storage(key).unwrap();
317
318 assert_eq!(engine.count_writes(), 3);
320 assert_eq!(engine.count_reads(), 2);
321 }
322}