odra_core/
host.rs

1//! A module that provides the interface for interacting with the host environment.
2
3use 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
18/// A host side reference to a contract.
19pub trait HostRef {
20    /// Creates a new host side reference to a contract.
21    fn new(address: Address, env: HostEnv) -> Self;
22    /// Creates a new host reference with attached tokens, based on the current instance.
23    ///
24    /// If there are tokens attached to the current instance, the tokens will be attached
25    /// to the next contract call.
26    fn with_tokens(&self, tokens: U512) -> Self;
27    /// Returns the address of the contract.
28    fn contract_address(&self) -> Address;
29    /// Returns the host environment.
30    fn env(&self) -> &HostEnv;
31    /// Returns the n-th event emitted by the contract.
32    ///
33    /// If the event is not found or the type does not match, returns `EventError::EventNotFound`.
34    fn get_event<T>(&self, index: i32) -> Result<T, EventError>
35    where
36        T: FromBytes + EventInstance + 'static;
37    /// Returns a detailed information about the last call of the contract.
38    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
47/// Trait for loading a contract from the host environment.
48///
49/// Similar to [Deployer], but does not deploy a new contract, but loads an existing one.
50pub trait HostRefLoader<T: HostRef> {
51    /// Loads an existing contract from the host environment.
52    fn load(env: &HostEnv, address: Address) -> T;
53}
54
55/// A type which can provide an [EntryPointsCaller].
56pub trait EntryPointsCallerProvider {
57    /// Returns an [EntryPointsCaller] for the given host environment.
58    fn entry_points_caller(env: &HostEnv) -> EntryPointsCaller;
59}
60
61/// A type which can deploy a contract.
62///
63/// Before any interaction with the contract, it must be deployed, either
64/// on a virtual machine or on a real blockchain.
65///
66/// The `Deployer` trait provides a simple way to deploy a contract.
67#[cfg(not(target_arch = "wasm32"))]
68pub trait Deployer<R: OdraContract>: Sized {
69    /// Deploys a contract with given init args.
70    ///
71    /// If the `init_args` is not [NoArgs], the contract is deployed and initialized
72    /// by calling the constructor. Otherwise no constructor is called.
73    ///
74    /// The default [OdraConfig] is used for deployment.
75    ///
76    /// Returns a host reference to the deployed contract.
77    fn deploy(env: &HostEnv, init_args: R::InitArgs) -> R::HostRef;
78
79    /// Tries to deploy a contract with given init args.
80    ///
81    /// Similar to `deploy`, but returns a result instead of panicking.
82    fn try_deploy(env: &HostEnv, init_args: R::InitArgs) -> OdraResult<R::HostRef>;
83
84    /// Deploys a contract with given init args and configuration.
85    ///
86    /// Returns a host reference to the deployed contract.
87    fn deploy_with_cfg<T: OdraConfig>(env: &HostEnv, init_args: R::InitArgs, cfg: T) -> R::HostRef;
88
89    /// Tries to deploy a contract with given init args and configuration.
90    ///
91    /// Similar to `deploy_with_cfg`, but returns a result instead of panicking.
92    fn try_deploy_with_cfg<T: OdraConfig>(
93        env: &HostEnv,
94        init_args: R::InitArgs,
95        cfg: T
96    ) -> OdraResult<R::HostRef>;
97}
98
99/// A type which can be used as initialization arguments for a contract.
100pub trait InitArgs: Into<RuntimeArgs> {}
101
102/// Default implementation of [InitArgs]. Should be used when the contract
103/// does not require initialization arguments.
104///
105/// Precisely, it means the constructor function has not been defined,
106/// or does not require any arguments.
107pub 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/// A configuration for a contract.
118///
119/// The configuration every contract written in Odra expects.
120/// Read more: [https://odra.dev/docs/backends/casper/#wasm-arguments]
121pub trait OdraConfig {
122    /// Returns the package hash of the contract.
123    ///
124    /// Used to set the `odra_cfg_package_hash_key_name` key at the contract initialization.
125    fn package_hash(&self) -> String;
126    /// Returns true if the contract should be deployed as upgradable.
127    ///
128    /// If true, the `odra_cfg_is_upgradable` key is set to `true` at the contract initialization.
129    fn is_upgradable(&self) -> bool;
130    /// If true and the key `odra_cfg_package_hash_key_name` already exists, it should be overwritten.
131    fn allow_key_override(&self) -> bool;
132}
133
134#[cfg(not(target_arch = "wasm32"))]
135/// Default configuration for a contract.
136struct 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/// The `HostContext` trait defines the interface for interacting with the host environment.
231#[cfg_attr(test, mockall::automock)]
232pub trait HostContext {
233    /// Sets the caller address for the current contract execution.
234    fn set_caller(&self, caller: Address);
235
236    /// Sets the gas limit for the current contract execution.
237    fn set_gas(&self, gas: u64);
238
239    /// Returns the caller address for the current contract execution.
240    fn caller(&self) -> Address;
241
242    /// Returns the account address at the specified index.
243    fn get_account(&self, index: usize) -> Address;
244
245    /// Returns the validator public key.
246    fn get_validator(&self, index: usize) -> PublicKey;
247
248    /// The validator at the given index will withdraw all funds and be removed from the validator set.
249    fn remove_validator(&self, index: usize);
250
251    /// Returns the CSPR balance of the specified address.
252    fn balance_of(&self, address: &Address) -> U512;
253
254    /// Advances the block time by the specified time difference.
255    fn advance_block_time(&self, time_diff: u64);
256
257    /// Advances the block time by the specified time difference and processes auctions.
258    fn advance_with_auctions(&self, time_diff: u64);
259
260    /// Time between auctions in milliseconds.
261    fn auction_delay(&self) -> u64;
262
263    /// Time for the funds to be transferred back to the delegator after undelegation in milliseconds.
264    fn unbonding_delay(&self) -> u64;
265
266    /// Returns the delegated amount for the specified delegator and validator.
267    fn delegated_amount(&self, delegator: Address, validator: PublicKey) -> U512;
268
269    /// Returns the current block time.
270    fn block_time(&self) -> u64;
271
272    /// Returns the event bytes for the specified contract address and index.
273    fn get_event(&self, contract_address: &Address, index: u32) -> Result<Bytes, EventError>;
274
275    /// Returns the native event bytes for the specified contract address and index.
276    fn get_native_event(&self, contract_address: &Address, index: u32)
277        -> Result<Bytes, EventError>;
278
279    /// Returns the number of emitted events for the specified contract address.
280    fn get_events_count(&self, contract_address: &Address) -> Result<u32, EventError>;
281
282    /// Returns the number of emitted native events for the specified contract address.
283    fn get_native_events_count(&self, contract_address: &Address) -> Result<u32, EventError>;
284
285    /// Calls a contract at the specified address with the given call definition.
286    fn call_contract(
287        &self,
288        address: &Address,
289        call_def: CallDef,
290        use_proxy: bool
291    ) -> OdraResult<Bytes>;
292
293    /// Creates a new contract with the specified name, initialization arguments, and entry points caller.
294    fn new_contract(
295        &self,
296        name: &str,
297        init_args: RuntimeArgs,
298        entry_points_caller: EntryPointsCaller
299    ) -> OdraResult<Address>;
300
301    /// Registers an existing contract with the specified address, name, and entry points caller.
302    fn register_contract(
303        &self,
304        address: Address,
305        contract_name: String,
306        entry_points_caller: EntryPointsCaller
307    );
308
309    /// Returns the contract environment.
310    fn contract_env(&self) -> ContractEnv;
311
312    /// Returns the gas report for the current contract execution.
313    fn gas_report(&self) -> GasReport;
314
315    /// Returns the gas cost of the last contract call.
316    fn last_call_gas_cost(&self) -> u64;
317
318    /// Signs the specified message with the given address and returns the signature.
319    fn sign_message(&self, message: &Bytes, address: &Address) -> Bytes;
320
321    /// Returns the public key associated with the specified address.
322    fn public_key(&self, address: &Address) -> PublicKey;
323
324    /// Transfers the specified amount of CSPR from the current caller to the specified address.
325    fn transfer(&self, to: Address, amount: U512) -> OdraResult<()>;
326}
327
328/// Represents the host environment for executing smart contracts.
329///
330/// It provides methods for interacting with the underlying host context and managing
331/// the execution of contracts.
332#[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>>>, // contract_address -> events_count
338    native_events_count: Rc<RefCell<BTreeMap<Address, u32>>>, // contract_address -> events_count
339    events_initialized: Rc<RefCell<BTreeMap<Address, bool>>>,
340    captures_events: Rc<RefCell<bool>>
341}
342
343impl HostEnv {
344    /// Creates a new `HostEnv` instance with the specified backend.
345    pub fn new(backend: Rc<RefCell<dyn HostContext>>) -> HostEnv {
346        HostEnv {
347            backend,
348            last_call_result: RefCell::new(None).into(),
349            deployed_contracts: RefCell::new(vec![]).into(),
350            events_count: Rc::new(RefCell::new(Default::default())),
351            native_events_count: Rc::new(RefCell::new(Default::default())),
352            events_initialized: Rc::new(RefCell::new(Default::default())),
353            captures_events: Rc::new(RefCell::new(true))
354        }
355    }
356
357    /// Sets the `captures_events` flag, which determines whether events should be captured.
358    pub fn set_captures_events(&self, captures: bool) {
359        *self.captures_events.borrow_mut() = captures;
360        if captures {
361            // Initialize events for all deployed contracts if capturing is enabled
362            for contract in self.deployed_contracts.borrow().iter() {
363                self.init_events(contract);
364            }
365        }
366    }
367
368    /// Returns the account address at the specified index.
369    pub fn get_account(&self, index: usize) -> Address {
370        let backend = self.backend.borrow();
371        backend.get_account(index)
372    }
373
374    /// Returns the validator public key.
375    pub fn get_validator(&self, index: usize) -> PublicKey {
376        let backend = self.backend.borrow();
377        backend.get_validator(index)
378    }
379
380    /// Sets the caller address for the current contract execution.
381    pub fn set_caller(&self, address: Address) {
382        if address.is_contract() {
383            panic!("Caller cannot be a contract: {:?}", address)
384        }
385        let backend = self.backend.borrow();
386        backend.set_caller(address)
387    }
388
389    /// Advances the block time by the specified time difference.
390    pub fn advance_block_time(&self, time_diff: u64) {
391        let backend = self.backend.borrow();
392        backend.advance_block_time(time_diff)
393    }
394
395    /// Advances the block time by the specified time difference and processes auctions.
396    pub fn advance_with_auctions(&self, time_diff: u64) {
397        let backend = self.backend.borrow();
398        backend.advance_with_auctions(time_diff);
399    }
400
401    /// Returns the era length in milliseconds.
402    pub fn auction_delay(&self) -> u64 {
403        let backend = self.backend.borrow();
404        backend.auction_delay()
405    }
406
407    /// Returns the delay between unstaking and the transfer of funds back to the delegator in milliseconds.
408    pub fn unbonding_delay(&self) -> u64 {
409        let backend = self.backend.borrow();
410        backend.unbonding_delay()
411    }
412
413    /// Returns the amount of CSPR delegated to the specified validator by the specified delegator.
414    pub fn delegated_amount(&self, delegator: Address, validator: PublicKey) -> U512 {
415        let backend = self.backend.borrow();
416        backend.delegated_amount(delegator, validator)
417    }
418
419    /// Evicts the validator at the specified index from the validator set.
420    pub fn remove_validator(&self, index: usize) {
421        let backend = self.backend.borrow();
422        backend.remove_validator(index);
423    }
424
425    /// Returns the current block time in milliseconds.
426    pub fn block_time(&self) -> u64 {
427        let backend = self.backend.borrow();
428        backend.block_time()
429    }
430
431    /// Returns the current block time in milliseconds.
432    pub fn block_time_millis(&self) -> u64 {
433        let backend = self.backend.borrow();
434        backend.block_time()
435    }
436
437    /// Returns the current block time in seconds.
438    pub fn block_time_secs(&self) -> u64 {
439        let backend = self.backend.borrow();
440        backend.block_time().checked_div(1000).unwrap()
441    }
442
443    /// Registers a new contract with the specified name, initialization arguments, and entry points caller.
444    pub fn new_contract(
445        &self,
446        name: &str,
447        init_args: RuntimeArgs,
448        entry_points_caller: EntryPointsCaller
449    ) -> OdraResult<Address> {
450        let backend = self.backend.borrow();
451        let deployed_contract = backend.new_contract(name, init_args, entry_points_caller)?;
452
453        self.deployed_contracts.borrow_mut().push(deployed_contract);
454        self.events_count.borrow_mut().insert(deployed_contract, 0);
455        self.native_events_count
456            .borrow_mut()
457            .insert(deployed_contract, 0);
458        self.events_initialized
459            .borrow_mut()
460            .insert(deployed_contract, true);
461        Ok(deployed_contract)
462    }
463
464    /// Registers an existing contract with the specified address, name and entry points caller.
465    /// Similar to `new_contract`, but skips the deployment phase.
466    pub fn register_contract(
467        &self,
468        address: Address,
469        contract_name: String,
470        entry_points_caller: EntryPointsCaller
471    ) {
472        let backend = self.backend.borrow();
473        backend.register_contract(address, contract_name, entry_points_caller);
474        self.deployed_contracts.borrow_mut().push(address);
475    }
476
477    /// Calls a contract at the specified address with the given call definition.
478    pub fn call_contract<T: FromBytes + CLTyped>(
479        &self,
480        address: Address,
481        call_def: CallDef
482    ) -> OdraResult<T> {
483        let use_proxy = T::cl_type() != <()>::cl_type() || !call_def.amount().is_zero();
484        let call_result = self.raw_call_contract(address, call_def, use_proxy);
485        call_result.map(|bytes| {
486            T::from_bytes(&bytes)
487                .map(|(obj, _)| obj)
488                .map_err(|_| OdraError::VmError(VmError::Deserialization))
489        })?
490    }
491
492    /// Calls a contract at the specified address with the given call definition. Returns raw,
493    /// not serialized bytes.
494    pub fn raw_call_contract(
495        &self,
496        address: Address,
497        call_def: CallDef,
498        use_proxy: bool
499    ) -> OdraResult<Bytes> {
500        let backend = self.backend.borrow();
501        let call_result = backend.call_contract(&address, call_def, use_proxy);
502
503        let mut events_map: BTreeMap<Address, Vec<Bytes>> = BTreeMap::new();
504        let mut native_events_map: BTreeMap<Address, Vec<Bytes>> = BTreeMap::new();
505
506        let captures_events = *self.captures_events.borrow();
507        if captures_events {
508            // Go through all contracts and collect their events
509            self.deployed_contracts
510                .borrow()
511                .iter()
512                .for_each(|contract_address| {
513                    let events = self.last_events(contract_address);
514                    let native_events = self.last_native_events(contract_address);
515                    events_map.insert(*contract_address, events);
516                    native_events_map.insert(*contract_address, native_events);
517                });
518        }
519
520        let last_call_gas_cost = backend.last_call_gas_cost();
521
522        self.last_call_result.replace(Some(CallResult::new(
523            address,
524            backend.caller(),
525            last_call_gas_cost,
526            call_result.clone(),
527            events_map,
528            native_events_map
529        )));
530
531        call_result
532    }
533
534    /// Returns the gas cost of the last contract call.
535    pub fn contract_env(&self) -> ContractEnv {
536        self.backend.borrow().contract_env()
537    }
538
539    /// Prints the gas report for the current contract execution.
540    pub fn gas_report(&self) -> GasReport {
541        self.backend.borrow().gas_report().clone()
542    }
543
544    /// Returns the CSPR balance of the specified address.
545    pub fn balance_of<T: Addressable>(&self, addr: &T) -> U512 {
546        let backend = self.backend.borrow();
547        backend.balance_of(&addr.address())
548    }
549
550    /// Retrieves an event with the specified index from the specified contract.
551    ///
552    /// # Returns
553    ///
554    /// Returns the event as an instance of the specified type, or an error if the event
555    /// couldn't be retrieved or parsed.
556    pub fn get_event<T: FromBytes + EventInstance, R: Addressable>(
557        &self,
558        addr: &R,
559        index: i32
560    ) -> Result<T, EventError> {
561        let contract_address = addr.address();
562        let backend = self.backend.borrow();
563        let events_count = self.events_count(&contract_address);
564        let event_absolute_position = crate::utils::event_absolute_position(events_count, index)
565            .ok_or(EventError::IndexOutOfBounds)?;
566
567        let bytes = backend.get_event(&contract_address, event_absolute_position)?;
568        T::from_bytes(&bytes)
569            .map_err(|_| EventError::Parsing)
570            .map(|r| r.0)
571    }
572
573    /// Retrieves a native event with the specified index from the specified contract.
574    ///
575    /// # Returns
576    ///
577    /// Returns the event as an instance of the specified type, or an error if the event
578    /// couldn't be retrieved or parsed.
579    pub fn get_native_event<T: FromBytes + EventInstance, R: Addressable>(
580        &self,
581        addr: &R,
582        index: i32
583    ) -> Result<T, EventError> {
584        let contract_address = addr.address();
585        let backend = self.backend.borrow();
586        let events_count = self.native_events_count(&contract_address);
587        let event_absolute_position = crate::utils::event_absolute_position(events_count, index)
588            .ok_or(EventError::IndexOutOfBounds)?;
589
590        let bytes = backend.get_native_event(&contract_address, event_absolute_position)?;
591        T::from_bytes(&bytes)
592            .map_err(|_| EventError::Parsing)
593            .map(|r| r.0)
594    }
595
596    /// Retrieves a raw event (serialized) with the specified index from the specified contract.
597    pub fn get_event_bytes<T: Addressable>(
598        &self,
599        addr: &T,
600        index: u32
601    ) -> Result<Bytes, EventError> {
602        let backend = self.backend.borrow();
603        backend.get_event(&addr.address(), index)
604    }
605
606    /// Retrieves a raw native event (serialized) with the specified index from the specified contract.
607    pub fn get_native_event_bytes<T: Addressable>(
608        &self,
609        addr: &T,
610        index: u32
611    ) -> Result<Bytes, EventError> {
612        let backend = self.backend.borrow();
613        backend.get_native_event(&addr.address(), index)
614    }
615
616    /// Returns the names of all events emitted by the specified contract.
617    pub fn event_names<T: Addressable>(&self, addr: &T) -> Vec<String> {
618        let events_count = self.events_count(addr);
619
620        let backend = self.backend.borrow();
621        (0..events_count)
622            .map(|event_id| {
623                backend
624                    .get_event(&addr.address(), event_id)
625                    .and_then(|bytes| utils::extract_event_name(&bytes))
626                    .unwrap_or_else(|e| panic!("Couldn't extract event name: {:?}", e))
627            })
628            .collect()
629    }
630
631    /// Returns all events emitted by the specified contract.
632    pub fn events<T: Addressable>(&self, addr: &T) -> Vec<Bytes> {
633        let backend = self.backend.borrow();
634        let contract_address = addr.address();
635        let events_count = backend
636            .get_events_count(&contract_address)
637            .unwrap_or_default();
638        (0..events_count)
639            .map(|event_id| {
640                backend
641                    .get_event(&contract_address, event_id)
642                    .unwrap_or_else(|e| {
643                        panic!(
644                            "Couldn't get event at address {:?} with id {}: {:?}",
645                            &contract_address, event_id, e
646                        )
647                    })
648            })
649            .collect()
650    }
651
652    /// Returns the number of events emitted by the specified contract.
653    pub fn events_count<T: Addressable>(&self, addr: &T) -> u32 {
654        let backend = self.backend.borrow();
655        backend
656            .get_events_count(&addr.address())
657            .unwrap_or_default()
658    }
659
660    /// Returns the number of native events emitted by the specified contract.
661    pub fn native_events_count<T: Addressable>(&self, addr: &T) -> u32 {
662        let backend = self.backend.borrow();
663        backend
664            .get_native_events_count(&addr.address())
665            .unwrap_or_default()
666    }
667
668    /// Returns true if the specified event was emitted by the specified contract.
669    pub fn emitted_event<T: ToBytes + EventInstance, R: Addressable>(
670        &self,
671        addr: &R,
672        event: T
673    ) -> bool {
674        let contract_address = addr.address();
675        let events_count = self.events_count(addr);
676
677        let event_bytes = Bytes::from(
678            event
679                .to_bytes()
680                .unwrap_or_else(|_| panic!("Couldn't serialize event"))
681        );
682
683        (0..events_count)
684            .map(|event_id| {
685                self.get_event_bytes(&contract_address, event_id)
686                    .unwrap_or_else(|e| {
687                        panic!(
688                            "Couldn't get event at address {:?} with id {}: {:?}",
689                            &contract_address, event_id, e
690                        )
691                    })
692            })
693            .any(|bytes| bytes == event_bytes)
694    }
695
696    /// Returns true if the specified event was emitted by the specified contract.
697    pub fn emitted_native_event<T: ToBytes + EventInstance, R: Addressable>(
698        &self,
699        addr: &R,
700        event: T
701    ) -> bool {
702        let contract_address = addr.address();
703        let events_count = self.native_events_count(addr);
704        if events_count > 0 {
705            let event_bytes = Bytes::from(
706                event
707                    .to_bytes()
708                    .unwrap_or_else(|_| panic!("Couldn't serialize event"))
709            );
710            (0..events_count)
711                .map(|event_id| {
712                    self.get_native_event_bytes(&contract_address, event_id)
713                        .unwrap_or_else(|e| {
714                            panic!(
715                                "Couldn't get event at address {:?} with id {}: {:?}",
716                                &contract_address, event_id, e
717                            )
718                        })
719                })
720                .any(|bytes| bytes == event_bytes)
721        } else {
722            false
723        }
724    }
725
726    /// Returns true if an event with the specified name was emitted by the specified contract.
727    pub fn emitted<T: AsRef<str>, R: Addressable>(&self, addr: &R, event_name: T) -> bool {
728        let events_count = self.events_count(addr);
729
730        (0..events_count)
731            .map(|event_id| {
732                self.get_event_bytes(addr, event_id).unwrap_or_else(|e| {
733                    panic!(
734                        "Couldn't get event at address {:?} with id {}: {:?}",
735                        addr.address(),
736                        event_id,
737                        e
738                    )
739                })
740            })
741            .any(|bytes| {
742                utils::extract_event_name(&bytes)
743                    .unwrap_or_else(|e| panic!("Couldn't extract event name: {:?}", e))
744                    .as_str()
745                    == event_name.as_ref()
746            })
747    }
748    /// Returns true if a native event with the specified name was emitted by the specified contract.
749    pub fn emitted_native<T: AsRef<str>, R: Addressable>(&self, addr: &R, event_name: T) -> bool {
750        let events_count = self.native_events_count(addr);
751
752        (0..events_count)
753            .map(|event_id| {
754                self.get_native_event_bytes(addr, event_id)
755                    .unwrap_or_else(|e| {
756                        panic!(
757                            "Couldn't get event at address {:?} with id {}: {:?}",
758                            addr.address(),
759                            event_id,
760                            e
761                        )
762                    })
763            })
764            .any(|bytes| {
765                utils::extract_event_name(&bytes)
766                    .unwrap_or_else(|e| panic!("Couldn't extract event name: {:?}", e))
767                    .as_str()
768                    == event_name.as_ref()
769            })
770    }
771
772    /// Returns the last call result for the specified contract.
773    pub fn last_call_result(&self, contract_address: Address) -> ContractCallResult {
774        self.last_call_result
775            .borrow()
776            .clone()
777            .unwrap()
778            .contract_last_call(contract_address)
779    }
780
781    /// Signs the specified message with the private key of the specified address.
782    pub fn sign_message(&self, message: &Bytes, address: &Address) -> Bytes {
783        let backend = self.backend.borrow();
784        backend.sign_message(message, address)
785    }
786
787    /// Returns the public key associated with the specified address.
788    pub fn public_key(&self, address: &Address) -> PublicKey {
789        let backend = self.backend.borrow();
790        backend.public_key(address)
791    }
792
793    /// Returns the caller address for the current contract execution.
794    pub fn caller(&self) -> Address {
795        let backend = self.backend.borrow();
796        backend.caller()
797    }
798
799    /// Sets the gas limit for the current contract execution.
800    pub fn set_gas(&self, gas: u64) {
801        let backend = self.backend.borrow();
802        backend.set_gas(gas)
803    }
804
805    /// Transfers the specified amount of CSPR from the current caller to the specified address.
806    pub fn transfer(&self, to: Address, amount: U512) -> OdraResult<()> {
807        if to.is_contract() {
808            return Err(OdraError::ExecutionError(
809                ExecutionError::TransferToContract
810            ));
811        }
812        let backend = self.backend.borrow();
813        backend.transfer(to, amount)
814    }
815
816    fn last_events(&self, contract_address: &Address) -> Vec<Bytes> {
817        let mut old_count_binding = self.events_count.borrow_mut();
818        let old_count = *old_count_binding
819            .get(contract_address)
820            .expect("Contract address not found in events count");
821        let new_count = self.events_count(contract_address);
822        let mut events = vec![];
823        for count in old_count..new_count {
824            let event = self.get_event_bytes(contract_address, count).unwrap();
825            events.push(event);
826        }
827
828        old_count_binding.insert(*contract_address, new_count);
829        events
830    }
831
832    fn last_native_events(&self, contract_address: &Address) -> Vec<Bytes> {
833        let mut old_count_binding = self.native_events_count.borrow_mut();
834        let old_count = *old_count_binding.get(contract_address).unwrap();
835        let new_count = self.native_events_count(contract_address);
836        let mut events = vec![];
837        for count in old_count..new_count {
838            let event = self
839                .get_native_event_bytes(contract_address, count)
840                .unwrap();
841            events.push(event);
842        }
843
844        old_count_binding.insert(*contract_address, new_count);
845        events
846    }
847
848    fn init_events(&self, contract_address: &Address) {
849        let events_initialized = self
850            .events_initialized
851            .borrow()
852            .get(contract_address)
853            .copied()
854            .unwrap_or(false);
855        if !events_initialized {
856            self.events_count
857                .borrow_mut()
858                .insert(*contract_address, self.events_count(contract_address));
859            self.native_events_count.borrow_mut().insert(
860                *contract_address,
861                self.native_events_count(contract_address)
862            );
863            self.events_initialized
864                .borrow_mut()
865                .insert(*contract_address, true);
866        }
867    }
868}
869
870#[cfg(test)]
871mod test {
872    use core::fmt::Debug;
873
874    use super::*;
875    use casper_event_standard::Event;
876    use casper_types::account::AccountHash;
877    use casper_types::contracts::ContractPackageHash;
878    use mockall::{mock, predicate};
879    use std::sync::Mutex;
880
881    static IDENT_MTX: Mutex<()> = Mutex::new(());
882    static EPC_MTX: Mutex<()> = Mutex::new(());
883
884    #[derive(Debug, Event, PartialEq)]
885    struct TestEv {}
886
887    mock! {
888        TestRef {}
889        impl HasIdent for TestRef {
890            fn ident() -> String;
891        }
892        impl EntryPointsCallerProvider for TestRef {
893            fn entry_points_caller(env: &HostEnv) -> EntryPointsCaller;
894        }
895        impl HostRef for TestRef {
896            fn new(address: Address, env: HostEnv) -> Self;
897            fn with_tokens(&self, tokens: U512) -> Self;
898            fn contract_address(&self) -> Address;
899            fn env(&self) -> &HostEnv;
900            fn get_event<T>(&self, index: i32) -> Result<T, EventError> where T: FromBytes + EventInstance + 'static;
901            fn last_call(&self) -> ContractCallResult;
902        }
903    }
904
905    impl crate::ContractRef for MockTestRef {
906        fn new(_env: Rc<ContractEnv>, _address: Address) -> Self {
907            unimplemented!()
908        }
909        fn address(&self) -> &Address {
910            unimplemented!()
911        }
912
913        fn with_tokens(&self, _tokens: U512) -> Self {
914            unimplemented!()
915        }
916    }
917
918    impl OdraContract for MockTestRef {
919        type HostRef = MockTestRef;
920
921        type ContractRef = MockTestRef;
922
923        type InitArgs = NoArgs;
924    }
925
926    mock! {
927        Ev {}
928        impl Into<RuntimeArgs> for Ev {
929            fn into(self) -> RuntimeArgs;
930        }
931    }
932
933    #[test]
934    fn test_deploy_with_default_args() {
935        // MockTestRef::ident() and  MockTestRef::entry_points_caller() are static and can't be safely used
936        // from multiple tests at the same time. Should be to protected with a Mutex. Each function has
937        // a separate Mutex.
938        // https://github.com/asomers/mockall/blob/master/mockall/tests/mock_struct_with_static_method.rs
939        let _i = IDENT_MTX.lock();
940        let _e = EPC_MTX.lock();
941
942        // stubs
943        let indent_ctx = MockTestRef::ident_context();
944        indent_ctx.expect().returning(|| "TestRef".to_string());
945
946        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
951        // check if TestRef::new() is called exactly once
952        let instance_ctx = MockTestRef::new_context();
953        instance_ctx
954            .expect()
955            .times(1)
956            .returning(|_, _| MockTestRef::default());
957
958        let mut ctx = MockHostContext::new();
959        ctx.expect_new_contract()
960            .returning(|_, _, _| Ok(Address::Account(AccountHash::new([0; 32]))));
961        let env = HostEnv::new(Rc::new(RefCell::new(ctx)));
962        MockTestRef::deploy(&env, NoArgs);
963    }
964
965    #[test]
966    fn test_load_ref() {
967        // MockTestRef::ident() and MockTestRef::entry_points_caller() are static and can't be safely used
968        // from multiple tests at the same time. Should be to protected with a Mutex. Each function has
969        // a separate Mutex.
970        // https://github.com/asomers/mockall/blob/master/mockall/tests/mock_struct_with_static_method.rs
971        let _e = EPC_MTX.lock();
972        let _i = IDENT_MTX.lock();
973
974        // stubs
975        let epc_ctx = MockTestRef::entry_points_caller_context();
976        epc_ctx
977            .expect()
978            .returning(|h| EntryPointsCaller::new(h.clone(), vec![], |_, _| Ok(Bytes::default())));
979        let indent_ctx = MockTestRef::ident_context();
980        indent_ctx.expect().returning(|| "TestRef".to_string());
981
982        let mut ctx = MockHostContext::new();
983        ctx.expect_register_contract().returning(|_, _, _| ());
984        ctx.expect_get_events_count().returning(|_| Ok(0));
985        ctx.expect_get_native_events_count().returning(|_| Ok(0));
986
987        // check if TestRef::new() is called exactly once
988        let instance_ctx = MockTestRef::new_context();
989        instance_ctx
990            .expect()
991            .times(1)
992            .returning(|_, _| MockTestRef::default());
993
994        let env = HostEnv::new(Rc::new(RefCell::new(ctx)));
995        let address = Address::Account(AccountHash::new([0; 32]));
996        MockTestRef::load(&env, address);
997    }
998
999    #[test]
1000    fn test_host_env() {
1001        let mut ctx = MockHostContext::new();
1002        ctx.expect_new_contract()
1003            .returning(|_, _, _| Ok(Address::Account(AccountHash::new([0; 32]))));
1004        ctx.expect_caller()
1005            .returning(|| Address::Account(AccountHash::new([2; 32])))
1006            .times(1);
1007        ctx.expect_gas_report().returning(GasReport::new).times(1);
1008        ctx.expect_set_gas().returning(|_| ()).times(1);
1009
1010        let env = HostEnv::new(Rc::new(RefCell::new(ctx)));
1011
1012        assert_eq!(env.caller(), Address::Account(AccountHash::new([2; 32])));
1013        // should call the `HostContext`
1014        env.gas_report();
1015        env.set_gas(1_000u64)
1016    }
1017
1018    #[test]
1019    fn test_successful_transfer_to_account() {
1020        // Given a host context that successfully transfers tokens.
1021        let mut ctx = MockHostContext::new();
1022        ctx.expect_transfer().returning(|_, _| Ok(()));
1023        let env = HostEnv::new(Rc::new(RefCell::new(ctx)));
1024
1025        let addr = Address::Account(AccountHash::new([0; 32]));
1026        // When transfer 100 tokens to an account.
1027        let result = env.transfer(addr, 100.into());
1028        // Then the transfer should be successful.
1029        assert!(result.is_ok());
1030    }
1031
1032    #[test]
1033    fn test_failing_transfer_to_account() {
1034        // Given a host context that fails to transfer tokens.
1035        let mut ctx = MockHostContext::new();
1036        ctx.expect_transfer()
1037            .returning(|_, _| Err(OdraError::ExecutionError(ExecutionError::UnwrapError)));
1038        let env = HostEnv::new(Rc::new(RefCell::new(ctx)));
1039
1040        let addr = Address::Account(AccountHash::new([0; 32]));
1041        // When transfer 100 tokens to an account.
1042        let result = env.transfer(addr, 100.into());
1043        // Then the transfer should fail.
1044        assert_eq!(
1045            result.err(),
1046            Some(OdraError::ExecutionError(ExecutionError::UnwrapError))
1047        );
1048    }
1049
1050    #[test]
1051    fn test_transfer_to_contract() {
1052        // Given a host context that successfully transfers tokens.
1053        let mut ctx = MockHostContext::new();
1054        ctx.expect_transfer().returning(|_, _| Ok(()));
1055        let env = HostEnv::new(Rc::new(RefCell::new(ctx)));
1056
1057        let addr = Address::Contract(ContractPackageHash::new([0; 32]));
1058        // When transfer 100 tokens to a contract.
1059        let result = env.transfer(addr, 100.into());
1060        // Then the transfer should fail.
1061        assert_eq!(
1062            result,
1063            Err(OdraError::ExecutionError(
1064                ExecutionError::TransferToContract
1065            ))
1066        );
1067    }
1068
1069    #[test]
1070    fn test_get_event() {
1071        let addr = Address::Account(AccountHash::new([0; 32]));
1072
1073        let mut ctx = MockHostContext::new();
1074        // there are 2 events emitted by the contract
1075        ctx.expect_get_events_count().returning(|_| Ok(2));
1076        // get_event() at index 0 will return an invalid event
1077        ctx.expect_get_event()
1078            .with(predicate::always(), predicate::eq(0))
1079            .returning(|_, _| Ok(vec![1].into()));
1080        // get_event() at index 1 will return an valid event
1081        ctx.expect_get_event()
1082            .with(predicate::always(), predicate::eq(1))
1083            .returning(|_, _| Ok(TestEv {}.to_bytes().unwrap().into()));
1084
1085        let env = HostEnv::new(Rc::new(RefCell::new(ctx)));
1086
1087        assert_eq!(env.get_event(&addr, 1), Ok(TestEv {}));
1088        assert_eq!(env.get_event(&addr, -1), Ok(TestEv {}));
1089        assert_eq!(
1090            env.get_event::<TestEv, _>(&addr, 0),
1091            Err(EventError::Parsing)
1092        );
1093        assert_eq!(
1094            env.get_event::<TestEv, _>(&addr, -2),
1095            Err(EventError::Parsing)
1096        );
1097        assert_eq!(
1098            env.get_event::<TestEv, _>(&addr, 2),
1099            Err(EventError::IndexOutOfBounds)
1100        );
1101        assert_eq!(
1102            env.get_event::<TestEv, _>(&addr, -3),
1103            Err(EventError::IndexOutOfBounds)
1104        );
1105    }
1106
1107    #[test]
1108    fn test_events_works() {
1109        let addr = Address::Account(AccountHash::new([0; 32]));
1110
1111        let mut ctx = MockHostContext::new();
1112        // there are 2 events emitted by the contract
1113        ctx.expect_get_events_count().returning(|_| Ok(2));
1114        // get_event() at index 0 will return an invalid event
1115        ctx.expect_get_event()
1116            .with(predicate::always(), predicate::eq(0))
1117            .returning(|_, _| Ok(vec![1].into()));
1118        // get_event() at index 1 will return an valid event
1119        ctx.expect_get_event()
1120            .with(predicate::always(), predicate::eq(1))
1121            .returning(|_, _| Ok(vec![1, 0, 1].into()));
1122
1123        let env = HostEnv::new(Rc::new(RefCell::new(ctx)));
1124
1125        assert_eq!(
1126            env.events(&addr),
1127            vec![vec![1].into(), vec![1, 0, 1].into()]
1128        );
1129    }
1130
1131    #[test]
1132    #[should_panic(
1133        expected = "Couldn't get event at address Account(AccountHash(0000000000000000000000000000000000000000000000000000000000000000)) with id 0: CouldntExtractEventData"
1134    )]
1135    fn test_events_fails() {
1136        let addr = Address::Account(AccountHash::new([0; 32]));
1137
1138        let mut ctx = MockHostContext::new();
1139        // there are 2 events emitted by the contract
1140        ctx.expect_get_events_count().returning(|_| Ok(2));
1141        // get_event() at index 0 panics
1142        ctx.expect_get_event()
1143            .with(predicate::always(), predicate::eq(0))
1144            .returning(|_, _| Err(EventError::CouldntExtractEventData));
1145
1146        let env = HostEnv::new(Rc::new(RefCell::new(ctx)));
1147
1148        env.events(&addr);
1149    }
1150
1151    #[test]
1152    fn test_emitted() {
1153        let addr = Address::Account(AccountHash::new([0; 32]));
1154        let mut ctx = MockHostContext::new();
1155
1156        ctx.expect_get_events_count().returning(|_| Ok(1));
1157        ctx.expect_get_event()
1158            .returning(|_, _| Ok(TestEv {}.to_bytes().unwrap().into()));
1159
1160        let env = HostEnv::new(Rc::new(RefCell::new(ctx)));
1161        assert!(env.emitted(&addr, "TestEv"));
1162        assert!(!env.emitted(&addr, "AnotherEvent"));
1163    }
1164}