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 balance_of(&self, address: &Address) -> U512;
247
248 fn advance_block_time(&self, time_diff: u64);
250
251 fn block_time(&self) -> u64;
253
254 fn get_event(&self, contract_address: &Address, index: u32) -> Result<Bytes, EventError>;
256
257 fn get_events_count(&self, contract_address: &Address) -> u32;
259
260 fn call_contract(
262 &self,
263 address: &Address,
264 call_def: CallDef,
265 use_proxy: bool
266 ) -> OdraResult<Bytes>;
267
268 fn new_contract(
270 &self,
271 name: &str,
272 init_args: RuntimeArgs,
273 entry_points_caller: EntryPointsCaller
274 ) -> OdraResult<Address>;
275
276 fn register_contract(
278 &self,
279 address: Address,
280 contract_name: String,
281 entry_points_caller: EntryPointsCaller
282 );
283
284 fn contract_env(&self) -> ContractEnv;
286
287 fn gas_report(&self) -> GasReport;
289
290 fn last_call_gas_cost(&self) -> u64;
292
293 fn sign_message(&self, message: &Bytes, address: &Address) -> Bytes;
295
296 fn public_key(&self, address: &Address) -> PublicKey;
298
299 fn transfer(&self, to: Address, amount: U512) -> OdraResult<()>;
301}
302
303#[derive(Clone)]
308pub struct HostEnv {
309 backend: Rc<RefCell<dyn HostContext>>,
310 last_call_result: Rc<RefCell<Option<CallResult>>>,
311 deployed_contracts: Rc<RefCell<Vec<Address>>>,
312 events_count: Rc<RefCell<BTreeMap<Address, u32>>> }
314
315impl HostEnv {
316 pub fn new(backend: Rc<RefCell<dyn HostContext>>) -> HostEnv {
318 HostEnv {
319 backend,
320 last_call_result: RefCell::new(None).into(),
321 deployed_contracts: RefCell::new(vec![]).into(),
322 events_count: Rc::new(RefCell::new(Default::default()))
323 }
324 }
325
326 pub fn get_account(&self, index: usize) -> Address {
328 let backend = self.backend.borrow();
329 backend.get_account(index)
330 }
331
332 pub fn set_caller(&self, address: Address) {
334 if address.is_contract() {
335 panic!("Caller cannot be a contract: {:?}", address)
336 }
337 let backend = self.backend.borrow();
338 backend.set_caller(address)
339 }
340
341 pub fn advance_block_time(&self, time_diff: u64) {
343 let backend = self.backend.borrow();
344 backend.advance_block_time(time_diff)
345 }
346
347 pub fn block_time(&self) -> u64 {
349 let backend = self.backend.borrow();
350 backend.block_time()
351 }
352
353 pub fn new_contract(
355 &self,
356 name: &str,
357 init_args: RuntimeArgs,
358 entry_points_caller: EntryPointsCaller
359 ) -> OdraResult<Address> {
360 let backend = self.backend.borrow();
361 let deployed_contract = backend.new_contract(name, init_args, entry_points_caller)?;
362
363 self.deployed_contracts.borrow_mut().push(deployed_contract);
364 self.events_count.borrow_mut().insert(deployed_contract, 0);
365 Ok(deployed_contract)
366 }
367
368 pub fn register_contract(
371 &self,
372 address: Address,
373 contract_name: String,
374 entry_points_caller: EntryPointsCaller
375 ) {
376 let backend = self.backend.borrow();
377 backend.register_contract(address, contract_name, entry_points_caller);
378 self.deployed_contracts.borrow_mut().push(address);
379 }
380
381 pub fn call_contract<T: FromBytes + CLTyped>(
383 &self,
384 address: Address,
385 call_def: CallDef
386 ) -> OdraResult<T> {
387 let use_proxy = T::cl_type() != <()>::cl_type() || !call_def.amount().is_zero();
388 let call_result = self.raw_call_contract(address, call_def, use_proxy);
389 call_result.map(|bytes| {
390 T::from_bytes(&bytes)
391 .map(|(obj, _)| obj)
392 .map_err(|_| OdraError::VmError(VmError::Deserialization))
393 })?
394 }
395
396 pub fn raw_call_contract(
399 &self,
400 address: Address,
401 call_def: CallDef,
402 use_proxy: bool
403 ) -> OdraResult<Bytes> {
404 let backend = self.backend.borrow();
405 let call_result = backend.call_contract(&address, call_def, use_proxy);
406
407 let mut events_map: BTreeMap<Address, Vec<Bytes>> = BTreeMap::new();
408 let mut binding = self.events_count.borrow_mut();
409
410 self.deployed_contracts
412 .borrow()
413 .iter()
414 .for_each(|contract_address| {
415 if binding.get(contract_address).is_none() {
416 binding.insert(
417 *contract_address,
418 backend.get_events_count(contract_address)
419 );
420 }
421 let events_count = binding.get_mut(contract_address).unwrap();
422 let old_events_last_id = *events_count;
423 let new_events_count = backend.get_events_count(contract_address);
424 let mut events = vec![];
425 for event_id in old_events_last_id..new_events_count {
426 let event = backend.get_event(contract_address, event_id).unwrap();
427 events.push(event);
428 }
429
430 events_map.insert(*contract_address, events);
431
432 *events_count = new_events_count;
433 });
434
435 let last_call_gas_cost = backend.last_call_gas_cost();
436
437 self.last_call_result.replace(Some(CallResult::new(
438 address,
439 backend.caller(),
440 last_call_gas_cost,
441 call_result.clone(),
442 events_map
443 )));
444
445 call_result
446 }
447
448 pub fn contract_env(&self) -> ContractEnv {
450 self.backend.borrow().contract_env()
451 }
452
453 pub fn gas_report(&self) -> GasReport {
455 self.backend.borrow().gas_report().clone()
456 }
457
458 pub fn balance_of<T: Addressable>(&self, address: &T) -> U512 {
460 let backend = self.backend.borrow();
461 backend.balance_of(address.address())
462 }
463
464 pub fn get_event<T: FromBytes + EventInstance, R: Addressable>(
471 &self,
472 contract_address: &R,
473 index: i32
474 ) -> Result<T, EventError> {
475 let contract_address = contract_address.address();
476 let backend = self.backend.borrow();
477 let events_count = self.events_count(contract_address);
478 let event_absolute_position = crate::utils::event_absolute_position(events_count, index)
479 .ok_or(EventError::IndexOutOfBounds)?;
480
481 let bytes = backend.get_event(contract_address, event_absolute_position)?;
482 T::from_bytes(&bytes)
483 .map_err(|_| EventError::Parsing)
484 .map(|r| r.0)
485 }
486
487 pub fn get_event_bytes<T: Addressable>(
489 &self,
490 contract_address: &T,
491 index: u32
492 ) -> Result<Bytes, EventError> {
493 let backend = self.backend.borrow();
494 backend.get_event(contract_address.address(), index)
495 }
496
497 pub fn event_names<T: Addressable>(&self, contract_address: &T) -> Vec<String> {
499 let backend = self.backend.borrow();
500 let events_count = backend.get_events_count(contract_address.address());
501
502 (0..events_count)
503 .map(|event_id| {
504 backend
505 .get_event(contract_address.address(), event_id)
506 .and_then(|bytes| utils::extract_event_name(&bytes))
507 .unwrap_or_else(|e| panic!("Couldn't extract event name: {:?}", e))
508 })
509 .collect()
510 }
511
512 pub fn events<T: Addressable>(&self, contract_address: &T) -> Vec<Bytes> {
514 let backend = self.backend.borrow();
515 let contract_address = contract_address.address();
516 let events_count = backend.get_events_count(contract_address);
517 (0..events_count)
518 .map(|event_id| {
519 backend
520 .get_event(contract_address, event_id)
521 .unwrap_or_else(|e| {
522 panic!(
523 "Couldn't get event at address {:?} with id {}: {:?}",
524 &contract_address, event_id, e
525 )
526 })
527 })
528 .collect()
529 }
530
531 pub fn events_count<T: Addressable>(&self, contract_address: &T) -> u32 {
533 let backend = self.backend.borrow();
534 backend.get_events_count(contract_address.address())
535 }
536
537 pub fn emitted_event<T: ToBytes + EventInstance, R: Addressable>(
539 &self,
540 contract_address: &R,
541 event: &T
542 ) -> bool {
543 let contract_address = contract_address.address();
544 let events_count = self.events_count(contract_address);
545 let event_bytes = Bytes::from(
546 event
547 .to_bytes()
548 .unwrap_or_else(|_| panic!("Couldn't serialize event"))
549 );
550 (0..events_count)
551 .map(|event_id| {
552 self.get_event_bytes(contract_address, event_id)
553 .unwrap_or_else(|e| {
554 panic!(
555 "Couldn't get event at address {:?} with id {}: {:?}",
556 &contract_address, event_id, e
557 )
558 })
559 })
560 .any(|bytes| bytes == event_bytes)
561 }
562
563 pub fn emitted<T: AsRef<str>, R: Addressable>(
565 &self,
566 contract_address: &R,
567 event_name: T
568 ) -> bool {
569 let events_count = self.events_count(contract_address);
570 (0..events_count)
571 .map(|event_id| {
572 self.get_event_bytes(contract_address, event_id)
573 .unwrap_or_else(|e| {
574 panic!(
575 "Couldn't get event at address {:?} with id {}: {:?}",
576 contract_address.address(),
577 event_id,
578 e
579 )
580 })
581 })
582 .any(|bytes| {
583 utils::extract_event_name(&bytes)
584 .unwrap_or_else(|e| panic!("Couldn't extract event name: {:?}", e))
585 .as_str()
586 == event_name.as_ref()
587 })
588 }
589
590 pub fn last_call_result(&self, contract_address: Address) -> ContractCallResult {
592 self.last_call_result
593 .borrow()
594 .clone()
595 .unwrap()
596 .contract_last_call(contract_address)
597 }
598
599 pub fn sign_message(&self, message: &Bytes, address: &Address) -> Bytes {
601 let backend = self.backend.borrow();
602 backend.sign_message(message, address)
603 }
604
605 pub fn public_key(&self, address: &Address) -> PublicKey {
607 let backend = self.backend.borrow();
608 backend.public_key(address)
609 }
610
611 pub fn caller(&self) -> Address {
613 let backend = self.backend.borrow();
614 backend.caller()
615 }
616
617 pub fn set_gas(&self, gas: u64) {
619 let backend = self.backend.borrow();
620 backend.set_gas(gas)
621 }
622
623 pub fn transfer(&self, to: Address, amount: U512) -> OdraResult<()> {
625 if to.is_contract() {
626 return Err(OdraError::ExecutionError(
627 ExecutionError::TransferToContract
628 ));
629 }
630 let backend = self.backend.borrow();
631 backend.transfer(to, amount)
632 }
633}
634
635#[cfg(test)]
636mod test {
637 use core::fmt::Debug;
638
639 use super::*;
640 use casper_event_standard::Event;
641 use casper_types::{account::AccountHash, ContractPackageHash};
642 use mockall::{mock, predicate};
643 use std::sync::Mutex;
644
645 static IDENT_MTX: Mutex<()> = Mutex::new(());
646 static EPC_MTX: Mutex<()> = Mutex::new(());
647
648 #[derive(Debug, Event, PartialEq)]
649 struct TestEv {}
650
651 mock! {
652 TestRef {}
653 impl HasIdent for TestRef {
654 fn ident() -> String;
655 }
656 impl EntryPointsCallerProvider for TestRef {
657 fn entry_points_caller(env: &HostEnv) -> EntryPointsCaller;
658 }
659 impl HostRef for TestRef {
660 fn new(address: Address, env: HostEnv) -> Self;
661 fn with_tokens(&self, tokens: U512) -> Self;
662 fn address(&self) -> &Address;
663 fn env(&self) -> &HostEnv;
664 fn get_event<T>(&self, index: i32) -> Result<T, EventError> where T: FromBytes + EventInstance + 'static;
665 fn last_call(&self) -> ContractCallResult;
666 }
667 }
668
669 impl crate::ContractRef for MockTestRef {
670 fn new(_env: Rc<ContractEnv>, _address: Address) -> Self {
671 unimplemented!()
672 }
673 fn address(&self) -> &Address {
674 unimplemented!()
675 }
676 }
677
678 impl OdraContract for MockTestRef {
679 type HostRef = MockTestRef;
680
681 type ContractRef = MockTestRef;
682
683 type InitArgs = NoArgs;
684 }
685
686 mock! {
687 Ev {}
688 impl Into<RuntimeArgs> for Ev {
689 fn into(self) -> RuntimeArgs;
690 }
691 }
692
693 #[test]
694 fn test_deploy_with_default_args() {
695 let _i = IDENT_MTX.lock();
700 let _e = EPC_MTX.lock();
701
702 let indent_ctx = MockTestRef::ident_context();
704 indent_ctx.expect().returning(|| "TestRef".to_string());
705
706 let epc_ctx = MockTestRef::entry_points_caller_context();
707 epc_ctx
708 .expect()
709 .returning(|h| EntryPointsCaller::new(h.clone(), vec![], |_, _| Ok(Bytes::default())));
710
711 let instance_ctx = MockTestRef::new_context();
713 instance_ctx
714 .expect()
715 .times(1)
716 .returning(|_, _| MockTestRef::default());
717
718 let mut ctx = MockHostContext::new();
719 ctx.expect_new_contract()
720 .returning(|_, _, _| Ok(Address::Account(AccountHash::new([0; 32]))));
721 let env = HostEnv::new(Rc::new(RefCell::new(ctx)));
722 MockTestRef::deploy(&env, NoArgs);
723 }
724
725 #[test]
726 fn test_load_ref() {
727 let _e = EPC_MTX.lock();
732 let _i = IDENT_MTX.lock();
733
734 let epc_ctx = MockTestRef::entry_points_caller_context();
736 epc_ctx
737 .expect()
738 .returning(|h| EntryPointsCaller::new(h.clone(), vec![], |_, _| Ok(Bytes::default())));
739 let indent_ctx = MockTestRef::ident_context();
740 indent_ctx.expect().returning(|| "TestRef".to_string());
741
742 let mut ctx = MockHostContext::new();
743 ctx.expect_register_contract().returning(|_, _, _| ());
744 ctx.expect_get_events_count().returning(|_| 0);
745
746 let instance_ctx = MockTestRef::new_context();
748 instance_ctx
749 .expect()
750 .times(1)
751 .returning(|_, _| MockTestRef::default());
752
753 let env = HostEnv::new(Rc::new(RefCell::new(ctx)));
754 let address = Address::Account(AccountHash::new([0; 32]));
755 MockTestRef::load(&env, address);
756 }
757
758 #[test]
759 fn test_host_env() {
760 let mut ctx = MockHostContext::new();
761 ctx.expect_new_contract()
762 .returning(|_, _, _| Ok(Address::Account(AccountHash::new([0; 32]))));
763 ctx.expect_caller()
764 .returning(|| Address::Account(AccountHash::new([2; 32])))
765 .times(1);
766 ctx.expect_gas_report().returning(GasReport::new).times(1);
767 ctx.expect_set_gas().returning(|_| ()).times(1);
768
769 let env = HostEnv::new(Rc::new(RefCell::new(ctx)));
770
771 assert_eq!(env.caller(), Address::Account(AccountHash::new([2; 32])));
772 env.gas_report();
774 env.set_gas(1_000u64)
775 }
776
777 #[test]
778 fn test_successful_transfer_to_account() {
779 let mut ctx = MockHostContext::new();
781 ctx.expect_transfer().returning(|_, _| Ok(()));
782 let env = HostEnv::new(Rc::new(RefCell::new(ctx)));
783
784 let addr = Address::Account(AccountHash::new([0; 32]));
785 let result = env.transfer(addr, 100.into());
787 assert!(result.is_ok());
789 }
790
791 #[test]
792 fn test_failing_transfer_to_account() {
793 let mut ctx = MockHostContext::new();
795 ctx.expect_transfer()
796 .returning(|_, _| Err(OdraError::ExecutionError(ExecutionError::UnwrapError)));
797 let env = HostEnv::new(Rc::new(RefCell::new(ctx)));
798
799 let addr = Address::Account(AccountHash::new([0; 32]));
800 let result = env.transfer(addr, 100.into());
802 assert_eq!(
804 result.err(),
805 Some(OdraError::ExecutionError(ExecutionError::UnwrapError))
806 );
807 }
808
809 #[test]
810 fn test_transfer_to_contract() {
811 let mut ctx = MockHostContext::new();
813 ctx.expect_transfer().returning(|_, _| Ok(()));
814 let env = HostEnv::new(Rc::new(RefCell::new(ctx)));
815
816 let addr = Address::Contract(ContractPackageHash::new([0; 32]));
817 let result = env.transfer(addr, 100.into());
819 assert_eq!(
821 result,
822 Err(OdraError::ExecutionError(
823 ExecutionError::TransferToContract
824 ))
825 );
826 }
827
828 #[test]
829 fn test_get_event() {
830 let addr = Address::Account(AccountHash::new([0; 32]));
831
832 let mut ctx = MockHostContext::new();
833 ctx.expect_get_events_count().returning(|_| 2);
835 ctx.expect_get_event()
837 .with(predicate::always(), predicate::eq(0))
838 .returning(|_, _| Ok(vec![1].into()));
839 ctx.expect_get_event()
841 .with(predicate::always(), predicate::eq(1))
842 .returning(|_, _| Ok(TestEv {}.to_bytes().unwrap().into()));
843
844 let env = HostEnv::new(Rc::new(RefCell::new(ctx)));
845
846 assert_eq!(env.get_event(&addr, 1), Ok(TestEv {}));
847 assert_eq!(env.get_event(&addr, -1), Ok(TestEv {}));
848 assert_eq!(
849 env.get_event::<TestEv, _>(&addr, 0),
850 Err(EventError::Parsing)
851 );
852 assert_eq!(
853 env.get_event::<TestEv, _>(&addr, -2),
854 Err(EventError::Parsing)
855 );
856 assert_eq!(
857 env.get_event::<TestEv, _>(&addr, 2),
858 Err(EventError::IndexOutOfBounds)
859 );
860 assert_eq!(
861 env.get_event::<TestEv, _>(&addr, -3),
862 Err(EventError::IndexOutOfBounds)
863 );
864 }
865
866 #[test]
867 fn test_events_works() {
868 let addr = Address::Account(AccountHash::new([0; 32]));
869
870 let mut ctx = MockHostContext::new();
871 ctx.expect_get_events_count().returning(|_| 2);
873 ctx.expect_get_event()
875 .with(predicate::always(), predicate::eq(0))
876 .returning(|_, _| Ok(vec![1].into()));
877 ctx.expect_get_event()
879 .with(predicate::always(), predicate::eq(1))
880 .returning(|_, _| Ok(vec![1, 0, 1].into()));
881
882 let env = HostEnv::new(Rc::new(RefCell::new(ctx)));
883
884 assert_eq!(
885 env.events(&addr),
886 vec![vec![1].into(), vec![1, 0, 1].into()]
887 );
888 }
889
890 #[test]
891 #[should_panic(
892 expected = "Couldn't get event at address Account(AccountHash(0000000000000000000000000000000000000000000000000000000000000000)) with id 0: CouldntExtractEventData"
893 )]
894 fn test_events_fails() {
895 let addr = Address::Account(AccountHash::new([0; 32]));
896
897 let mut ctx = MockHostContext::new();
898 ctx.expect_get_events_count().returning(|_| 2);
900 ctx.expect_get_event()
902 .with(predicate::always(), predicate::eq(0))
903 .returning(|_, _| Err(EventError::CouldntExtractEventData));
904
905 let env = HostEnv::new(Rc::new(RefCell::new(ctx)));
906
907 env.events(&addr);
908 }
909
910 #[test]
911 fn test_emitted() {
912 let addr = Address::Account(AccountHash::new([0; 32]));
913 let mut ctx = MockHostContext::new();
914
915 ctx.expect_get_events_count().returning(|_| 1);
916 ctx.expect_get_event()
917 .returning(|_, _| Ok(TestEv {}.to_bytes().unwrap().into()));
918
919 let env = HostEnv::new(Rc::new(RefCell::new(ctx)));
920 assert!(env.emitted(&addr, "TestEv"));
921 assert!(!env.emitted(&addr, "AnotherEvent"));
922 }
923}