1use ink_engine::ext::Engine;
16#[cfg(feature = "xcm")]
17use ink_primitives::Weight;
18use ink_primitives::{
19 Address,
20 CodeHashErr,
21 H256,
22 U256,
23 abi::{
24 AbiEncodeWith,
25 Ink,
26 Sol,
27 },
28 sol::SolResultEncode,
29 types::{
30 AccountIdMapper,
31 Environment,
32 },
33};
34use ink_storage_traits::{
35 Storable,
36 decode_all,
37};
38use pallet_revive_uapi::{
39 ReturnErrorCode,
40 ReturnFlags,
41};
42#[cfg(feature = "unstable-hostfn")]
43use schnorrkel::{
44 PublicKey,
45 Signature,
46};
47
48use super::EnvInstance;
49use crate::{
50 DecodeDispatch,
51 DispatchError,
52 EnvBackend,
53 Result,
54 TypedEnvBackend,
55 call::{
56 Call,
57 CallParams,
58 ConstructorReturnType,
59 CreateParams,
60 DelegateCall,
61 FromAddr,
62 LimitParamsV2,
63 utils::{
64 DecodeMessageResult,
65 EncodeArgsWith,
66 },
67 },
68 event::{
69 Event,
70 TopicEncoder,
71 TopicsBuilderBackend,
72 },
73 hash::{
74 Blake2x128,
75 Blake2x256,
76 CryptoHash,
77 HashOutput,
78 Keccak256,
79 Sha2x256,
80 },
81 test::callee,
82};
83
84const BUFFER_SIZE: usize = crate::BUFFER_SIZE;
88
89fn execute_contract_call<ContractRef>(input: Vec<u8>) -> Vec<u8>
91where
92 ContractRef: crate::ContractReverseReference,
93 <ContractRef as crate::ContractReverseReference>::Type:
94 crate::reflect::ContractMessageDecoder,
95{
96 let dispatch = <
97 <
98 <
99 ContractRef
100 as crate::ContractReverseReference
101 >::Type
102 as crate::reflect::ContractMessageDecoder
103 >::Type
104 as DecodeDispatch
105 >::decode_dispatch(&mut &input[..])
106 .unwrap_or_else(|e| panic!("Failed to decode constructor call: {e:?}"));
107
108 crate::reflect::ExecuteDispatchable::execute_dispatchable(dispatch)
109 .unwrap_or_else(|e| panic!("Message call failed: {e:?}"));
110
111 crate::test::get_return_value()
112}
113
114fn invoke_contract_impl<R, Abi>(
115 env: &mut EnvInstance,
116 _gas_limit: Option<u64>,
117 _call_flags: u32,
118 _transferred_value: Option<&U256>,
119 callee_account: Address,
120 input: Vec<u8>,
121) -> Result<ink_primitives::MessageResult<R>>
122where
123 R: DecodeMessageResult<Abi>,
124{
125 let callee_code_hash = env.code_hash(&callee_account).unwrap_or_else(|err| {
126 panic!("failed getting code hash for {callee_account:?}: {err:?}")
127 });
128
129 let handler = env
130 .engine
131 .database
132 .get_contract_message_handler(&callee_code_hash);
133 let old_callee = env.engine.get_callee();
134 env.engine.set_callee(callee_account);
135
136 let result = handler(input);
137
138 env.engine.set_callee(old_callee);
139
140 R::decode_output(&result, false)
142}
143
144fn invoke_contract_impl_delegate<R, Abi>(
145 env: &mut EnvInstance,
146 _gas_limit: Option<u64>,
147 _call_flags: u32,
148 _transferred_value: Option<&U256>,
149 callee_account: Address,
150 input: Vec<u8>,
151) -> Result<ink_primitives::MessageResult<R>>
152where
153 R: DecodeMessageResult<Abi>,
154{
155 let callee_code_hash = env.code_hash(&callee_account).unwrap_or_else(|err| {
156 panic!("failed getting code hash for {callee_account:?}: {err:?}")
157 });
158
159 let handler = env
160 .engine
161 .database
162 .get_contract_message_handler(&callee_code_hash);
163 let result = handler(input);
164
165 R::decode_output(&result, false)
167}
168
169impl CryptoHash for Blake2x128 {
170 fn hash(input: &[u8], output: &mut <Self as HashOutput>::Type) {
171 type OutputType = [u8; 16];
172 static_assertions::assert_type_eq_all!(
173 <Blake2x128 as HashOutput>::Type,
174 OutputType
175 );
176 let output: &mut OutputType = array_mut_ref!(output, 0, 16);
177 Engine::hash_blake2_128(input, output);
178 }
179
180 fn hash_with_buffer(
181 _input: &[u8],
182 _buffer: &mut [u8],
183 _output: &mut <Self as HashOutput>::Type,
184 ) {
185 unreachable!("not required, `hash` has been implemented.");
186 }
187}
188
189impl CryptoHash for Blake2x256 {
190 fn hash(input: &[u8], output: &mut <Self as HashOutput>::Type) {
191 type OutputType = [u8; 32];
194 static_assertions::assert_type_eq_all!(
195 <Blake2x256 as HashOutput>::Type,
196 OutputType
197 );
198 let output: &mut OutputType = array_mut_ref!(output, 0, 32);
199 Engine::hash_blake2_256(input, output);
200 }
201
202 fn hash_with_buffer(
203 _input: &[u8],
204 _buffer: &mut [u8],
205 _output: &mut <Self as HashOutput>::Type,
206 ) {
207 unreachable!("not required, `hash` has been implemented.");
208 }
209}
210
211impl CryptoHash for Sha2x256 {
212 fn hash(input: &[u8], output: &mut <Self as HashOutput>::Type) {
213 type OutputType = [u8; 32];
216 static_assertions::assert_type_eq_all!(
217 <Sha2x256 as HashOutput>::Type,
218 OutputType
219 );
220 let output: &mut OutputType = array_mut_ref!(output, 0, 32);
221 Engine::hash_sha2_256(input, output);
222 }
223
224 fn hash_with_buffer(
225 _input: &[u8],
226 _buffer: &mut [u8],
227 _output: &mut <Self as HashOutput>::Type,
228 ) {
229 unreachable!("not required, `hash` has been implemented.");
230 }
231}
232
233impl CryptoHash for Keccak256 {
234 fn hash(input: &[u8], output: &mut <Self as HashOutput>::Type) {
235 type OutputType = [u8; 32];
236 static_assertions::assert_type_eq_all!(
237 <Keccak256 as HashOutput>::Type,
238 OutputType
239 );
240 let output: &mut OutputType = array_mut_ref!(output, 0, 32);
241 Engine::hash_keccak_256(input, output);
242 }
243
244 fn hash_with_buffer(
245 _input: &[u8],
246 _buffer: &mut [u8],
247 _output: &mut <Self as HashOutput>::Type,
248 ) {
249 unreachable!("not required, `hash` has been implemented.");
250 }
251}
252
253#[derive(Default)]
254pub struct TopicsBuilder {
255 pub topics: Vec<[u8; 32]>,
256}
257
258impl<Abi> TopicsBuilderBackend<Abi> for TopicsBuilder
259where
260 Abi: TopicEncoder,
261{
262 type Output = Vec<[u8; 32]>;
263
264 fn push_topic<T>(&mut self, topic_value: &T)
265 where
266 T: AbiEncodeWith<Abi>,
267 {
268 let output = <Abi as TopicEncoder>::encode_topic(topic_value);
269 self.topics.push(output);
270 }
271
272 fn output(self) -> Self::Output {
273 self.topics
274 }
275}
276
277impl TopicEncoder for Ink {
278 const REQUIRES_BUFFER: bool = false;
279
280 fn encode_topic<T>(value: &T) -> [u8; 32]
281 where
282 T: AbiEncodeWith<Self>,
283 {
284 value.encode_topic(<Blake2x256 as CryptoHash>::hash)
285 }
286
287 fn encode_topic_with_hash_buffer<T>(
288 _value: &T,
289 _output: &mut [u8; 32],
290 _buffer: &mut [u8],
291 ) where
292 T: AbiEncodeWith<Self>,
293 {
294 unreachable!("not required, `encode_topic` has been implemented.");
295 }
296}
297
298impl TopicEncoder for Sol {
299 const REQUIRES_BUFFER: bool = false;
300
301 fn encode_topic<T>(value: &T) -> [u8; 32]
302 where
303 T: AbiEncodeWith<Self>,
304 {
305 value.encode_topic(<Keccak256 as CryptoHash>::hash)
306 }
307
308 fn encode_topic_with_hash_buffer<T>(
309 _value: &T,
310 _output: &mut [u8; 32],
311 _buffer: &mut [u8],
312 ) where
313 T: AbiEncodeWith<Self>,
314 {
315 unreachable!("not required, `encode_topic` has been implemented.");
316 }
317}
318
319impl EnvInstance {
320 fn get_property<T>(
322 &mut self,
323 ext_fn: fn(engine: &Engine, output: &mut &mut [u8]),
324 ) -> Result<T>
325 where
326 T: scale::Decode,
327 {
328 let mut full_scope: [u8; BUFFER_SIZE] = [0; BUFFER_SIZE];
329 let full_scope = &mut &mut full_scope[..];
330 ext_fn(&self.engine, full_scope);
331 scale::Decode::decode(&mut &full_scope[..]).map_err(Into::into)
332 }
333
334 pub fn get_return_value(&mut self) -> Vec<u8> {
335 self.engine.get_storage(&[255_u8; 32]).unwrap().to_vec()
336 }
337
338 pub fn upload_code<ContractRef>(&mut self) -> H256
339 where
340 ContractRef: crate::ContractReverseReference,
341 <ContractRef as crate::ContractReverseReference>::Type:
342 crate::reflect::ContractMessageDecoder,
343 {
344 H256::from(
345 self.engine
346 .database
347 .set_contract_message_handler(execute_contract_call::<ContractRef>),
348 )
349 }
350}
351
352impl EnvBackend for EnvInstance {
353 fn set_contract_storage<K, V>(&mut self, key: &K, value: &V) -> Option<u32>
354 where
355 K: scale::Encode,
356 V: Storable,
357 {
358 let mut v = vec![];
359 Storable::encode(value, &mut v);
360 self.engine.set_storage(&key.encode(), &v[..])
361 }
362
363 fn get_contract_storage<K, R>(&mut self, key: &K) -> Result<Option<R>>
364 where
365 K: scale::Encode,
366 R: Storable,
367 {
368 match self.engine.get_storage(&key.encode()) {
369 Ok(res) => {
370 let decoded = decode_all(&mut &res[..])?;
371 Ok(Some(decoded))
372 }
373 Err(ReturnErrorCode::KeyNotFound) => Ok(None),
374 Err(_) => panic!("encountered unexpected error"),
375 }
376 }
377
378 fn take_contract_storage<K, R>(&mut self, key: &K) -> Result<Option<R>>
379 where
380 K: scale::Encode,
381 R: Storable,
382 {
383 match self.engine.take_storage(&key.encode()) {
384 Ok(output) => {
385 let decoded = decode_all(&mut &output[..])?;
386 Ok(Some(decoded))
387 }
388 Err(ReturnErrorCode::KeyNotFound) => Ok(None),
389 Err(_) => panic!("encountered unexpected error"),
390 }
391 }
392
393 fn remaining_buffer(&mut self) -> usize {
394 BUFFER_SIZE
395 }
396
397 fn contains_contract_storage<K>(&mut self, key: &K) -> Option<u32>
398 where
399 K: scale::Encode,
400 {
401 self.engine.contains_storage(&key.encode())
402 }
403
404 fn clear_contract_storage<K>(&mut self, key: &K) -> Option<u32>
405 where
406 K: scale::Encode,
407 {
408 self.engine.clear_storage(&key.encode())
409 }
410
411 fn decode_input<T>(&mut self) -> core::result::Result<T, DispatchError>
412 where
413 T: DecodeDispatch,
414 {
415 unimplemented!("the off-chain env does not implement `input`")
416 }
417
418 #[cfg(not(feature = "std"))]
419 fn return_value<R>(&mut self, _flags: ReturnFlags, _return_value: &R) -> !
420 where
421 R: scale::Encode,
422 {
423 panic!("enable feature `std` to use `return_value()`")
424 }
425
426 #[cfg(feature = "std")]
427 fn return_value<R>(&mut self, _flags: ReturnFlags, return_value: &R)
428 where
429 R: scale::Encode,
430 {
431 let mut v = vec![];
432 return_value.encode_to(&mut v);
433 self.engine.set_storage(&[255_u8; 32], &v[..]);
434 }
435
436 fn return_value_solidity<R>(&mut self, _flags: ReturnFlags, _return_value: &R) -> !
437 where
438 R: for<'a> SolResultEncode<'a>,
439 {
440 unimplemented!("the off-chain env does not implement `return_value_solidity`")
441 }
442
443 fn hash_bytes<H>(&mut self, input: &[u8], output: &mut <H as HashOutput>::Type)
444 where
445 H: CryptoHash,
446 {
447 <H as CryptoHash>::hash(input, output)
448 }
449
450 fn hash_encoded<H, T>(&mut self, input: &T, output: &mut <H as HashOutput>::Type)
451 where
452 H: CryptoHash,
453 T: scale::Encode,
454 {
455 let enc_input = &scale::Encode::encode(input)[..];
456 <H as CryptoHash>::hash(enc_input, output)
457 }
458
459 fn bn128_add(&mut self, _x1: U256, _y1: U256, _x2: U256, _y2: U256) -> (U256, U256) {
460 unimplemented!(
461 "`bn128_add` is not implemented in the off-chain testing environment"
462 );
463 }
464
465 fn bn128_mul(&mut self, _x1: U256, _y1: U256, _scalar: U256) -> (U256, U256) {
466 unimplemented!(
467 "`bn128_mul` is not implemented in the off-chain testing environment"
468 );
469 }
470
471 fn bn128_pairing(&mut self, _input: &[u8]) -> bool {
472 unimplemented!(
473 "`bn128_pairing` is not implemented in the off-chain testing environment"
474 );
475 }
476
477 #[allow(clippy::arithmetic_side_effects)] fn ecdsa_recover(
479 &mut self,
480 signature: &[u8; 65],
481 message_hash: &[u8; 32],
482 output: &mut [u8; 33],
483 ) -> Result<()> {
484 use secp256k1::{
485 Message,
486 SECP256K1,
487 ecdsa::{
488 RecoverableSignature,
489 RecoveryId,
490 },
491 };
492
493 let recovery_byte = if signature[64] > 26 {
497 signature[64] - 27
498 } else {
499 signature[64]
500 };
501 let recovery_id = RecoveryId::try_from(recovery_byte as i32)
502 .unwrap_or_else(|error| panic!("Unable to parse the recovery id: {error}"));
503 let message = Message::from_digest(*message_hash);
504 let signature =
505 RecoverableSignature::from_compact(&signature[0..64], recovery_id)
506 .unwrap_or_else(|error| panic!("Unable to parse the signature: {error}"));
507
508 let pub_key = SECP256K1.recover_ecdsa(message, &signature);
509 match pub_key {
510 Ok(pub_key) => {
511 *output = pub_key.serialize();
512 Ok(())
513 }
514 Err(_) => Err(ReturnErrorCode::EcdsaRecoveryFailed.into()),
515 }
516 }
517
518 #[cfg(feature = "unstable-hostfn")]
519 fn ecdsa_to_eth_address(
520 &mut self,
521 pubkey: &[u8; 33],
522 output: &mut [u8; 20],
523 ) -> Result<()> {
524 let pk = secp256k1::PublicKey::from_slice(pubkey)
525 .map_err(|_| ReturnErrorCode::EcdsaRecoveryFailed)?;
526 let uncompressed = pk.serialize_uncompressed();
527 let mut hash = <Keccak256 as HashOutput>::Type::default();
528 <Keccak256>::hash(&uncompressed[1..], &mut hash);
529 output.as_mut().copy_from_slice(&hash[12..]);
530 Ok(())
531 }
532
533 #[cfg(feature = "unstable-hostfn")]
534 fn sr25519_verify(
535 &mut self,
536 signature: &[u8; 64],
537 message: &[u8],
538 pub_key: &[u8; 32],
539 ) -> Result<()> {
540 let context = b"substrate";
544 let signature: Signature = Signature::from_bytes(signature)
546 .map_err(|_| ReturnErrorCode::Sr25519VerifyFailed)?;
547 let public_key: PublicKey = PublicKey::from_bytes(pub_key)
549 .map_err(|_| ReturnErrorCode::Sr25519VerifyFailed)?;
550 public_key
552 .verify_simple(context, message, &signature)
553 .map_err(|_| ReturnErrorCode::Sr25519VerifyFailed.into())
554 }
555
556 #[cfg(feature = "unstable-hostfn")]
557 fn set_code_hash(&mut self, code_hash: &H256) -> Result<()> {
558 self.engine
559 .database
560 .set_code_hash(&self.engine.get_callee(), code_hash);
561 Ok(())
562 }
563}
564
565impl TypedEnvBackend for EnvInstance {
566 fn caller(&mut self) -> Address {
567 self.get_property::<Address>(Engine::caller)
568 .unwrap_or_else(|error| panic!("could not read `caller` property: {error:?}"))
569 }
570
571 fn gas_limit(&mut self) -> u64 {
572 unimplemented!("not implemented, the off-chain environment will be removed");
573 }
574
575 fn gas_price(&mut self) -> u64 {
576 unimplemented!("not implemented, the off-chain environment will be removed");
577 }
578
579 fn gas_left(&mut self) -> u64 {
580 unimplemented!("not implemented, the off-chain environment will be removed");
581 }
582
583 fn chain_id(&mut self) -> U256 {
584 unimplemented!("not implemented, the off-chain environment will be removed");
585 }
586
587 fn balance_of(&mut self, _addr: Address) -> U256 {
588 unimplemented!("not implemented, the off-chain environment will be removed");
589 }
590
591 fn base_fee(&mut self) -> U256 {
592 unimplemented!("not implemented, the off-chain environment will be removed");
593 }
594
595 fn origin(&mut self) -> Address {
596 unimplemented!("not implemented, the off-chain environment will be removed");
597 }
598
599 fn block_hash<E: Environment>(&mut self, _block_number: E::BlockNumber) -> H256 {
600 unimplemented!("not implemented, the off-chain environment will be removed");
601 }
602
603 fn block_author(&mut self) -> Address {
604 unimplemented!("not implemented, the off-chain environment will be removed");
605 }
606
607 fn code_size(&mut self, _addr: Address) -> u64 {
608 unimplemented!("not implemented, the off-chain environment will be removed");
609 }
610
611 fn call_data_size(&mut self) -> u64 {
612 unimplemented!("not implemented, the off-chain environment will be removed");
613 }
614
615 fn return_data_size(&mut self) -> u64 {
616 unimplemented!("not implemented, the off-chain environment will be removed");
617 }
618
619 fn transferred_value(&mut self) -> U256 {
620 self.get_property(Engine::value_transferred)
621 .unwrap_or_else(|error| {
622 panic!("could not read `transferred_value` property: {error:?}")
623 })
624 }
625
626 fn block_timestamp<E: Environment>(&mut self) -> E::Timestamp {
627 self.get_property::<E::Timestamp>(Engine::block_timestamp)
628 .unwrap_or_else(|error| {
629 panic!("could not read `block_timestamp` property: {error:?}")
630 })
631 }
632
633 fn to_account_id<E: Environment>(&mut self, addr: Address) -> E::AccountId {
634 let mut full_scope: [u8; BUFFER_SIZE] = [0; BUFFER_SIZE];
635 let full_scope = &mut &mut full_scope[..];
636 Engine::to_account_id(&self.engine, addr.as_bytes(), full_scope);
637 scale::Decode::decode(&mut &full_scope[..]).unwrap()
638 }
639
640 fn account_id<E: Environment>(&mut self) -> E::AccountId {
641 self.get_property::<E::AccountId>(Engine::account_id)
642 .unwrap_or_else(|error| {
643 panic!("could not read `account_id` property: {error:?}")
644 })
645 }
646
647 fn address(&mut self) -> Address {
648 self.get_property::<Address>(Engine::address)
649 .unwrap_or_else(|error| {
650 panic!("could not read `account_id` property: {error:?}")
651 })
652 }
653
654 fn balance(&mut self) -> U256 {
655 self.get_property::<U256>(Engine::balance)
656 .unwrap_or_else(|error| {
657 panic!("could not read `balance` property: {error:?}")
658 })
659 }
660
661 fn block_number<E: Environment>(&mut self) -> E::BlockNumber {
662 self.get_property::<E::BlockNumber>(Engine::block_number)
663 .unwrap_or_else(|error| {
664 panic!("could not read `block_number` property: {error:?}")
665 })
666 }
667
668 fn minimum_balance(&mut self) -> U256 {
669 self.get_property::<U256>(Engine::minimum_balance)
670 .unwrap_or_else(|error| {
671 panic!("could not read `minimum_balance` property: {error:?}")
672 })
673 }
674
675 fn emit_event<Evt, Abi>(&mut self, event: &Evt)
676 where
677 Evt: Event<Abi>,
678 Abi: TopicEncoder,
679 {
680 let builder = TopicsBuilder::default();
681 let enc_topics = event.topics(builder.into());
682 let enc_data = event.encode_data();
683 self.engine
684 .deposit_event(&enc_topics[..], enc_data.as_slice());
685 }
686
687 fn invoke_contract<E, Args, R, Abi>(
688 &mut self,
689 params: &CallParams<E, Call, Args, R, Abi>,
690 ) -> Result<ink_primitives::MessageResult<R>>
691 where
692 E: Environment,
693 Args: EncodeArgsWith<Abi>,
694 R: DecodeMessageResult<Abi>,
695 {
696 let call_flags = params.call_flags().bits();
697 let transferred_value = params.transferred_value();
698 let input = params.exec_input().encode();
699 let callee_account = params.callee();
700
701 invoke_contract_impl::<R, Abi>(
702 self,
703 None,
704 call_flags,
705 Some(transferred_value),
706 *callee_account, input,
708 )
709 }
710
711 fn invoke_contract_delegate<E, Args, R, Abi>(
712 &mut self,
713 params: &CallParams<E, DelegateCall, Args, R, Abi>,
714 ) -> Result<ink_primitives::MessageResult<R>>
715 where
716 E: Environment,
717 Args: EncodeArgsWith<Abi>,
718 R: DecodeMessageResult<Abi>,
719 {
720 let _addr = params.address(); let call_flags = params.call_flags().bits();
722 let input = params.exec_input().encode();
723
724 invoke_contract_impl_delegate::<R, Abi>(
725 self,
726 None,
727 call_flags,
728 None,
729 *params.address(),
730 input,
731 )
732 }
733
734 fn instantiate_contract<E, ContractRef, Args, R, Abi>(
735 &mut self,
736 params: &CreateParams<E, ContractRef, LimitParamsV2, Args, R, Abi>,
737 ) -> Result<
738 ink_primitives::ConstructorResult<
739 <R as ConstructorReturnType<ContractRef, Abi>>::Output,
740 >,
741 >
742 where
743 E: Environment,
744 ContractRef: FromAddr + crate::ContractReverseReference,
745 <ContractRef as crate::ContractReverseReference>::Type:
746 crate::reflect::ContractConstructorDecoder,
747 Args: EncodeArgsWith<Abi>,
748 R: ConstructorReturnType<ContractRef, Abi>,
749 {
750 let endowment = params.endowment();
751 let salt_bytes = params.salt_bytes();
752 let code_hash = params.code_hash();
753
754 let input = params.exec_input().encode();
755
756 let account_id_vec = {
758 let mut account_input = Vec::<u8>::new();
759 account_input.extend(&b"contract_addr".to_vec());
760 scale::Encode::encode_to(
761 &self.engine.exec_context.caller.as_bytes(),
762 &mut account_input,
763 );
764 account_input.extend(&code_hash.0);
765 account_input.extend(&input);
766 if let Some(salt) = salt_bytes {
767 account_input.extend(salt);
768 }
769 let mut account_id = [0_u8; 32];
770 ink_engine::hashing::blake2b_256(&account_input[..], &mut account_id);
771 account_id.to_vec()
772 };
773 let contract_addr = AccountIdMapper::to_address(&account_id_vec[..]);
775
776 let old_callee = self.engine.get_callee();
777 self.engine.set_callee(contract_addr);
778
779 let dispatch = <
780 <
781 <
782 ContractRef
783 as crate::ContractReverseReference
784 >::Type
785 as crate::reflect::ContractConstructorDecoder
786 >::Type
787 as DecodeDispatch
788 >::decode_dispatch(&mut &input[..])
789 .unwrap_or_else(|e| panic!("Failed to decode constructor call: {e:?}"));
790 crate::reflect::ExecuteDispatchable::execute_dispatchable(dispatch)
791 .unwrap_or_else(|e| panic!("Constructor call failed: {e:?}"));
792
793 self.engine
794 .database
795 .set_code_hash(&self.engine.get_callee(), code_hash);
796 self.engine.set_contract(callee());
797 self.engine
798 .database
799 .set_balance(&callee(), *endowment);
801
802 self.engine.set_callee(old_callee);
804
805 Ok(Ok(R::ok(<ContractRef as FromAddr>::from_addr(
806 contract_addr,
807 ))))
808 }
809
810 #[cfg(feature = "unstable-hostfn")]
811 fn terminate_contract(&mut self, beneficiary: Address) -> ! {
812 self.engine.terminate(beneficiary)
813 }
814
815 fn transfer<E>(&mut self, destination: Address, value: U256) -> Result<()>
816 where
817 E: Environment,
818 {
819 let enc_value = &scale::Encode::encode(&value)[..];
820 self.engine
821 .transfer(destination, enc_value)
822 .map_err(Into::into)
823 }
824
825 fn weight_to_fee(&mut self, gas: u64) -> U256 {
826 let mut output: [u8; BUFFER_SIZE] = [0; BUFFER_SIZE];
827 self.engine.weight_to_fee(gas, &mut &mut output[..]);
828 scale::Decode::decode(&mut &output[..]).unwrap_or_else(|error| {
829 panic!("could not read `weight_to_fee` property: {error:?}")
830 })
831 }
832
833 fn is_contract(&mut self, account: &Address) -> bool {
834 self.engine.is_contract(account)
835 }
836
837 fn caller_is_origin(&mut self) -> bool {
838 unimplemented!("off-chain environment does not support cross-contract calls")
839 }
840
841 fn caller_is_root(&mut self) -> bool {
842 unimplemented!("off-chain environment does not support `caller_is_root`")
843 }
844
845 fn code_hash(&mut self, addr: &Address) -> core::result::Result<H256, CodeHashErr> {
846 let code_hash = self.engine.database.get_code_hash(addr);
847 if let Some(code_hash) = code_hash {
848 let code_hash = H256::decode(&mut &code_hash[..]).unwrap();
850 Ok(code_hash)
851 } else {
852 Err(CodeHashErr::AddressNotFound)
853 }
854 }
855
856 fn own_code_hash(&mut self) -> H256 {
857 let callee = &self.engine.get_callee();
858 self.engine
859 .database
860 .get_code_hash(callee)
861 .expect("own code hash not found")
862 }
863
864 #[cfg(feature = "xcm")]
865 fn xcm_weigh<Call>(&mut self, _msg: &xcm::VersionedXcm<Call>) -> Result<Weight> {
866 unimplemented!("off-chain environment does not support `xcm_execute`")
867 }
868
869 #[cfg(feature = "xcm")]
870 fn xcm_execute<Call>(
871 &mut self,
872 _msg: &xcm::VersionedXcm<Call>,
873 _weight: Weight,
874 ) -> Result<()> {
875 unimplemented!("off-chain environment does not support `xcm_execute`")
876 }
877
878 #[cfg(feature = "xcm")]
879 fn xcm_send<Call>(
880 &mut self,
881 _dest: &xcm::VersionedLocation,
882 _msg: &xcm::VersionedXcm<Call>,
883 ) -> Result<()> {
884 unimplemented!("off-chain environment does not support `xcm_send`")
885 }
886}