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