1use crate::{
21 database::Database,
22 exec_context::ExecContext,
23 test_api::{
24 DebugInfo,
25 EmittedEvent,
26 },
27 types::BlockTimestamp,
28};
29use hex_literal::hex;
30use ink_primitives::{
31 Address,
32 U256,
33};
34pub use pallet_revive_uapi::ReturnErrorCode as Error;
35use std::panic::panic_any;
36
37pub struct Engine {
39 pub database: Database,
41 pub exec_context: ExecContext,
43 pub(crate) debug_info: DebugInfo,
47 pub chain_spec: ChainSpec,
49}
50
51pub struct ChainSpec {
53 pub gas_price: U256,
55 pub minimum_balance: U256,
58 pub block_time: BlockTimestamp,
60}
61
62impl Default for ChainSpec {
70 fn default() -> Self {
71 Self {
72 gas_price: 100.into(),
73 minimum_balance: 42.into(),
74 block_time: 6,
75 }
76 }
77}
78
79impl Engine {
80 pub fn new() -> Self {
82 Self {
83 database: Database::new(),
84 exec_context: ExecContext::new(),
85 debug_info: DebugInfo::new(),
86 chain_spec: ChainSpec::default(),
87 }
88 }
89}
90
91impl Default for Engine {
92 fn default() -> Self {
93 Self::new()
94 }
95}
96
97impl Engine {
98 #[allow(clippy::arithmetic_side_effects)] pub fn transfer(&mut self, dest: Address, mut value: &[u8]) -> Result<(), Error> {
101 let increment = <u128 as scale::Decode>::decode(&mut value)
103 .map_err(|_| Error::TransferFailed)?;
104
105 let dest_old_balance = self.get_balance(dest).unwrap_or_default();
107
108 let contract = self.get_callee();
109 let contract_old_balance = self
110 .get_balance(contract)
111 .map_err(|_| Error::TransferFailed)?;
112
113 self.database
114 .set_balance(&contract, contract_old_balance - increment);
115 self.database
116 .set_balance(&dest, dest_old_balance + increment);
117 Ok(())
118 }
119
120 pub fn deposit_event(&mut self, topics: &[[u8; 32]], data: &[u8]) {
122 self.debug_info.record_event(EmittedEvent {
123 topics: topics.to_vec(),
124 data: data.to_vec(),
125 });
126 }
127
128 pub fn set_storage(&mut self, key: &[u8], encoded_value: &[u8]) -> Option<u32> {
131 let callee = self.get_callee();
132
133 self.debug_info.inc_writes(callee);
134 self.debug_info
135 .record_cell_for_account(callee, key.to_vec());
136
137 self.database
138 .insert_into_contract_storage(&callee, key, encoded_value.to_vec())
139 .map(|v| <u32>::try_from(v.len()).expect("usize to u32 conversion failed"))
140 }
141
142 pub fn get_storage(&mut self, key: &[u8]) -> Result<&[u8], Error> {
144 let callee = self.get_callee();
145
146 self.debug_info.inc_reads(callee);
147 match self.database.get_from_contract_storage(&callee, key) {
148 Some(val) => Ok(val),
149 None => Err(Error::KeyNotFound),
150 }
151 }
152
153 pub fn take_storage(&mut self, key: &[u8]) -> Result<Vec<u8>, Error> {
156 let callee = self.get_callee();
157
158 self.debug_info.inc_writes(callee);
159 match self.database.remove_contract_storage(&callee, key) {
160 Some(val) => Ok(val),
161 None => Err(Error::KeyNotFound),
162 }
163 }
164
165 pub fn contains_storage(&mut self, key: &[u8]) -> Option<u32> {
167 let callee = self.get_callee();
168
169 self.debug_info.inc_reads(callee);
170 self.database
171 .get_from_contract_storage(&callee, key)
172 .map(|val| val.len() as u32)
173 }
174
175 pub fn clear_storage(&mut self, key: &[u8]) -> Option<u32> {
178 let callee = self.get_callee();
179 self.debug_info.inc_writes(callee);
180 let _ = self
181 .debug_info
182 .remove_cell_for_account(callee, key.to_vec());
183 self.database
184 .remove_contract_storage(&callee, key)
185 .map(|val| val.len() as u32)
186 }
187
188 pub fn terminate(&mut self, beneficiary: Address) -> ! {
195 let contract = self.get_callee();
197 let all = self
198 .get_balance(contract)
199 .unwrap_or_else(|err| panic!("could not get balance: {err:?}"));
200 let value = &scale::Encode::encode(&all)[..];
201 self.transfer(beneficiary, value)
202 .unwrap_or_else(|err| panic!("transfer did not work: {err:?}"));
203
204 let res = (all, beneficiary);
208 panic_any(scale::Encode::encode(&res));
209 }
210
211 pub fn caller(&self, output: &mut &mut [u8]) {
213 let caller = self.exec_context.caller;
214 let caller = scale::Encode::encode(&caller);
215 set_output(output, &caller[..])
216 }
217
218 pub fn balance(&self, output: &mut &mut [u8]) {
220 let contract = self
221 .exec_context
222 .callee
223 .as_ref()
224 .expect("no callee has been set");
225
226 let balance_in_storage = self
227 .database
228 .get_balance(contract)
229 .expect("currently executing contract must exist");
230 let balance = scale::Encode::encode(&balance_in_storage);
231 set_output(output, &balance[..])
232 }
233
234 pub fn value_transferred(&self, output: &mut &mut [u8]) {
236 let value_transferred: Vec<u8> =
237 scale::Encode::encode(&self.exec_context.value_transferred);
238 set_output(output, &value_transferred[..])
239 }
240
241 pub fn address(&self, output: &mut &mut [u8]) {
243 let callee = self
244 .exec_context
245 .callee
246 .as_ref()
247 .expect("no callee has been set")
248 .as_bytes();
249 set_output(output, callee)
250 }
251
252 pub fn account_id(&self, output: &mut &mut [u8]) {
253 let callee = self
254 .exec_context
255 .callee
256 .as_ref()
257 .expect("no callee has been set");
258 let account_id = self.database.to_account_id(callee);
259 set_output(output, account_id.as_slice())
260 }
261
262 pub fn to_account_id(&self, input: &[u8], output: &mut &mut [u8]) {
264 let addr =
265 scale::Decode::decode(&mut &input[..]).expect("unable to decode Address");
266 let account_id = self.database.to_account_id(&addr);
267 set_output(output, account_id.as_slice())
268 }
269
270 pub fn hash_blake2_256(input: &[u8], output: &mut [u8; 32]) {
272 super::hashing::blake2b_256(input, output);
273 }
274
275 pub fn hash_blake2_128(input: &[u8], output: &mut [u8; 16]) {
277 super::hashing::blake2b_128(input, output);
278 }
279
280 pub fn hash_sha2_256(input: &[u8], output: &mut [u8; 32]) {
282 super::hashing::sha2_256(input, output);
283 }
284
285 pub fn hash_keccak_256(input: &[u8], output: &mut [u8; 32]) {
287 super::hashing::keccak_256(input, output);
288 }
289
290 pub fn block_number(&self, output: &mut &mut [u8]) {
292 let block_number: Vec<u8> =
293 scale::Encode::encode(&self.exec_context.block_number);
294 set_output(output, &block_number[..])
295 }
296
297 pub fn block_timestamp(&self, output: &mut &mut [u8]) {
299 let block_timestamp: Vec<u8> =
300 scale::Encode::encode(&self.exec_context.block_timestamp);
301 set_output(output, &block_timestamp[..])
302 }
303
304 pub fn minimum_balance(&self, output: &mut &mut [u8]) {
307 let minimum_balance: Vec<u8> =
308 scale::Encode::encode(&self.chain_spec.minimum_balance);
309 set_output(output, &minimum_balance[..])
310 }
311
312 #[allow(clippy::too_many_arguments)]
313 pub fn instantiate(
314 &mut self,
315 _code_hash: &[u8],
316 _gas_limit: u64,
317 _endowment: &[u8],
318 _input: &[u8],
319 _out_address: &mut &mut [u8],
320 _out_return_value: &mut &mut [u8],
321 _salt: &[u8],
322 ) -> Result<(), Error> {
323 unimplemented!("off-chain environment does not yet support `instantiate`");
324 }
325
326 pub fn call(
327 &mut self,
328 callee: &[u8],
329 _gas_limit: u64,
330 _value: &[u8],
331 input: &[u8],
332 output: &mut &mut [u8],
333 ) -> Result<(), Error> {
334 const ECRECOVER: [u8; 20] = hex!("0000000000000000000000000000000000000001");
335 if callee == ECRECOVER {
336 let mut signature = [0u8; 65];
337 signature.copy_from_slice(&input[..65]);
338 let mut message_hash = [0u8; 32];
339 message_hash.copy_from_slice(&input[65..65 + 32]);
340
341 let out: &mut [u8; 33] = output
342 .as_mut()
343 .try_into()
344 .expect("Slice must be exactly 33 bytes long");
345 let _ = self.ecdsa_recover(&signature, &message_hash, out);
346 }
347 unimplemented!(
348 "off-chain environment does not yet support `call` for non-precompiles"
349 );
350 }
351
352 pub fn weight_to_fee(&self, gas: u64, output: &mut &mut [u8]) {
354 let fee = self.chain_spec.gas_price.saturating_mul(gas.into());
355 let fee: Vec<u8> = scale::Encode::encode(&fee);
356 set_output(output, &fee[..])
357 }
358}
359
360impl Engine {
361 #[allow(clippy::arithmetic_side_effects)] pub fn ecdsa_recover(
365 &mut self,
366 signature: &[u8; 65],
367 message_hash: &[u8; 32],
368 output: &mut [u8; 33],
369 ) -> Result<(), Error> {
370 use secp256k1::{
371 Message,
372 SECP256K1,
373 ecdsa::{
374 RecoverableSignature,
375 RecoveryId,
376 },
377 };
378
379 let recovery_byte = if signature[64] > 26 {
383 signature[64] - 27
384 } else {
385 signature[64]
386 };
387
388 let recovery_id = RecoveryId::try_from(recovery_byte as i32)
389 .unwrap_or_else(|error| panic!("Unable to parse the recovery id: {error}"));
390
391 let message = Message::from_digest_slice(message_hash).unwrap_or_else(|error| {
392 panic!("Unable to create the message from hash: {error}")
393 });
394 let signature =
395 RecoverableSignature::from_compact(&signature[0..64], recovery_id)
396 .unwrap_or_else(|error| panic!("Unable to parse the signature: {error}"));
397
398 let pub_key = SECP256K1.recover_ecdsa(&message, &signature);
399 match pub_key {
400 Ok(pub_key) => {
401 *output = pub_key.serialize();
402 Ok(())
403 }
404 Err(_) => Err(Error::EcdsaRecoveryFailed),
405 }
406 }
407}
408
409fn set_output(output: &mut &mut [u8], slice: &[u8]) {
413 assert!(
414 slice.len() <= output.len(),
415 "the output buffer is too small! the decoded storage is of size {} bytes, \
416 but the output buffer has only room for {}.",
417 slice.len(),
418 output.len(),
419 );
420 output[..slice.len()].copy_from_slice(slice);
421}