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>>> }
340
341impl HostEnv {
342 pub fn new(backend: Rc<RefCell<dyn HostContext>>) -> HostEnv {
344 HostEnv {
345 backend,
346 last_call_result: RefCell::new(None).into(),
347 deployed_contracts: RefCell::new(vec![]).into(),
348 events_count: Rc::new(RefCell::new(Default::default())),
349 native_events_count: Rc::new(RefCell::new(Default::default()))
350 }
351 }
352
353 pub fn get_account(&self, index: usize) -> Address {
355 let backend = self.backend.borrow();
356 backend.get_account(index)
357 }
358
359 pub fn get_validator(&self, index: usize) -> PublicKey {
361 let backend = self.backend.borrow();
362 backend.get_validator(index)
363 }
364
365 pub fn set_caller(&self, address: Address) {
367 if address.is_contract() {
368 panic!("Caller cannot be a contract: {:?}", address)
369 }
370 let backend = self.backend.borrow();
371 backend.set_caller(address)
372 }
373
374 pub fn advance_block_time(&self, time_diff: u64) {
376 let backend = self.backend.borrow();
377 backend.advance_block_time(time_diff)
378 }
379
380 pub fn advance_with_auctions(&self, time_diff: u64) {
382 let backend = self.backend.borrow();
383 backend.advance_with_auctions(time_diff);
384 }
385
386 pub fn auction_delay(&self) -> u64 {
388 let backend = self.backend.borrow();
389 backend.auction_delay()
390 }
391
392 pub fn unbonding_delay(&self) -> u64 {
394 let backend = self.backend.borrow();
395 backend.unbonding_delay()
396 }
397
398 pub fn delegated_amount(&self, delegator: Address, validator: PublicKey) -> U512 {
400 let backend = self.backend.borrow();
401 backend.delegated_amount(delegator, validator)
402 }
403
404 pub fn remove_validator(&self, index: usize) {
406 let backend = self.backend.borrow();
407 backend.remove_validator(index);
408 }
409
410 pub fn block_time(&self) -> u64 {
412 let backend = self.backend.borrow();
413 backend.block_time()
414 }
415
416 pub fn block_time_millis(&self) -> u64 {
418 let backend = self.backend.borrow();
419 backend.block_time()
420 }
421
422 pub fn block_time_secs(&self) -> u64 {
424 let backend = self.backend.borrow();
425 backend.block_time().checked_div(1000).unwrap()
426 }
427
428 pub fn new_contract(
430 &self,
431 name: &str,
432 init_args: RuntimeArgs,
433 entry_points_caller: EntryPointsCaller
434 ) -> OdraResult<Address> {
435 let backend = self.backend.borrow();
436 let deployed_contract = backend.new_contract(name, init_args, entry_points_caller)?;
437
438 self.deployed_contracts.borrow_mut().push(deployed_contract);
439 self.events_count.borrow_mut().insert(deployed_contract, 0);
440 self.native_events_count
441 .borrow_mut()
442 .insert(deployed_contract, 0);
443 Ok(deployed_contract)
444 }
445
446 pub fn register_contract(
449 &self,
450 address: Address,
451 contract_name: String,
452 entry_points_caller: EntryPointsCaller
453 ) {
454 let events_count = self.events_count(&address);
455 let native_events_count = self.native_events_count(&address);
456 let backend = self.backend.borrow();
457 backend.register_contract(address, contract_name, entry_points_caller);
458 self.deployed_contracts.borrow_mut().push(address);
459 self.events_count.borrow_mut().insert(address, events_count);
460 self.native_events_count
461 .borrow_mut()
462 .insert(address, native_events_count);
463 }
464
465 pub fn call_contract<T: FromBytes + CLTyped>(
467 &self,
468 address: Address,
469 call_def: CallDef
470 ) -> OdraResult<T> {
471 let use_proxy = T::cl_type() != <()>::cl_type() || !call_def.amount().is_zero();
472 let call_result = self.raw_call_contract(address, call_def, use_proxy);
473 call_result.map(|bytes| {
474 T::from_bytes(&bytes)
475 .map(|(obj, _)| obj)
476 .map_err(|_| OdraError::VmError(VmError::Deserialization))
477 })?
478 }
479
480 pub fn raw_call_contract(
483 &self,
484 address: Address,
485 call_def: CallDef,
486 use_proxy: bool
487 ) -> OdraResult<Bytes> {
488 let backend = self.backend.borrow();
489 let call_result = backend.call_contract(&address, call_def, use_proxy);
490
491 let mut events_map: BTreeMap<Address, Vec<Bytes>> = BTreeMap::new();
492 let mut native_events_map: BTreeMap<Address, Vec<Bytes>> = BTreeMap::new();
493
494 self.deployed_contracts
496 .borrow()
497 .iter()
498 .for_each(|contract_address| {
499 let events = self.last_events(contract_address);
500 let native_events = self.last_native_events(contract_address);
501 events_map.insert(*contract_address, events);
502 native_events_map.insert(*contract_address, native_events);
503 });
504
505 let last_call_gas_cost = backend.last_call_gas_cost();
506
507 self.last_call_result.replace(Some(CallResult::new(
508 address,
509 backend.caller(),
510 last_call_gas_cost,
511 call_result.clone(),
512 events_map,
513 native_events_map
514 )));
515
516 call_result
517 }
518
519 pub fn contract_env(&self) -> ContractEnv {
521 self.backend.borrow().contract_env()
522 }
523
524 pub fn gas_report(&self) -> GasReport {
526 self.backend.borrow().gas_report().clone()
527 }
528
529 pub fn balance_of<T: Addressable>(&self, address: &T) -> U512 {
531 let backend = self.backend.borrow();
532 backend.balance_of(address.address())
533 }
534
535 pub fn get_event<T: FromBytes + EventInstance, R: Addressable>(
542 &self,
543 contract_address: &R,
544 index: i32
545 ) -> Result<T, EventError> {
546 let contract_address = contract_address.address();
547 let backend = self.backend.borrow();
548 let events_count = self.events_count(contract_address);
549 let event_absolute_position = crate::utils::event_absolute_position(events_count, index)
550 .ok_or(EventError::IndexOutOfBounds)?;
551
552 let bytes = backend.get_event(contract_address, event_absolute_position)?;
553 T::from_bytes(&bytes)
554 .map_err(|_| EventError::Parsing)
555 .map(|r| r.0)
556 }
557
558 pub fn get_native_event<T: FromBytes + EventInstance, R: Addressable>(
565 &self,
566 contract_address: &R,
567 index: i32
568 ) -> Result<T, EventError> {
569 let contract_address = contract_address.address();
570 let backend = self.backend.borrow();
571 let events_count = self.native_events_count(contract_address);
572 let event_absolute_position = crate::utils::event_absolute_position(events_count, index)
573 .ok_or(EventError::IndexOutOfBounds)?;
574
575 let bytes = backend.get_native_event(contract_address, event_absolute_position)?;
576 T::from_bytes(&bytes)
577 .map_err(|_| EventError::Parsing)
578 .map(|r| r.0)
579 }
580
581 pub fn get_event_bytes<T: Addressable>(
583 &self,
584 contract_address: &T,
585 index: u32
586 ) -> Result<Bytes, EventError> {
587 let backend = self.backend.borrow();
588 backend.get_event(contract_address.address(), index)
589 }
590
591 pub fn get_native_event_bytes<T: Addressable>(
593 &self,
594 contract_address: &T,
595 index: u32
596 ) -> Result<Bytes, EventError> {
597 let backend = self.backend.borrow();
598 backend.get_native_event(contract_address.address(), index)
599 }
600
601 pub fn event_names<T: Addressable>(&self, contract_address: &T) -> Vec<String> {
603 let events_count = self.events_count(contract_address);
604
605 let backend = self.backend.borrow();
606 (0..events_count)
607 .map(|event_id| {
608 backend
609 .get_event(contract_address.address(), event_id)
610 .and_then(|bytes| utils::extract_event_name(&bytes))
611 .unwrap_or_else(|e| panic!("Couldn't extract event name: {:?}", e))
612 })
613 .collect()
614 }
615
616 pub fn events<T: Addressable>(&self, contract_address: &T) -> Vec<Bytes> {
618 let backend = self.backend.borrow();
619 let contract_address = contract_address.address();
620 let events_count = backend
621 .get_events_count(contract_address)
622 .unwrap_or_default();
623 (0..events_count)
624 .map(|event_id| {
625 backend
626 .get_event(contract_address, event_id)
627 .unwrap_or_else(|e| {
628 panic!(
629 "Couldn't get event at address {:?} with id {}: {:?}",
630 &contract_address, event_id, e
631 )
632 })
633 })
634 .collect()
635 }
636
637 pub fn events_count<T: Addressable>(&self, address: &T) -> u32 {
639 let backend = self.backend.borrow();
640 backend
641 .get_events_count(address.address())
642 .unwrap_or_default()
643 }
644
645 pub fn native_events_count<T: Addressable>(&self, address: &T) -> u32 {
647 let backend = self.backend.borrow();
648 backend
649 .get_native_events_count(address.address())
650 .unwrap_or_default()
651 }
652
653 pub fn emitted_event<T: ToBytes + EventInstance, R: Addressable>(
655 &self,
656 contract_address: &R,
657 event: &T
658 ) -> bool {
659 let contract_address = contract_address.address();
660 let events_count = self.events_count(contract_address);
661
662 let event_bytes = Bytes::from(
663 event
664 .to_bytes()
665 .unwrap_or_else(|_| panic!("Couldn't serialize event"))
666 );
667
668 (0..events_count)
669 .map(|event_id| {
670 self.get_event_bytes(contract_address, event_id)
671 .unwrap_or_else(|e| {
672 panic!(
673 "Couldn't get event at address {:?} with id {}: {:?}",
674 &contract_address, event_id, e
675 )
676 })
677 })
678 .any(|bytes| bytes == event_bytes)
679 }
680
681 pub fn emitted_native_event<T: ToBytes + EventInstance, R: Addressable>(
683 &self,
684 contract_address: &R,
685 event: &T
686 ) -> bool {
687 let contract_address = contract_address.address();
688 let events_count = self.native_events_count(contract_address);
689 if events_count > 0 {
690 let event_bytes = Bytes::from(
691 event
692 .to_bytes()
693 .unwrap_or_else(|_| panic!("Couldn't serialize event"))
694 );
695 (0..events_count)
696 .map(|event_id| {
697 self.get_native_event_bytes(contract_address, event_id)
698 .unwrap_or_else(|e| {
699 panic!(
700 "Couldn't get event at address {:?} with id {}: {:?}",
701 &contract_address, event_id, e
702 )
703 })
704 })
705 .any(|bytes| bytes == event_bytes)
706 } else {
707 false
708 }
709 }
710
711 pub fn emitted<T: AsRef<str>, R: Addressable>(
713 &self,
714 contract_address: &R,
715 event_name: T
716 ) -> bool {
717 let events_count = self.events_count(contract_address);
718
719 (0..events_count)
720 .map(|event_id| {
721 self.get_event_bytes(contract_address, event_id)
722 .unwrap_or_else(|e| {
723 panic!(
724 "Couldn't get event at address {:?} with id {}: {:?}",
725 contract_address.address(),
726 event_id,
727 e
728 )
729 })
730 })
731 .any(|bytes| {
732 utils::extract_event_name(&bytes)
733 .unwrap_or_else(|e| panic!("Couldn't extract event name: {:?}", e))
734 .as_str()
735 == event_name.as_ref()
736 })
737 }
738 pub fn emitted_native<T: AsRef<str>, R: Addressable>(
740 &self,
741 contract_address: &R,
742 event_name: T
743 ) -> bool {
744 let events_count = self.native_events_count(contract_address);
745
746 (0..events_count)
747 .map(|event_id| {
748 self.get_native_event_bytes(contract_address, event_id)
749 .unwrap_or_else(|e| {
750 panic!(
751 "Couldn't get event at address {:?} with id {}: {:?}",
752 contract_address.address(),
753 event_id,
754 e
755 )
756 })
757 })
758 .any(|bytes| {
759 utils::extract_event_name(&bytes)
760 .unwrap_or_else(|e| panic!("Couldn't extract event name: {:?}", e))
761 .as_str()
762 == event_name.as_ref()
763 })
764 }
765
766 pub fn last_call_result(&self, contract_address: Address) -> ContractCallResult {
768 self.last_call_result
769 .borrow()
770 .clone()
771 .unwrap()
772 .contract_last_call(contract_address)
773 }
774
775 pub fn sign_message(&self, message: &Bytes, address: &Address) -> Bytes {
777 let backend = self.backend.borrow();
778 backend.sign_message(message, address)
779 }
780
781 pub fn public_key(&self, address: &Address) -> PublicKey {
783 let backend = self.backend.borrow();
784 backend.public_key(address)
785 }
786
787 pub fn caller(&self) -> Address {
789 let backend = self.backend.borrow();
790 backend.caller()
791 }
792
793 pub fn set_gas(&self, gas: u64) {
795 let backend = self.backend.borrow();
796 backend.set_gas(gas)
797 }
798
799 pub fn transfer(&self, to: Address, amount: U512) -> OdraResult<()> {
801 if to.is_contract() {
802 return Err(OdraError::ExecutionError(
803 ExecutionError::TransferToContract
804 ));
805 }
806 let backend = self.backend.borrow();
807 backend.transfer(to, amount)
808 }
809
810 fn last_events(&self, contract_address: &Address) -> Vec<Bytes> {
811 let mut old_count_binding = self.events_count.borrow_mut();
812 let old_count = *old_count_binding.get(contract_address).unwrap();
813 let new_count = self.events_count(contract_address);
814 let mut events = vec![];
815 for count in old_count..new_count {
816 let event = self.get_event_bytes(contract_address, count).unwrap();
817 events.push(event);
818 }
819
820 old_count_binding.insert(*contract_address, new_count);
821 events
822 }
823
824 fn last_native_events(&self, contract_address: &Address) -> Vec<Bytes> {
825 let mut old_count_binding = self.native_events_count.borrow_mut();
826 let old_count = *old_count_binding.get(contract_address).unwrap();
827 let new_count = self.native_events_count(contract_address);
828 let mut events = vec![];
829 for count in old_count..new_count {
830 let event = self
831 .get_native_event_bytes(contract_address, count)
832 .unwrap();
833 events.push(event);
834 }
835
836 old_count_binding.insert(*contract_address, new_count);
837 events
838 }
839}
840
841#[cfg(test)]
842mod test {
843 use core::fmt::Debug;
844
845 use super::*;
846 use casper_event_standard::Event;
847 use casper_types::account::AccountHash;
848 use casper_types::contracts::ContractPackageHash;
849 use mockall::{mock, predicate};
850 use std::sync::Mutex;
851
852 static IDENT_MTX: Mutex<()> = Mutex::new(());
853 static EPC_MTX: Mutex<()> = Mutex::new(());
854
855 #[derive(Debug, Event, PartialEq)]
856 struct TestEv {}
857
858 mock! {
859 TestRef {}
860 impl HasIdent for TestRef {
861 fn ident() -> String;
862 }
863 impl EntryPointsCallerProvider for TestRef {
864 fn entry_points_caller(env: &HostEnv) -> EntryPointsCaller;
865 }
866 impl HostRef for TestRef {
867 fn new(address: Address, env: HostEnv) -> Self;
868 fn with_tokens(&self, tokens: U512) -> Self;
869 fn address(&self) -> &Address;
870 fn env(&self) -> &HostEnv;
871 fn get_event<T>(&self, index: i32) -> Result<T, EventError> where T: FromBytes + EventInstance + 'static;
872 fn last_call(&self) -> ContractCallResult;
873 }
874 }
875
876 impl crate::ContractRef for MockTestRef {
877 fn new(_env: Rc<ContractEnv>, _address: Address) -> Self {
878 unimplemented!()
879 }
880 fn address(&self) -> &Address {
881 unimplemented!()
882 }
883
884 fn with_tokens(&self, _tokens: U512) -> Self {
885 unimplemented!()
886 }
887 }
888
889 impl OdraContract for MockTestRef {
890 type HostRef = MockTestRef;
891
892 type ContractRef = MockTestRef;
893
894 type InitArgs = NoArgs;
895 }
896
897 mock! {
898 Ev {}
899 impl Into<RuntimeArgs> for Ev {
900 fn into(self) -> RuntimeArgs;
901 }
902 }
903
904 #[test]
905 fn test_deploy_with_default_args() {
906 let _i = IDENT_MTX.lock();
911 let _e = EPC_MTX.lock();
912
913 let indent_ctx = MockTestRef::ident_context();
915 indent_ctx.expect().returning(|| "TestRef".to_string());
916
917 let epc_ctx = MockTestRef::entry_points_caller_context();
918 epc_ctx
919 .expect()
920 .returning(|h| EntryPointsCaller::new(h.clone(), vec![], |_, _| Ok(Bytes::default())));
921
922 let instance_ctx = MockTestRef::new_context();
924 instance_ctx
925 .expect()
926 .times(1)
927 .returning(|_, _| MockTestRef::default());
928
929 let mut ctx = MockHostContext::new();
930 ctx.expect_new_contract()
931 .returning(|_, _, _| Ok(Address::Account(AccountHash::new([0; 32]))));
932 let env = HostEnv::new(Rc::new(RefCell::new(ctx)));
933 MockTestRef::deploy(&env, NoArgs);
934 }
935
936 #[test]
937 fn test_load_ref() {
938 let _e = EPC_MTX.lock();
943 let _i = IDENT_MTX.lock();
944
945 let epc_ctx = MockTestRef::entry_points_caller_context();
947 epc_ctx
948 .expect()
949 .returning(|h| EntryPointsCaller::new(h.clone(), vec![], |_, _| Ok(Bytes::default())));
950 let indent_ctx = MockTestRef::ident_context();
951 indent_ctx.expect().returning(|| "TestRef".to_string());
952
953 let mut ctx = MockHostContext::new();
954 ctx.expect_register_contract().returning(|_, _, _| ());
955 ctx.expect_get_events_count().returning(|_| Ok(0));
956 ctx.expect_get_native_events_count().returning(|_| Ok(0));
957
958 let instance_ctx = MockTestRef::new_context();
960 instance_ctx
961 .expect()
962 .times(1)
963 .returning(|_, _| MockTestRef::default());
964
965 let env = HostEnv::new(Rc::new(RefCell::new(ctx)));
966 let address = Address::Account(AccountHash::new([0; 32]));
967 MockTestRef::load(&env, address);
968 }
969
970 #[test]
971 fn test_host_env() {
972 let mut ctx = MockHostContext::new();
973 ctx.expect_new_contract()
974 .returning(|_, _, _| Ok(Address::Account(AccountHash::new([0; 32]))));
975 ctx.expect_caller()
976 .returning(|| Address::Account(AccountHash::new([2; 32])))
977 .times(1);
978 ctx.expect_gas_report().returning(GasReport::new).times(1);
979 ctx.expect_set_gas().returning(|_| ()).times(1);
980
981 let env = HostEnv::new(Rc::new(RefCell::new(ctx)));
982
983 assert_eq!(env.caller(), Address::Account(AccountHash::new([2; 32])));
984 env.gas_report();
986 env.set_gas(1_000u64)
987 }
988
989 #[test]
990 fn test_successful_transfer_to_account() {
991 let mut ctx = MockHostContext::new();
993 ctx.expect_transfer().returning(|_, _| Ok(()));
994 let env = HostEnv::new(Rc::new(RefCell::new(ctx)));
995
996 let addr = Address::Account(AccountHash::new([0; 32]));
997 let result = env.transfer(addr, 100.into());
999 assert!(result.is_ok());
1001 }
1002
1003 #[test]
1004 fn test_failing_transfer_to_account() {
1005 let mut ctx = MockHostContext::new();
1007 ctx.expect_transfer()
1008 .returning(|_, _| Err(OdraError::ExecutionError(ExecutionError::UnwrapError)));
1009 let env = HostEnv::new(Rc::new(RefCell::new(ctx)));
1010
1011 let addr = Address::Account(AccountHash::new([0; 32]));
1012 let result = env.transfer(addr, 100.into());
1014 assert_eq!(
1016 result.err(),
1017 Some(OdraError::ExecutionError(ExecutionError::UnwrapError))
1018 );
1019 }
1020
1021 #[test]
1022 fn test_transfer_to_contract() {
1023 let mut ctx = MockHostContext::new();
1025 ctx.expect_transfer().returning(|_, _| Ok(()));
1026 let env = HostEnv::new(Rc::new(RefCell::new(ctx)));
1027
1028 let addr = Address::Contract(ContractPackageHash::new([0; 32]));
1029 let result = env.transfer(addr, 100.into());
1031 assert_eq!(
1033 result,
1034 Err(OdraError::ExecutionError(
1035 ExecutionError::TransferToContract
1036 ))
1037 );
1038 }
1039
1040 #[test]
1041 fn test_get_event() {
1042 let addr = Address::Account(AccountHash::new([0; 32]));
1043
1044 let mut ctx = MockHostContext::new();
1045 ctx.expect_get_events_count().returning(|_| Ok(2));
1047 ctx.expect_get_event()
1049 .with(predicate::always(), predicate::eq(0))
1050 .returning(|_, _| Ok(vec![1].into()));
1051 ctx.expect_get_event()
1053 .with(predicate::always(), predicate::eq(1))
1054 .returning(|_, _| Ok(TestEv {}.to_bytes().unwrap().into()));
1055
1056 let env = HostEnv::new(Rc::new(RefCell::new(ctx)));
1057
1058 assert_eq!(env.get_event(&addr, 1), Ok(TestEv {}));
1059 assert_eq!(env.get_event(&addr, -1), Ok(TestEv {}));
1060 assert_eq!(
1061 env.get_event::<TestEv, _>(&addr, 0),
1062 Err(EventError::Parsing)
1063 );
1064 assert_eq!(
1065 env.get_event::<TestEv, _>(&addr, -2),
1066 Err(EventError::Parsing)
1067 );
1068 assert_eq!(
1069 env.get_event::<TestEv, _>(&addr, 2),
1070 Err(EventError::IndexOutOfBounds)
1071 );
1072 assert_eq!(
1073 env.get_event::<TestEv, _>(&addr, -3),
1074 Err(EventError::IndexOutOfBounds)
1075 );
1076 }
1077
1078 #[test]
1079 fn test_events_works() {
1080 let addr = Address::Account(AccountHash::new([0; 32]));
1081
1082 let mut ctx = MockHostContext::new();
1083 ctx.expect_get_events_count().returning(|_| Ok(2));
1085 ctx.expect_get_event()
1087 .with(predicate::always(), predicate::eq(0))
1088 .returning(|_, _| Ok(vec![1].into()));
1089 ctx.expect_get_event()
1091 .with(predicate::always(), predicate::eq(1))
1092 .returning(|_, _| Ok(vec![1, 0, 1].into()));
1093
1094 let env = HostEnv::new(Rc::new(RefCell::new(ctx)));
1095
1096 assert_eq!(
1097 env.events(&addr),
1098 vec![vec![1].into(), vec![1, 0, 1].into()]
1099 );
1100 }
1101
1102 #[test]
1103 #[should_panic(
1104 expected = "Couldn't get event at address Account(AccountHash(0000000000000000000000000000000000000000000000000000000000000000)) with id 0: CouldntExtractEventData"
1105 )]
1106 fn test_events_fails() {
1107 let addr = Address::Account(AccountHash::new([0; 32]));
1108
1109 let mut ctx = MockHostContext::new();
1110 ctx.expect_get_events_count().returning(|_| Ok(2));
1112 ctx.expect_get_event()
1114 .with(predicate::always(), predicate::eq(0))
1115 .returning(|_, _| Err(EventError::CouldntExtractEventData));
1116
1117 let env = HostEnv::new(Rc::new(RefCell::new(ctx)));
1118
1119 env.events(&addr);
1120 }
1121
1122 #[test]
1123 fn test_emitted() {
1124 let addr = Address::Account(AccountHash::new([0; 32]));
1125 let mut ctx = MockHostContext::new();
1126
1127 ctx.expect_get_events_count().returning(|_| Ok(1));
1128 ctx.expect_get_event()
1129 .returning(|_, _| Ok(TestEv {}.to_bytes().unwrap().into()));
1130
1131 let env = HostEnv::new(Rc::new(RefCell::new(ctx)));
1132 assert!(env.emitted(&addr, "TestEv"));
1133 assert!(!env.emitted(&addr, "AnotherEvent"));
1134 }
1135}