1use crate::address::Addressable;
4use crate::gas_report::GasReport;
5use crate::{
6 call_result::CallResult, entry_point_callback::EntryPointsCaller, CallDef, ContractCallResult,
7 ContractEnv, EventError, VmError
8};
9#[cfg(not(target_arch = "wasm32"))]
10use crate::{consts, contract::OdraContract, contract_def::HasIdent};
11use crate::{prelude::*, utils};
12use casper_event_standard::EventInstance;
13use casper_types::{
14 bytesrepr::{Bytes, FromBytes, ToBytes},
15 CLTyped, PublicKey, RuntimeArgs, U512
16};
17
18pub trait HostRef {
20 fn new(address: Address, env: HostEnv) -> Self;
22 fn with_tokens(&self, tokens: U512) -> Self;
27 fn address(&self) -> &Address;
29 fn env(&self) -> &HostEnv;
31 fn get_event<T>(&self, index: i32) -> Result<T, EventError>
35 where
36 T: FromBytes + EventInstance + 'static;
37 fn last_call(&self) -> ContractCallResult;
39}
40
41impl<T: HostRef> Addressable for T {
42 fn address(&self) -> &Address {
43 HostRef::address(self)
44 }
45}
46
47pub trait HostRefLoader<T: HostRef> {
51 fn load(env: &HostEnv, address: Address) -> T;
53}
54
55pub trait EntryPointsCallerProvider {
57 fn entry_points_caller(env: &HostEnv) -> EntryPointsCaller;
59}
60
61#[cfg(not(target_arch = "wasm32"))]
68pub trait Deployer<R: OdraContract>: Sized {
69 fn deploy(env: &HostEnv, init_args: R::InitArgs) -> R::HostRef;
78
79 fn try_deploy(env: &HostEnv, init_args: R::InitArgs) -> OdraResult<R::HostRef>;
83
84 fn deploy_with_cfg<T: OdraConfig>(env: &HostEnv, init_args: R::InitArgs, cfg: T) -> R::HostRef;
88
89 fn try_deploy_with_cfg<T: OdraConfig>(
93 env: &HostEnv,
94 init_args: R::InitArgs,
95 cfg: T
96 ) -> OdraResult<R::HostRef>;
97}
98
99pub trait InitArgs: Into<RuntimeArgs> {}
101
102pub struct NoArgs;
108
109impl InitArgs for NoArgs {}
110
111impl From<NoArgs> for RuntimeArgs {
112 fn from(_: NoArgs) -> Self {
113 RuntimeArgs::new()
114 }
115}
116
117pub trait OdraConfig {
122 fn package_hash(&self) -> String;
126 fn is_upgradable(&self) -> bool;
130 fn allow_key_override(&self) -> bool;
132}
133
134#[cfg(not(target_arch = "wasm32"))]
135struct DefaultOdraConfig {
137 name: String
138}
139
140#[cfg(not(target_arch = "wasm32"))]
141impl OdraConfig for DefaultOdraConfig {
142 fn package_hash(&self) -> String {
143 self.name.clone()
144 }
145
146 fn is_upgradable(&self) -> bool {
147 false
148 }
149
150 fn allow_key_override(&self) -> bool {
151 true
152 }
153}
154
155#[cfg(not(target_arch = "wasm32"))]
156impl<R: OdraContract> Deployer<R> for R {
157 fn deploy(
158 env: &HostEnv,
159 init_args: <R as OdraContract>::InitArgs
160 ) -> <R as OdraContract>::HostRef {
161 let contract_ident = R::HostRef::ident();
162 match Self::try_deploy(env, init_args) {
163 Ok(contract) => contract,
164 Err(OdraError::ExecutionError(ExecutionError::MissingArg)) => {
165 core::panic!("Invalid init args for contract {}.", contract_ident)
166 }
167 Err(e) => core::panic!("Contract init failed {:?}", e)
168 }
169 }
170
171 fn try_deploy(
172 env: &HostEnv,
173 init_args: <R as OdraContract>::InitArgs
174 ) -> OdraResult<<R as OdraContract>::HostRef> {
175 Self::try_deploy_with_cfg(
176 env,
177 init_args,
178 DefaultOdraConfig {
179 name: R::HostRef::ident()
180 }
181 )
182 }
183
184 fn deploy_with_cfg<T: OdraConfig>(
185 env: &HostEnv,
186 init_args: <R as OdraContract>::InitArgs,
187 cfg: T
188 ) -> <R as OdraContract>::HostRef {
189 let contract_ident = R::HostRef::ident();
190 match Self::try_deploy_with_cfg(env, init_args, cfg) {
191 Ok(contract) => contract,
192 Err(OdraError::ExecutionError(ExecutionError::MissingArg)) => {
193 core::panic!("Invalid init args for contract {}.", contract_ident)
194 }
195 Err(e) => core::panic!("Contract init failed {:?}", e)
196 }
197 }
198
199 fn try_deploy_with_cfg<T: OdraConfig>(
200 env: &HostEnv,
201 init_args: <R as OdraContract>::InitArgs,
202 cfg: T
203 ) -> OdraResult<<R as OdraContract>::HostRef> {
204 let contract_ident = R::HostRef::ident();
205 let caller = R::HostRef::entry_points_caller(env);
206
207 let mut init_args = init_args.into();
208 init_args.insert(consts::IS_UPGRADABLE_ARG, cfg.is_upgradable())?;
209 init_args.insert(consts::ALLOW_KEY_OVERRIDE_ARG, cfg.allow_key_override())?;
210 init_args.insert(
211 consts::PACKAGE_HASH_KEY_NAME_ARG,
212 format!("{}_package_hash", cfg.package_hash())
213 )?;
214
215 let address = env.new_contract(&contract_ident, init_args, caller)?;
216 Ok(R::HostRef::new(address, env.clone()))
217 }
218}
219
220#[cfg(not(target_arch = "wasm32"))]
221impl<T: OdraContract> HostRefLoader<T::HostRef> for T {
222 fn load(env: &HostEnv, address: Address) -> T::HostRef {
223 let caller = T::HostRef::entry_points_caller(env);
224 let contract_name = T::HostRef::ident();
225 env.register_contract(address, contract_name, caller);
226 T::HostRef::new(address, env.clone())
227 }
228}
229
230#[cfg_attr(test, mockall::automock)]
232pub trait HostContext {
233 fn set_caller(&self, caller: Address);
235
236 fn set_gas(&self, gas: u64);
238
239 fn caller(&self) -> Address;
241
242 fn get_account(&self, index: usize) -> Address;
244
245 fn get_validator(&self, index: usize) -> PublicKey;
247
248 fn remove_validator(&self, index: usize);
250
251 fn balance_of(&self, address: &Address) -> U512;
253
254 fn advance_block_time(&self, time_diff: u64);
256
257 fn advance_with_auctions(&self, time_diff: u64);
259
260 fn auction_delay(&self) -> u64;
262
263 fn unbonding_delay(&self) -> u64;
265
266 fn delegated_amount(&self, delegator: Address, validator: PublicKey) -> U512;
268
269 fn block_time(&self) -> u64;
271
272 fn get_event(&self, contract_address: &Address, index: u32) -> Result<Bytes, EventError>;
274
275 fn get_native_event(&self, contract_address: &Address, index: u32)
277 -> Result<Bytes, EventError>;
278
279 fn get_events_count(&self, contract_address: &Address) -> Result<u32, EventError>;
281
282 fn get_native_events_count(&self, contract_address: &Address) -> Result<u32, EventError>;
284
285 fn call_contract(
287 &self,
288 address: &Address,
289 call_def: CallDef,
290 use_proxy: bool
291 ) -> OdraResult<Bytes>;
292
293 fn new_contract(
295 &self,
296 name: &str,
297 init_args: RuntimeArgs,
298 entry_points_caller: EntryPointsCaller
299 ) -> OdraResult<Address>;
300
301 fn register_contract(
303 &self,
304 address: Address,
305 contract_name: String,
306 entry_points_caller: EntryPointsCaller
307 );
308
309 fn contract_env(&self) -> ContractEnv;
311
312 fn gas_report(&self) -> GasReport;
314
315 fn last_call_gas_cost(&self) -> u64;
317
318 fn sign_message(&self, message: &Bytes, address: &Address) -> Bytes;
320
321 fn public_key(&self, address: &Address) -> PublicKey;
323
324 fn transfer(&self, to: Address, amount: U512) -> OdraResult<()>;
326}
327
328#[derive(Clone)]
333pub struct HostEnv {
334 backend: Rc<RefCell<dyn HostContext>>,
335 last_call_result: Rc<RefCell<Option<CallResult>>>,
336 deployed_contracts: Rc<RefCell<Vec<Address>>>,
337 events_count: Rc<RefCell<BTreeMap<Address, u32>>>, native_events_count: Rc<RefCell<BTreeMap<Address, u32>>>, events_initialized: Rc<RefCell<BTreeMap<Address, bool>>>
340}
341
342impl HostEnv {
343 pub fn new(backend: Rc<RefCell<dyn HostContext>>) -> HostEnv {
345 HostEnv {
346 backend,
347 last_call_result: RefCell::new(None).into(),
348 deployed_contracts: RefCell::new(vec![]).into(),
349 events_count: Rc::new(RefCell::new(Default::default())),
350 native_events_count: Rc::new(RefCell::new(Default::default())),
351 events_initialized: Rc::new(RefCell::new(Default::default()))
352 }
353 }
354
355 pub fn get_account(&self, index: usize) -> Address {
357 let backend = self.backend.borrow();
358 backend.get_account(index)
359 }
360
361 pub fn get_validator(&self, index: usize) -> PublicKey {
363 let backend = self.backend.borrow();
364 backend.get_validator(index)
365 }
366
367 pub fn set_caller(&self, address: Address) {
369 if address.is_contract() {
370 panic!("Caller cannot be a contract: {:?}", address)
371 }
372 let backend = self.backend.borrow();
373 backend.set_caller(address)
374 }
375
376 pub fn advance_block_time(&self, time_diff: u64) {
378 let backend = self.backend.borrow();
379 backend.advance_block_time(time_diff)
380 }
381
382 pub fn advance_with_auctions(&self, time_diff: u64) {
384 let backend = self.backend.borrow();
385 backend.advance_with_auctions(time_diff);
386 }
387
388 pub fn auction_delay(&self) -> u64 {
390 let backend = self.backend.borrow();
391 backend.auction_delay()
392 }
393
394 pub fn unbonding_delay(&self) -> u64 {
396 let backend = self.backend.borrow();
397 backend.unbonding_delay()
398 }
399
400 pub fn delegated_amount(&self, delegator: Address, validator: PublicKey) -> U512 {
402 let backend = self.backend.borrow();
403 backend.delegated_amount(delegator, validator)
404 }
405
406 pub fn remove_validator(&self, index: usize) {
408 let backend = self.backend.borrow();
409 backend.remove_validator(index);
410 }
411
412 pub fn block_time(&self) -> u64 {
414 let backend = self.backend.borrow();
415 backend.block_time()
416 }
417
418 pub fn block_time_millis(&self) -> u64 {
420 let backend = self.backend.borrow();
421 backend.block_time()
422 }
423
424 pub fn block_time_secs(&self) -> u64 {
426 let backend = self.backend.borrow();
427 backend.block_time().checked_div(1000).unwrap()
428 }
429
430 pub fn new_contract(
432 &self,
433 name: &str,
434 init_args: RuntimeArgs,
435 entry_points_caller: EntryPointsCaller
436 ) -> OdraResult<Address> {
437 let backend = self.backend.borrow();
438 let deployed_contract = backend.new_contract(name, init_args, entry_points_caller)?;
439
440 self.deployed_contracts.borrow_mut().push(deployed_contract);
441 self.events_count.borrow_mut().insert(deployed_contract, 0);
442 self.native_events_count
443 .borrow_mut()
444 .insert(deployed_contract, 0);
445 self.events_initialized
446 .borrow_mut()
447 .insert(deployed_contract, true);
448 Ok(deployed_contract)
449 }
450
451 pub fn register_contract(
454 &self,
455 address: Address,
456 contract_name: String,
457 entry_points_caller: EntryPointsCaller
458 ) {
459 let backend = self.backend.borrow();
460 backend.register_contract(address, contract_name, entry_points_caller);
461 self.deployed_contracts.borrow_mut().push(address);
462 }
463
464 pub fn call_contract<T: FromBytes + CLTyped>(
466 &self,
467 address: Address,
468 call_def: CallDef
469 ) -> OdraResult<T> {
470 let use_proxy = T::cl_type() != <()>::cl_type() || !call_def.amount().is_zero();
471 let call_result = self.raw_call_contract(address, call_def, use_proxy);
472 call_result.map(|bytes| {
473 T::from_bytes(&bytes)
474 .map(|(obj, _)| obj)
475 .map_err(|_| OdraError::VmError(VmError::Deserialization))
476 })?
477 }
478
479 pub fn raw_call_contract(
482 &self,
483 address: Address,
484 call_def: CallDef,
485 use_proxy: bool
486 ) -> OdraResult<Bytes> {
487 let backend = self.backend.borrow();
488 let call_result = backend.call_contract(&address, call_def, use_proxy);
489
490 let mut events_map: BTreeMap<Address, Vec<Bytes>> = BTreeMap::new();
491 let mut native_events_map: BTreeMap<Address, Vec<Bytes>> = BTreeMap::new();
492
493 self.deployed_contracts
495 .borrow()
496 .iter()
497 .for_each(|contract_address| {
498 let events = self.last_events(contract_address);
499 let native_events = self.last_native_events(contract_address);
500 events_map.insert(*contract_address, events);
501 native_events_map.insert(*contract_address, native_events);
502 });
503
504 let last_call_gas_cost = backend.last_call_gas_cost();
505
506 self.last_call_result.replace(Some(CallResult::new(
507 address,
508 backend.caller(),
509 last_call_gas_cost,
510 call_result.clone(),
511 events_map,
512 native_events_map
513 )));
514
515 call_result
516 }
517
518 pub fn contract_env(&self) -> ContractEnv {
520 self.backend.borrow().contract_env()
521 }
522
523 pub fn gas_report(&self) -> GasReport {
525 self.backend.borrow().gas_report().clone()
526 }
527
528 pub fn balance_of<T: Addressable>(&self, address: &T) -> U512 {
530 let backend = self.backend.borrow();
531 backend.balance_of(address.address())
532 }
533
534 pub fn get_event<T: FromBytes + EventInstance, R: Addressable>(
541 &self,
542 contract_address: &R,
543 index: i32
544 ) -> Result<T, EventError> {
545 let contract_address = contract_address.address();
546 let backend = self.backend.borrow();
547 let events_count = self.events_count(contract_address);
548 let event_absolute_position = crate::utils::event_absolute_position(events_count, index)
549 .ok_or(EventError::IndexOutOfBounds)?;
550
551 let bytes = backend.get_event(contract_address, event_absolute_position)?;
552 T::from_bytes(&bytes)
553 .map_err(|_| EventError::Parsing)
554 .map(|r| r.0)
555 }
556
557 pub fn get_native_event<T: FromBytes + EventInstance, R: Addressable>(
564 &self,
565 contract_address: &R,
566 index: i32
567 ) -> Result<T, EventError> {
568 let contract_address = contract_address.address();
569 let backend = self.backend.borrow();
570 let events_count = self.native_events_count(contract_address);
571 let event_absolute_position = crate::utils::event_absolute_position(events_count, index)
572 .ok_or(EventError::IndexOutOfBounds)?;
573
574 let bytes = backend.get_native_event(contract_address, event_absolute_position)?;
575 T::from_bytes(&bytes)
576 .map_err(|_| EventError::Parsing)
577 .map(|r| r.0)
578 }
579
580 pub fn get_event_bytes<T: Addressable>(
582 &self,
583 contract_address: &T,
584 index: u32
585 ) -> Result<Bytes, EventError> {
586 let backend = self.backend.borrow();
587 backend.get_event(contract_address.address(), index)
588 }
589
590 pub fn get_native_event_bytes<T: Addressable>(
592 &self,
593 contract_address: &T,
594 index: u32
595 ) -> Result<Bytes, EventError> {
596 let backend = self.backend.borrow();
597 backend.get_native_event(contract_address.address(), index)
598 }
599
600 pub fn event_names<T: Addressable>(&self, contract_address: &T) -> Vec<String> {
602 let events_count = self.events_count(contract_address);
603
604 let backend = self.backend.borrow();
605 (0..events_count)
606 .map(|event_id| {
607 backend
608 .get_event(contract_address.address(), event_id)
609 .and_then(|bytes| utils::extract_event_name(&bytes))
610 .unwrap_or_else(|e| panic!("Couldn't extract event name: {:?}", e))
611 })
612 .collect()
613 }
614
615 pub fn events<T: Addressable>(&self, contract_address: &T) -> Vec<Bytes> {
617 let backend = self.backend.borrow();
618 let contract_address = contract_address.address();
619 let events_count = backend
620 .get_events_count(contract_address)
621 .unwrap_or_default();
622 (0..events_count)
623 .map(|event_id| {
624 backend
625 .get_event(contract_address, event_id)
626 .unwrap_or_else(|e| {
627 panic!(
628 "Couldn't get event at address {:?} with id {}: {:?}",
629 &contract_address, event_id, e
630 )
631 })
632 })
633 .collect()
634 }
635
636 pub fn events_count<T: Addressable>(&self, address: &T) -> u32 {
638 let backend = self.backend.borrow();
639 backend
640 .get_events_count(address.address())
641 .unwrap_or_default()
642 }
643
644 pub fn native_events_count<T: Addressable>(&self, address: &T) -> u32 {
646 let backend = self.backend.borrow();
647 backend
648 .get_native_events_count(address.address())
649 .unwrap_or_default()
650 }
651
652 pub fn emitted_event<T: ToBytes + EventInstance, R: Addressable>(
654 &self,
655 contract_address: &R,
656 event: &T
657 ) -> bool {
658 let contract_address = contract_address.address();
659 let events_count = self.events_count(contract_address);
660
661 let event_bytes = Bytes::from(
662 event
663 .to_bytes()
664 .unwrap_or_else(|_| panic!("Couldn't serialize event"))
665 );
666
667 (0..events_count)
668 .map(|event_id| {
669 self.get_event_bytes(contract_address, event_id)
670 .unwrap_or_else(|e| {
671 panic!(
672 "Couldn't get event at address {:?} with id {}: {:?}",
673 &contract_address, event_id, e
674 )
675 })
676 })
677 .any(|bytes| bytes == event_bytes)
678 }
679
680 pub fn emitted_native_event<T: ToBytes + EventInstance, R: Addressable>(
682 &self,
683 contract_address: &R,
684 event: &T
685 ) -> bool {
686 let contract_address = contract_address.address();
687 let events_count = self.native_events_count(contract_address);
688 if events_count > 0 {
689 let event_bytes = Bytes::from(
690 event
691 .to_bytes()
692 .unwrap_or_else(|_| panic!("Couldn't serialize event"))
693 );
694 (0..events_count)
695 .map(|event_id| {
696 self.get_native_event_bytes(contract_address, event_id)
697 .unwrap_or_else(|e| {
698 panic!(
699 "Couldn't get event at address {:?} with id {}: {:?}",
700 &contract_address, event_id, e
701 )
702 })
703 })
704 .any(|bytes| bytes == event_bytes)
705 } else {
706 false
707 }
708 }
709
710 pub fn emitted<T: AsRef<str>, R: Addressable>(
712 &self,
713 contract_address: &R,
714 event_name: T
715 ) -> bool {
716 let events_count = self.events_count(contract_address);
717
718 (0..events_count)
719 .map(|event_id| {
720 self.get_event_bytes(contract_address, event_id)
721 .unwrap_or_else(|e| {
722 panic!(
723 "Couldn't get event at address {:?} with id {}: {:?}",
724 contract_address.address(),
725 event_id,
726 e
727 )
728 })
729 })
730 .any(|bytes| {
731 utils::extract_event_name(&bytes)
732 .unwrap_or_else(|e| panic!("Couldn't extract event name: {:?}", e))
733 .as_str()
734 == event_name.as_ref()
735 })
736 }
737 pub fn emitted_native<T: AsRef<str>, R: Addressable>(
739 &self,
740 contract_address: &R,
741 event_name: T
742 ) -> bool {
743 let events_count = self.native_events_count(contract_address);
744
745 (0..events_count)
746 .map(|event_id| {
747 self.get_native_event_bytes(contract_address, event_id)
748 .unwrap_or_else(|e| {
749 panic!(
750 "Couldn't get event at address {:?} with id {}: {:?}",
751 contract_address.address(),
752 event_id,
753 e
754 )
755 })
756 })
757 .any(|bytes| {
758 utils::extract_event_name(&bytes)
759 .unwrap_or_else(|e| panic!("Couldn't extract event name: {:?}", e))
760 .as_str()
761 == event_name.as_ref()
762 })
763 }
764
765 pub fn last_call_result(&self, contract_address: Address) -> ContractCallResult {
767 self.last_call_result
768 .borrow()
769 .clone()
770 .unwrap()
771 .contract_last_call(contract_address)
772 }
773
774 pub fn sign_message(&self, message: &Bytes, address: &Address) -> Bytes {
776 let backend = self.backend.borrow();
777 backend.sign_message(message, address)
778 }
779
780 pub fn public_key(&self, address: &Address) -> PublicKey {
782 let backend = self.backend.borrow();
783 backend.public_key(address)
784 }
785
786 pub fn caller(&self) -> Address {
788 let backend = self.backend.borrow();
789 backend.caller()
790 }
791
792 pub fn set_gas(&self, gas: u64) {
794 let backend = self.backend.borrow();
795 backend.set_gas(gas)
796 }
797
798 pub fn transfer(&self, to: Address, amount: U512) -> OdraResult<()> {
800 if to.is_contract() {
801 return Err(OdraError::ExecutionError(
802 ExecutionError::TransferToContract
803 ));
804 }
805 let backend = self.backend.borrow();
806 backend.transfer(to, amount)
807 }
808
809 fn last_events(&self, contract_address: &Address) -> Vec<Bytes> {
810 let events_initialized = self
811 .events_initialized
812 .borrow()
813 .get(contract_address)
814 .copied()
815 .unwrap_or(false);
816 if !events_initialized {
817 self.events_count
818 .borrow_mut()
819 .insert(*contract_address, self.events_count(contract_address));
820 self.native_events_count.borrow_mut().insert(
821 *contract_address,
822 self.native_events_count(contract_address)
823 );
824 self.events_initialized
825 .borrow_mut()
826 .insert(*contract_address, true);
827 }
828
829 let mut old_count_binding = self.events_count.borrow_mut();
830 let old_count = *old_count_binding
831 .get(contract_address)
832 .expect("Contract address not found in events count");
833 let new_count = self.events_count(contract_address);
834 let mut events = vec![];
835 for count in old_count..new_count {
836 let event = self.get_event_bytes(contract_address, count).unwrap();
837 events.push(event);
838 }
839
840 old_count_binding.insert(*contract_address, new_count);
841 events
842 }
843
844 fn last_native_events(&self, contract_address: &Address) -> Vec<Bytes> {
845 let mut old_count_binding = self.native_events_count.borrow_mut();
846 let old_count = *old_count_binding.get(contract_address).unwrap();
847 let new_count = self.native_events_count(contract_address);
848 let mut events = vec![];
849 for count in old_count..new_count {
850 let event = self
851 .get_native_event_bytes(contract_address, count)
852 .unwrap();
853 events.push(event);
854 }
855
856 old_count_binding.insert(*contract_address, new_count);
857 events
858 }
859}
860
861#[cfg(test)]
862mod test {
863 use core::fmt::Debug;
864
865 use super::*;
866 use casper_event_standard::Event;
867 use casper_types::account::AccountHash;
868 use casper_types::contracts::ContractPackageHash;
869 use mockall::{mock, predicate};
870 use std::sync::Mutex;
871
872 static IDENT_MTX: Mutex<()> = Mutex::new(());
873 static EPC_MTX: Mutex<()> = Mutex::new(());
874
875 #[derive(Debug, Event, PartialEq)]
876 struct TestEv {}
877
878 mock! {
879 TestRef {}
880 impl HasIdent for TestRef {
881 fn ident() -> String;
882 }
883 impl EntryPointsCallerProvider for TestRef {
884 fn entry_points_caller(env: &HostEnv) -> EntryPointsCaller;
885 }
886 impl HostRef for TestRef {
887 fn new(address: Address, env: HostEnv) -> Self;
888 fn with_tokens(&self, tokens: U512) -> Self;
889 fn address(&self) -> &Address;
890 fn env(&self) -> &HostEnv;
891 fn get_event<T>(&self, index: i32) -> Result<T, EventError> where T: FromBytes + EventInstance + 'static;
892 fn last_call(&self) -> ContractCallResult;
893 }
894 }
895
896 impl crate::ContractRef for MockTestRef {
897 fn new(_env: Rc<ContractEnv>, _address: Address) -> Self {
898 unimplemented!()
899 }
900 fn address(&self) -> &Address {
901 unimplemented!()
902 }
903
904 fn with_tokens(&self, _tokens: U512) -> Self {
905 unimplemented!()
906 }
907 }
908
909 impl OdraContract for MockTestRef {
910 type HostRef = MockTestRef;
911
912 type ContractRef = MockTestRef;
913
914 type InitArgs = NoArgs;
915 }
916
917 mock! {
918 Ev {}
919 impl Into<RuntimeArgs> for Ev {
920 fn into(self) -> RuntimeArgs;
921 }
922 }
923
924 #[test]
925 fn test_deploy_with_default_args() {
926 let _i = IDENT_MTX.lock();
931 let _e = EPC_MTX.lock();
932
933 let indent_ctx = MockTestRef::ident_context();
935 indent_ctx.expect().returning(|| "TestRef".to_string());
936
937 let epc_ctx = MockTestRef::entry_points_caller_context();
938 epc_ctx
939 .expect()
940 .returning(|h| EntryPointsCaller::new(h.clone(), vec![], |_, _| Ok(Bytes::default())));
941
942 let instance_ctx = MockTestRef::new_context();
944 instance_ctx
945 .expect()
946 .times(1)
947 .returning(|_, _| MockTestRef::default());
948
949 let mut ctx = MockHostContext::new();
950 ctx.expect_new_contract()
951 .returning(|_, _, _| Ok(Address::Account(AccountHash::new([0; 32]))));
952 let env = HostEnv::new(Rc::new(RefCell::new(ctx)));
953 MockTestRef::deploy(&env, NoArgs);
954 }
955
956 #[test]
957 fn test_load_ref() {
958 let _e = EPC_MTX.lock();
963 let _i = IDENT_MTX.lock();
964
965 let epc_ctx = MockTestRef::entry_points_caller_context();
967 epc_ctx
968 .expect()
969 .returning(|h| EntryPointsCaller::new(h.clone(), vec![], |_, _| Ok(Bytes::default())));
970 let indent_ctx = MockTestRef::ident_context();
971 indent_ctx.expect().returning(|| "TestRef".to_string());
972
973 let mut ctx = MockHostContext::new();
974 ctx.expect_register_contract().returning(|_, _, _| ());
975 ctx.expect_get_events_count().returning(|_| Ok(0));
976 ctx.expect_get_native_events_count().returning(|_| Ok(0));
977
978 let instance_ctx = MockTestRef::new_context();
980 instance_ctx
981 .expect()
982 .times(1)
983 .returning(|_, _| MockTestRef::default());
984
985 let env = HostEnv::new(Rc::new(RefCell::new(ctx)));
986 let address = Address::Account(AccountHash::new([0; 32]));
987 MockTestRef::load(&env, address);
988 }
989
990 #[test]
991 fn test_host_env() {
992 let mut ctx = MockHostContext::new();
993 ctx.expect_new_contract()
994 .returning(|_, _, _| Ok(Address::Account(AccountHash::new([0; 32]))));
995 ctx.expect_caller()
996 .returning(|| Address::Account(AccountHash::new([2; 32])))
997 .times(1);
998 ctx.expect_gas_report().returning(GasReport::new).times(1);
999 ctx.expect_set_gas().returning(|_| ()).times(1);
1000
1001 let env = HostEnv::new(Rc::new(RefCell::new(ctx)));
1002
1003 assert_eq!(env.caller(), Address::Account(AccountHash::new([2; 32])));
1004 env.gas_report();
1006 env.set_gas(1_000u64)
1007 }
1008
1009 #[test]
1010 fn test_successful_transfer_to_account() {
1011 let mut ctx = MockHostContext::new();
1013 ctx.expect_transfer().returning(|_, _| Ok(()));
1014 let env = HostEnv::new(Rc::new(RefCell::new(ctx)));
1015
1016 let addr = Address::Account(AccountHash::new([0; 32]));
1017 let result = env.transfer(addr, 100.into());
1019 assert!(result.is_ok());
1021 }
1022
1023 #[test]
1024 fn test_failing_transfer_to_account() {
1025 let mut ctx = MockHostContext::new();
1027 ctx.expect_transfer()
1028 .returning(|_, _| Err(OdraError::ExecutionError(ExecutionError::UnwrapError)));
1029 let env = HostEnv::new(Rc::new(RefCell::new(ctx)));
1030
1031 let addr = Address::Account(AccountHash::new([0; 32]));
1032 let result = env.transfer(addr, 100.into());
1034 assert_eq!(
1036 result.err(),
1037 Some(OdraError::ExecutionError(ExecutionError::UnwrapError))
1038 );
1039 }
1040
1041 #[test]
1042 fn test_transfer_to_contract() {
1043 let mut ctx = MockHostContext::new();
1045 ctx.expect_transfer().returning(|_, _| Ok(()));
1046 let env = HostEnv::new(Rc::new(RefCell::new(ctx)));
1047
1048 let addr = Address::Contract(ContractPackageHash::new([0; 32]));
1049 let result = env.transfer(addr, 100.into());
1051 assert_eq!(
1053 result,
1054 Err(OdraError::ExecutionError(
1055 ExecutionError::TransferToContract
1056 ))
1057 );
1058 }
1059
1060 #[test]
1061 fn test_get_event() {
1062 let addr = Address::Account(AccountHash::new([0; 32]));
1063
1064 let mut ctx = MockHostContext::new();
1065 ctx.expect_get_events_count().returning(|_| Ok(2));
1067 ctx.expect_get_event()
1069 .with(predicate::always(), predicate::eq(0))
1070 .returning(|_, _| Ok(vec![1].into()));
1071 ctx.expect_get_event()
1073 .with(predicate::always(), predicate::eq(1))
1074 .returning(|_, _| Ok(TestEv {}.to_bytes().unwrap().into()));
1075
1076 let env = HostEnv::new(Rc::new(RefCell::new(ctx)));
1077
1078 assert_eq!(env.get_event(&addr, 1), Ok(TestEv {}));
1079 assert_eq!(env.get_event(&addr, -1), Ok(TestEv {}));
1080 assert_eq!(
1081 env.get_event::<TestEv, _>(&addr, 0),
1082 Err(EventError::Parsing)
1083 );
1084 assert_eq!(
1085 env.get_event::<TestEv, _>(&addr, -2),
1086 Err(EventError::Parsing)
1087 );
1088 assert_eq!(
1089 env.get_event::<TestEv, _>(&addr, 2),
1090 Err(EventError::IndexOutOfBounds)
1091 );
1092 assert_eq!(
1093 env.get_event::<TestEv, _>(&addr, -3),
1094 Err(EventError::IndexOutOfBounds)
1095 );
1096 }
1097
1098 #[test]
1099 fn test_events_works() {
1100 let addr = Address::Account(AccountHash::new([0; 32]));
1101
1102 let mut ctx = MockHostContext::new();
1103 ctx.expect_get_events_count().returning(|_| Ok(2));
1105 ctx.expect_get_event()
1107 .with(predicate::always(), predicate::eq(0))
1108 .returning(|_, _| Ok(vec![1].into()));
1109 ctx.expect_get_event()
1111 .with(predicate::always(), predicate::eq(1))
1112 .returning(|_, _| Ok(vec![1, 0, 1].into()));
1113
1114 let env = HostEnv::new(Rc::new(RefCell::new(ctx)));
1115
1116 assert_eq!(
1117 env.events(&addr),
1118 vec![vec![1].into(), vec![1, 0, 1].into()]
1119 );
1120 }
1121
1122 #[test]
1123 #[should_panic(
1124 expected = "Couldn't get event at address Account(AccountHash(0000000000000000000000000000000000000000000000000000000000000000)) with id 0: CouldntExtractEventData"
1125 )]
1126 fn test_events_fails() {
1127 let addr = Address::Account(AccountHash::new([0; 32]));
1128
1129 let mut ctx = MockHostContext::new();
1130 ctx.expect_get_events_count().returning(|_| Ok(2));
1132 ctx.expect_get_event()
1134 .with(predicate::always(), predicate::eq(0))
1135 .returning(|_, _| Err(EventError::CouldntExtractEventData));
1136
1137 let env = HostEnv::new(Rc::new(RefCell::new(ctx)));
1138
1139 env.events(&addr);
1140 }
1141
1142 #[test]
1143 fn test_emitted() {
1144 let addr = Address::Account(AccountHash::new([0; 32]));
1145 let mut ctx = MockHostContext::new();
1146
1147 ctx.expect_get_events_count().returning(|_| Ok(1));
1148 ctx.expect_get_event()
1149 .returning(|_, _| Ok(TestEv {}.to_bytes().unwrap().into()));
1150
1151 let env = HostEnv::new(Rc::new(RefCell::new(ctx)));
1152 assert!(env.emitted(&addr, "TestEv"));
1153 assert!(!env.emitted(&addr, "AnotherEvent"));
1154 }
1155}