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 contract_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::contract_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(env: &HostEnv, init_args: R::InitArgs, cfg: InstallConfig) -> R::HostRef;
88
89 fn try_deploy_with_cfg(
93 env: &HostEnv,
94 init_args: R::InitArgs,
95 cfg: InstallConfig
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
117#[cfg(not(target_arch = "wasm32"))]
122pub struct InstallConfig {
123 pub package_named_key: String,
127 pub is_upgradable: bool,
131 pub allow_key_override: bool
133}
134
135#[cfg(not(target_arch = "wasm32"))]
136impl InstallConfig {
137 fn new<T: HasIdent>(is_upgradable: bool, allow_key_override: bool) -> Self {
138 InstallConfig {
139 package_named_key: T::ident(),
140 is_upgradable,
141 allow_key_override
142 }
143 }
144}
145
146#[cfg(not(target_arch = "wasm32"))]
147impl<R: OdraContract> Deployer<R> for R {
148 fn deploy(
149 env: &HostEnv,
150 init_args: <R as OdraContract>::InitArgs
151 ) -> <R as OdraContract>::HostRef {
152 let contract_ident = R::HostRef::ident();
153 match Self::try_deploy(env, init_args) {
154 Ok(contract) => contract,
155 Err(OdraError::ExecutionError(ExecutionError::MissingArg)) => {
156 core::panic!("Invalid init args for contract {}.", contract_ident)
157 }
158 Err(e) => core::panic!("Contract init failed {:?}", e)
159 }
160 }
161
162 fn try_deploy(
163 env: &HostEnv,
164 init_args: <R as OdraContract>::InitArgs
165 ) -> OdraResult<<R as OdraContract>::HostRef> {
166 Self::try_deploy_with_cfg(
167 env,
168 init_args,
169 InstallConfig::new::<<R as OdraContract>::HostRef>(false, true)
170 )
171 }
172
173 fn deploy_with_cfg(
174 env: &HostEnv,
175 init_args: <R as OdraContract>::InitArgs,
176 cfg: InstallConfig
177 ) -> <R as OdraContract>::HostRef {
178 let contract_ident = R::HostRef::ident();
179 match Self::try_deploy_with_cfg(env, init_args, cfg) {
180 Ok(contract) => contract,
181 Err(OdraError::ExecutionError(ExecutionError::MissingArg)) => {
182 core::panic!("Invalid init args for contract {}.", contract_ident)
183 }
184 Err(e) => core::panic!("Contract init failed {:?}", e)
185 }
186 }
187
188 fn try_deploy_with_cfg(
189 env: &HostEnv,
190 init_args: <R as OdraContract>::InitArgs,
191 cfg: InstallConfig
192 ) -> OdraResult<<R as OdraContract>::HostRef> {
193 let contract_ident = R::HostRef::ident();
194 let caller = R::HostRef::entry_points_caller(env);
195
196 let mut init_args = init_args.into();
197 init_args.insert(consts::IS_UPGRADABLE_ARG, cfg.is_upgradable)?;
198 init_args.insert(consts::ALLOW_KEY_OVERRIDE_ARG, cfg.allow_key_override)?;
199 init_args.insert(
200 consts::PACKAGE_HASH_KEY_NAME_ARG,
201 format!("{}_package_hash", cfg.package_named_key)
202 )?;
203
204 let address = env.new_contract(&contract_ident, init_args, caller)?;
205 Ok(R::HostRef::new(address, env.clone()))
206 }
207}
208
209#[cfg(not(target_arch = "wasm32"))]
210impl<T: OdraContract> HostRefLoader<T::HostRef> for T {
211 fn load(env: &HostEnv, address: Address) -> T::HostRef {
212 let caller = T::HostRef::entry_points_caller(env);
213 let contract_name = T::HostRef::ident();
214 env.register_contract(address, contract_name, caller);
215 T::HostRef::new(address, env.clone())
216 }
217}
218
219#[cfg_attr(test, mockall::automock)]
221pub trait HostContext {
222 fn set_caller(&self, caller: Address);
224
225 fn set_gas(&self, gas: u64);
227
228 fn caller(&self) -> Address;
230
231 fn get_account(&self, index: usize) -> Address;
233
234 fn get_validator(&self, index: usize) -> PublicKey;
236
237 fn remove_validator(&self, index: usize);
239
240 fn balance_of(&self, address: &Address) -> U512;
242
243 fn advance_block_time(&self, time_diff: u64);
245
246 fn advance_with_auctions(&self, time_diff: u64);
248
249 fn auction_delay(&self) -> u64;
251
252 fn unbonding_delay(&self) -> u64;
254
255 fn delegated_amount(&self, delegator: Address, validator: PublicKey) -> U512;
257
258 fn block_time(&self) -> u64;
260
261 fn get_event(&self, contract_address: &Address, index: u32) -> Result<Bytes, EventError>;
263
264 fn get_native_event(&self, contract_address: &Address, index: u32)
266 -> Result<Bytes, EventError>;
267
268 fn get_events_count(&self, contract_address: &Address) -> Result<u32, EventError>;
270
271 fn get_native_events_count(&self, contract_address: &Address) -> Result<u32, EventError>;
273
274 fn call_contract(
276 &self,
277 address: &Address,
278 call_def: CallDef,
279 use_proxy: bool
280 ) -> OdraResult<Bytes>;
281
282 fn new_contract(
284 &self,
285 name: &str,
286 init_args: RuntimeArgs,
287 entry_points_caller: EntryPointsCaller
288 ) -> OdraResult<Address>;
289
290 fn register_contract(
292 &self,
293 address: Address,
294 contract_name: String,
295 entry_points_caller: EntryPointsCaller
296 );
297
298 fn contract_env(&self) -> ContractEnv;
300
301 fn gas_report(&self) -> GasReport;
303
304 fn last_call_gas_cost(&self) -> u64;
306
307 fn sign_message(&self, message: &Bytes, address: &Address) -> Bytes;
309
310 fn public_key(&self, address: &Address) -> PublicKey;
312
313 fn transfer(&self, to: Address, amount: U512) -> OdraResult<()>;
315}
316
317#[derive(Clone)]
322pub struct HostEnv {
323 backend: Rc<RefCell<dyn HostContext>>,
324 last_call_result: Rc<RefCell<Option<CallResult>>>,
325 deployed_contracts: Rc<RefCell<Vec<Address>>>,
326 events_count: Rc<RefCell<BTreeMap<Address, u32>>>, native_events_count: Rc<RefCell<BTreeMap<Address, u32>>>, events_initialized: Rc<RefCell<BTreeMap<Address, bool>>>,
329 captures_events: Rc<RefCell<bool>>
330}
331
332impl HostEnv {
333 pub fn new(backend: Rc<RefCell<dyn HostContext>>) -> HostEnv {
335 HostEnv {
336 backend,
337 last_call_result: RefCell::new(None).into(),
338 deployed_contracts: RefCell::new(vec![]).into(),
339 events_count: Rc::new(RefCell::new(Default::default())),
340 native_events_count: Rc::new(RefCell::new(Default::default())),
341 events_initialized: Rc::new(RefCell::new(Default::default())),
342 captures_events: Rc::new(RefCell::new(true))
343 }
344 }
345
346 pub fn set_captures_events(&self, captures: bool) {
348 *self.captures_events.borrow_mut() = captures;
349 if captures {
350 for contract in self.deployed_contracts.borrow().iter() {
352 self.init_events(contract);
353 }
354 }
355 }
356
357 pub fn get_account(&self, index: usize) -> Address {
359 let backend = self.backend.borrow();
360 backend.get_account(index)
361 }
362
363 pub fn get_validator(&self, index: usize) -> PublicKey {
365 let backend = self.backend.borrow();
366 backend.get_validator(index)
367 }
368
369 pub fn set_caller(&self, address: Address) {
371 if address.is_contract() {
372 panic!("Caller cannot be a contract: {:?}", address)
373 }
374 let backend = self.backend.borrow();
375 backend.set_caller(address)
376 }
377
378 pub fn advance_block_time(&self, time_diff: u64) {
380 let backend = self.backend.borrow();
381 backend.advance_block_time(time_diff)
382 }
383
384 pub fn advance_with_auctions(&self, time_diff: u64) {
386 let backend = self.backend.borrow();
387 backend.advance_with_auctions(time_diff);
388 }
389
390 pub fn auction_delay(&self) -> u64 {
392 let backend = self.backend.borrow();
393 backend.auction_delay()
394 }
395
396 pub fn unbonding_delay(&self) -> u64 {
398 let backend = self.backend.borrow();
399 backend.unbonding_delay()
400 }
401
402 pub fn delegated_amount(&self, delegator: Address, validator: PublicKey) -> U512 {
404 let backend = self.backend.borrow();
405 backend.delegated_amount(delegator, validator)
406 }
407
408 pub fn remove_validator(&self, index: usize) {
410 let backend = self.backend.borrow();
411 backend.remove_validator(index);
412 }
413
414 pub fn block_time(&self) -> u64 {
416 let backend = self.backend.borrow();
417 backend.block_time()
418 }
419
420 pub fn block_time_millis(&self) -> u64 {
422 let backend = self.backend.borrow();
423 backend.block_time()
424 }
425
426 pub fn block_time_secs(&self) -> u64 {
428 let backend = self.backend.borrow();
429 backend.block_time().checked_div(1000).unwrap()
430 }
431
432 pub fn new_contract(
434 &self,
435 name: &str,
436 init_args: RuntimeArgs,
437 entry_points_caller: EntryPointsCaller
438 ) -> OdraResult<Address> {
439 let backend = self.backend.borrow();
440 let deployed_contract = backend.new_contract(name, init_args, entry_points_caller)?;
441
442 self.deployed_contracts.borrow_mut().push(deployed_contract);
443 self.events_count.borrow_mut().insert(deployed_contract, 0);
444 self.native_events_count
445 .borrow_mut()
446 .insert(deployed_contract, 0);
447 self.events_initialized
448 .borrow_mut()
449 .insert(deployed_contract, true);
450 Ok(deployed_contract)
451 }
452
453 pub fn register_contract(
456 &self,
457 address: Address,
458 contract_name: String,
459 entry_points_caller: EntryPointsCaller
460 ) {
461 let backend = self.backend.borrow();
462 backend.register_contract(address, contract_name, entry_points_caller);
463 self.deployed_contracts.borrow_mut().push(address);
464 }
465
466 pub fn call_contract<T: FromBytes + CLTyped>(
468 &self,
469 address: Address,
470 call_def: CallDef
471 ) -> OdraResult<T> {
472 let use_proxy = T::cl_type() != <()>::cl_type() || !call_def.amount().is_zero();
473 let call_result = self.raw_call_contract(address, call_def, use_proxy);
474 call_result.map(|bytes| {
475 T::from_bytes(&bytes)
476 .map(|(obj, _)| obj)
477 .map_err(|_| OdraError::VmError(VmError::Deserialization))
478 })?
479 }
480
481 pub fn raw_call_contract(
484 &self,
485 address: Address,
486 call_def: CallDef,
487 use_proxy: bool
488 ) -> OdraResult<Bytes> {
489 let backend = self.backend.borrow();
490 let call_result = backend.call_contract(&address, call_def, use_proxy);
491
492 let mut events_map: BTreeMap<Address, Vec<Bytes>> = BTreeMap::new();
493 let mut native_events_map: BTreeMap<Address, Vec<Bytes>> = BTreeMap::new();
494
495 let captures_events = *self.captures_events.borrow();
496 if captures_events {
497 self.deployed_contracts
499 .borrow()
500 .iter()
501 .for_each(|contract_address| {
502 let events = self.last_events(contract_address);
503 let native_events = self.last_native_events(contract_address);
504 events_map.insert(*contract_address, events);
505 native_events_map.insert(*contract_address, native_events);
506 });
507 }
508
509 let last_call_gas_cost = backend.last_call_gas_cost();
510
511 self.last_call_result.replace(Some(CallResult::new(
512 address,
513 backend.caller(),
514 last_call_gas_cost,
515 call_result.clone(),
516 events_map,
517 native_events_map
518 )));
519
520 call_result
521 }
522
523 pub fn contract_env(&self) -> ContractEnv {
525 self.backend.borrow().contract_env()
526 }
527
528 pub fn gas_report(&self) -> GasReport {
530 self.backend.borrow().gas_report().clone()
531 }
532
533 pub fn balance_of<T: Addressable>(&self, addr: &T) -> U512 {
535 let backend = self.backend.borrow();
536 backend.balance_of(&addr.address())
537 }
538
539 pub fn get_event<T: FromBytes + EventInstance, R: Addressable>(
546 &self,
547 addr: &R,
548 index: i32
549 ) -> Result<T, EventError> {
550 let contract_address = addr.address();
551 let backend = self.backend.borrow();
552 let events_count = self.events_count(&contract_address);
553 let event_absolute_position = crate::utils::event_absolute_position(events_count, index)
554 .ok_or(EventError::IndexOutOfBounds)?;
555
556 let bytes = backend.get_event(&contract_address, event_absolute_position)?;
557 T::from_bytes(&bytes)
558 .map_err(|_| EventError::Parsing)
559 .map(|r| r.0)
560 }
561
562 pub fn get_native_event<T: FromBytes + EventInstance, R: Addressable>(
569 &self,
570 addr: &R,
571 index: i32
572 ) -> Result<T, EventError> {
573 let contract_address = addr.address();
574 let backend = self.backend.borrow();
575 let events_count = self.native_events_count(&contract_address);
576 let event_absolute_position = crate::utils::event_absolute_position(events_count, index)
577 .ok_or(EventError::IndexOutOfBounds)?;
578
579 let bytes = backend.get_native_event(&contract_address, event_absolute_position)?;
580 T::from_bytes(&bytes)
581 .map_err(|_| EventError::Parsing)
582 .map(|r| r.0)
583 }
584
585 pub fn get_event_bytes<T: Addressable>(
587 &self,
588 addr: &T,
589 index: u32
590 ) -> Result<Bytes, EventError> {
591 let backend = self.backend.borrow();
592 backend.get_event(&addr.address(), index)
593 }
594
595 pub fn get_native_event_bytes<T: Addressable>(
597 &self,
598 addr: &T,
599 index: u32
600 ) -> Result<Bytes, EventError> {
601 let backend = self.backend.borrow();
602 backend.get_native_event(&addr.address(), index)
603 }
604
605 pub fn event_names<T: Addressable>(&self, addr: &T) -> Vec<String> {
607 let events_count = self.events_count(addr);
608
609 let backend = self.backend.borrow();
610 (0..events_count)
611 .map(|event_id| {
612 backend
613 .get_event(&addr.address(), event_id)
614 .and_then(|bytes| utils::extract_event_name(&bytes))
615 .unwrap_or_else(|e| panic!("Couldn't extract event name: {:?}", e))
616 })
617 .collect()
618 }
619
620 pub fn events<T: Addressable>(&self, addr: &T) -> Vec<Bytes> {
622 let backend = self.backend.borrow();
623 let contract_address = addr.address();
624 let events_count = backend
625 .get_events_count(&contract_address)
626 .unwrap_or_default();
627 (0..events_count)
628 .map(|event_id| {
629 backend
630 .get_event(&contract_address, event_id)
631 .unwrap_or_else(|e| {
632 panic!(
633 "Couldn't get event at address {:?} with id {}: {:?}",
634 &contract_address, event_id, e
635 )
636 })
637 })
638 .collect()
639 }
640
641 pub fn events_count<T: Addressable>(&self, addr: &T) -> u32 {
643 let backend = self.backend.borrow();
644 backend
645 .get_events_count(&addr.address())
646 .unwrap_or_default()
647 }
648
649 pub fn native_events_count<T: Addressable>(&self, addr: &T) -> u32 {
651 let backend = self.backend.borrow();
652 backend
653 .get_native_events_count(&addr.address())
654 .unwrap_or_default()
655 }
656
657 pub fn emitted_event<T: ToBytes + EventInstance, R: Addressable>(
659 &self,
660 addr: &R,
661 event: T
662 ) -> bool {
663 let contract_address = addr.address();
664 let events_count = self.events_count(addr);
665
666 let event_bytes = Bytes::from(
667 event
668 .to_bytes()
669 .unwrap_or_else(|_| panic!("Couldn't serialize event"))
670 );
671
672 (0..events_count)
673 .map(|event_id| {
674 self.get_event_bytes(&contract_address, event_id)
675 .unwrap_or_else(|e| {
676 panic!(
677 "Couldn't get event at address {:?} with id {}: {:?}",
678 &contract_address, event_id, e
679 )
680 })
681 })
682 .any(|bytes| bytes == event_bytes)
683 }
684
685 pub fn emitted_native_event<T: ToBytes + EventInstance, R: Addressable>(
687 &self,
688 addr: &R,
689 event: T
690 ) -> bool {
691 let contract_address = addr.address();
692 let events_count = self.native_events_count(addr);
693 if events_count > 0 {
694 let event_bytes = Bytes::from(
695 event
696 .to_bytes()
697 .unwrap_or_else(|_| panic!("Couldn't serialize event"))
698 );
699 (0..events_count)
700 .map(|event_id| {
701 self.get_native_event_bytes(&contract_address, event_id)
702 .unwrap_or_else(|e| {
703 panic!(
704 "Couldn't get event at address {:?} with id {}: {:?}",
705 &contract_address, event_id, e
706 )
707 })
708 })
709 .any(|bytes| bytes == event_bytes)
710 } else {
711 false
712 }
713 }
714
715 pub fn emitted<T: AsRef<str>, R: Addressable>(&self, addr: &R, event_name: T) -> bool {
717 let events_count = self.events_count(addr);
718
719 (0..events_count)
720 .map(|event_id| {
721 self.get_event_bytes(addr, event_id).unwrap_or_else(|e| {
722 panic!(
723 "Couldn't get event at address {:?} with id {}: {:?}",
724 addr.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>(&self, addr: &R, event_name: T) -> bool {
739 let events_count = self.native_events_count(addr);
740
741 (0..events_count)
742 .map(|event_id| {
743 self.get_native_event_bytes(addr, event_id)
744 .unwrap_or_else(|e| {
745 panic!(
746 "Couldn't get event at address {:?} with id {}: {:?}",
747 addr.address(),
748 event_id,
749 e
750 )
751 })
752 })
753 .any(|bytes| {
754 utils::extract_event_name(&bytes)
755 .unwrap_or_else(|e| panic!("Couldn't extract event name: {:?}", e))
756 .as_str()
757 == event_name.as_ref()
758 })
759 }
760
761 pub fn last_call_result(&self, contract_address: Address) -> ContractCallResult {
763 self.last_call_result
764 .borrow()
765 .clone()
766 .unwrap()
767 .contract_last_call(contract_address)
768 }
769
770 pub fn sign_message(&self, message: &Bytes, address: &Address) -> Bytes {
772 let backend = self.backend.borrow();
773 backend.sign_message(message, address)
774 }
775
776 pub fn public_key(&self, address: &Address) -> PublicKey {
778 let backend = self.backend.borrow();
779 backend.public_key(address)
780 }
781
782 pub fn caller(&self) -> Address {
784 let backend = self.backend.borrow();
785 backend.caller()
786 }
787
788 pub fn set_gas(&self, gas: u64) {
790 let backend = self.backend.borrow();
791 backend.set_gas(gas)
792 }
793
794 pub fn transfer(&self, to: Address, amount: U512) -> OdraResult<()> {
796 if to.is_contract() {
797 return Err(OdraError::ExecutionError(
798 ExecutionError::TransferToContract
799 ));
800 }
801 let backend = self.backend.borrow();
802 backend.transfer(to, amount)
803 }
804
805 fn last_events(&self, contract_address: &Address) -> Vec<Bytes> {
806 let mut old_count_binding = self.events_count.borrow_mut();
807 let old_count = *old_count_binding
808 .get(contract_address)
809 .expect("Contract address not found in events count");
810 let new_count = self.events_count(contract_address);
811 let mut events = vec![];
812 for count in old_count..new_count {
813 let event = self.get_event_bytes(contract_address, count).unwrap();
814 events.push(event);
815 }
816
817 old_count_binding.insert(*contract_address, new_count);
818 events
819 }
820
821 fn last_native_events(&self, contract_address: &Address) -> Vec<Bytes> {
822 let mut old_count_binding = self.native_events_count.borrow_mut();
823 let old_count = *old_count_binding.get(contract_address).unwrap();
824 let new_count = self.native_events_count(contract_address);
825 let mut events = vec![];
826 for count in old_count..new_count {
827 let event = self
828 .get_native_event_bytes(contract_address, count)
829 .unwrap();
830 events.push(event);
831 }
832
833 old_count_binding.insert(*contract_address, new_count);
834 events
835 }
836
837 fn init_events(&self, contract_address: &Address) {
838 let events_initialized = self
839 .events_initialized
840 .borrow()
841 .get(contract_address)
842 .copied()
843 .unwrap_or(false);
844 if !events_initialized {
845 self.events_count
846 .borrow_mut()
847 .insert(*contract_address, self.events_count(contract_address));
848 self.native_events_count.borrow_mut().insert(
849 *contract_address,
850 self.native_events_count(contract_address)
851 );
852 self.events_initialized
853 .borrow_mut()
854 .insert(*contract_address, true);
855 }
856 }
857}
858
859#[cfg(test)]
860mod test {
861 use core::fmt::Debug;
862
863 use super::*;
864 use casper_event_standard::Event;
865 use casper_types::account::AccountHash;
866 use casper_types::contracts::ContractPackageHash;
867 use mockall::{mock, predicate};
868 use std::sync::Mutex;
869
870 static IDENT_MTX: Mutex<()> = Mutex::new(());
871 static EPC_MTX: Mutex<()> = Mutex::new(());
872
873 #[derive(Debug, Event, PartialEq)]
874 struct TestEv {}
875
876 mock! {
877 TestRef {}
878 impl HasIdent for TestRef {
879 fn ident() -> String;
880 }
881 impl EntryPointsCallerProvider for TestRef {
882 fn entry_points_caller(env: &HostEnv) -> EntryPointsCaller;
883 }
884 impl HostRef for TestRef {
885 fn new(address: Address, env: HostEnv) -> Self;
886 fn with_tokens(&self, tokens: U512) -> Self;
887 fn contract_address(&self) -> Address;
888 fn env(&self) -> &HostEnv;
889 fn get_event<T>(&self, index: i32) -> Result<T, EventError> where T: FromBytes + EventInstance + 'static;
890 fn last_call(&self) -> ContractCallResult;
891 }
892 }
893
894 impl crate::ContractRef for MockTestRef {
895 fn new(_env: Rc<ContractEnv>, _address: Address) -> Self {
896 unimplemented!()
897 }
898 fn address(&self) -> &Address {
899 unimplemented!()
900 }
901
902 fn with_tokens(&self, _tokens: U512) -> Self {
903 unimplemented!()
904 }
905 }
906
907 impl OdraContract for MockTestRef {
908 type HostRef = MockTestRef;
909
910 type ContractRef = MockTestRef;
911
912 type InitArgs = NoArgs;
913 }
914
915 mock! {
916 Ev {}
917 impl Into<RuntimeArgs> for Ev {
918 fn into(self) -> RuntimeArgs;
919 }
920 }
921
922 #[test]
923 fn test_deploy_with_default_args() {
924 let _i = IDENT_MTX.lock();
929 let _e = EPC_MTX.lock();
930
931 let indent_ctx = MockTestRef::ident_context();
933 indent_ctx.expect().returning(|| "TestRef".to_string());
934
935 let epc_ctx = MockTestRef::entry_points_caller_context();
936 epc_ctx
937 .expect()
938 .returning(|h| EntryPointsCaller::new(h.clone(), vec![], |_, _| Ok(Bytes::default())));
939
940 let instance_ctx = MockTestRef::new_context();
942 instance_ctx
943 .expect()
944 .times(1)
945 .returning(|_, _| MockTestRef::default());
946
947 let mut ctx = MockHostContext::new();
948 ctx.expect_new_contract()
949 .returning(|_, _, _| Ok(Address::Account(AccountHash::new([0; 32]))));
950 let env = HostEnv::new(Rc::new(RefCell::new(ctx)));
951 MockTestRef::deploy(&env, NoArgs);
952 }
953
954 #[test]
955 fn test_load_ref() {
956 let _e = EPC_MTX.lock();
961 let _i = IDENT_MTX.lock();
962
963 let epc_ctx = MockTestRef::entry_points_caller_context();
965 epc_ctx
966 .expect()
967 .returning(|h| EntryPointsCaller::new(h.clone(), vec![], |_, _| Ok(Bytes::default())));
968 let indent_ctx = MockTestRef::ident_context();
969 indent_ctx.expect().returning(|| "TestRef".to_string());
970
971 let mut ctx = MockHostContext::new();
972 ctx.expect_register_contract().returning(|_, _, _| ());
973 ctx.expect_get_events_count().returning(|_| Ok(0));
974 ctx.expect_get_native_events_count().returning(|_| Ok(0));
975
976 let instance_ctx = MockTestRef::new_context();
978 instance_ctx
979 .expect()
980 .times(1)
981 .returning(|_, _| MockTestRef::default());
982
983 let env = HostEnv::new(Rc::new(RefCell::new(ctx)));
984 let address = Address::Account(AccountHash::new([0; 32]));
985 MockTestRef::load(&env, address);
986 }
987
988 #[test]
989 fn test_host_env() {
990 let mut ctx = MockHostContext::new();
991 ctx.expect_new_contract()
992 .returning(|_, _, _| Ok(Address::Account(AccountHash::new([0; 32]))));
993 ctx.expect_caller()
994 .returning(|| Address::Account(AccountHash::new([2; 32])))
995 .times(1);
996 ctx.expect_gas_report().returning(GasReport::new).times(1);
997 ctx.expect_set_gas().returning(|_| ()).times(1);
998
999 let env = HostEnv::new(Rc::new(RefCell::new(ctx)));
1000
1001 assert_eq!(env.caller(), Address::Account(AccountHash::new([2; 32])));
1002 env.gas_report();
1004 env.set_gas(1_000u64)
1005 }
1006
1007 #[test]
1008 fn test_successful_transfer_to_account() {
1009 let mut ctx = MockHostContext::new();
1011 ctx.expect_transfer().returning(|_, _| Ok(()));
1012 let env = HostEnv::new(Rc::new(RefCell::new(ctx)));
1013
1014 let addr = Address::Account(AccountHash::new([0; 32]));
1015 let result = env.transfer(addr, 100.into());
1017 assert!(result.is_ok());
1019 }
1020
1021 #[test]
1022 fn test_failing_transfer_to_account() {
1023 let mut ctx = MockHostContext::new();
1025 ctx.expect_transfer()
1026 .returning(|_, _| Err(OdraError::ExecutionError(ExecutionError::UnwrapError)));
1027 let env = HostEnv::new(Rc::new(RefCell::new(ctx)));
1028
1029 let addr = Address::Account(AccountHash::new([0; 32]));
1030 let result = env.transfer(addr, 100.into());
1032 assert_eq!(
1034 result.err(),
1035 Some(OdraError::ExecutionError(ExecutionError::UnwrapError))
1036 );
1037 }
1038
1039 #[test]
1040 fn test_transfer_to_contract() {
1041 let mut ctx = MockHostContext::new();
1043 ctx.expect_transfer().returning(|_, _| Ok(()));
1044 let env = HostEnv::new(Rc::new(RefCell::new(ctx)));
1045
1046 let addr = Address::Contract(ContractPackageHash::new([0; 32]));
1047 let result = env.transfer(addr, 100.into());
1049 assert_eq!(
1051 result,
1052 Err(OdraError::ExecutionError(
1053 ExecutionError::TransferToContract
1054 ))
1055 );
1056 }
1057
1058 #[test]
1059 fn test_get_event() {
1060 let addr = Address::Account(AccountHash::new([0; 32]));
1061
1062 let mut ctx = MockHostContext::new();
1063 ctx.expect_get_events_count().returning(|_| Ok(2));
1065 ctx.expect_get_event()
1067 .with(predicate::always(), predicate::eq(0))
1068 .returning(|_, _| Ok(vec![1].into()));
1069 ctx.expect_get_event()
1071 .with(predicate::always(), predicate::eq(1))
1072 .returning(|_, _| Ok(TestEv {}.to_bytes().unwrap().into()));
1073
1074 let env = HostEnv::new(Rc::new(RefCell::new(ctx)));
1075
1076 assert_eq!(env.get_event(&addr, 1), Ok(TestEv {}));
1077 assert_eq!(env.get_event(&addr, -1), Ok(TestEv {}));
1078 assert_eq!(
1079 env.get_event::<TestEv, _>(&addr, 0),
1080 Err(EventError::Parsing)
1081 );
1082 assert_eq!(
1083 env.get_event::<TestEv, _>(&addr, -2),
1084 Err(EventError::Parsing)
1085 );
1086 assert_eq!(
1087 env.get_event::<TestEv, _>(&addr, 2),
1088 Err(EventError::IndexOutOfBounds)
1089 );
1090 assert_eq!(
1091 env.get_event::<TestEv, _>(&addr, -3),
1092 Err(EventError::IndexOutOfBounds)
1093 );
1094 }
1095
1096 #[test]
1097 fn test_events_works() {
1098 let addr = Address::Account(AccountHash::new([0; 32]));
1099
1100 let mut ctx = MockHostContext::new();
1101 ctx.expect_get_events_count().returning(|_| Ok(2));
1103 ctx.expect_get_event()
1105 .with(predicate::always(), predicate::eq(0))
1106 .returning(|_, _| Ok(vec![1].into()));
1107 ctx.expect_get_event()
1109 .with(predicate::always(), predicate::eq(1))
1110 .returning(|_, _| Ok(vec![1, 0, 1].into()));
1111
1112 let env = HostEnv::new(Rc::new(RefCell::new(ctx)));
1113
1114 assert_eq!(
1115 env.events(&addr),
1116 vec![vec![1].into(), vec![1, 0, 1].into()]
1117 );
1118 }
1119
1120 #[test]
1121 #[should_panic(
1122 expected = "Couldn't get event at address Account(AccountHash(0000000000000000000000000000000000000000000000000000000000000000)) with id 0: CouldntExtractEventData"
1123 )]
1124 fn test_events_fails() {
1125 let addr = Address::Account(AccountHash::new([0; 32]));
1126
1127 let mut ctx = MockHostContext::new();
1128 ctx.expect_get_events_count().returning(|_| Ok(2));
1130 ctx.expect_get_event()
1132 .with(predicate::always(), predicate::eq(0))
1133 .returning(|_, _| Err(EventError::CouldntExtractEventData));
1134
1135 let env = HostEnv::new(Rc::new(RefCell::new(ctx)));
1136
1137 env.events(&addr);
1138 }
1139
1140 #[test]
1141 fn test_emitted() {
1142 let addr = Address::Account(AccountHash::new([0; 32]));
1143 let mut ctx = MockHostContext::new();
1144
1145 ctx.expect_get_events_count().returning(|_| Ok(1));
1146 ctx.expect_get_event()
1147 .returning(|_, _| Ok(TestEv {}.to_bytes().unwrap().into()));
1148
1149 let env = HostEnv::new(Rc::new(RefCell::new(ctx)));
1150 assert!(env.emitted(&addr, "TestEv"));
1151 assert!(!env.emitted(&addr, "AnotherEvent"));
1152 }
1153}