casper_execution_engine/runtime_context/
mod.rs

1//! The context of execution of WASM code.
2
3#[cfg(test)]
4mod tests;
5
6use std::{
7    cell::RefCell,
8    collections::BTreeSet,
9    convert::{TryFrom, TryInto},
10    fmt::Debug,
11    rc::Rc,
12};
13
14use tracing::error;
15
16use casper_storage::{
17    global_state::{error::Error as GlobalStateError, state::StateReader},
18    tracking_copy::{
19        AddResult, TrackingCopy, TrackingCopyCache, TrackingCopyEntityExt, TrackingCopyError,
20        TrackingCopyExt,
21    },
22    AddressGenerator,
23};
24
25use casper_types::{
26    account::{
27        Account, AccountHash, AddKeyFailure, RemoveKeyFailure, SetThresholdFailure,
28        UpdateKeyFailure,
29    },
30    addressable_entity::{
31        ActionType, EntityKindTag, MessageTopicError, MessageTopics, NamedKeyAddr, NamedKeyValue,
32        Weight,
33    },
34    bytesrepr::ToBytes,
35    contract_messages::{Message, MessageAddr, MessageTopicSummary, Messages, TopicNameHash},
36    contracts::{ContractHash, ContractPackage, ContractPackageHash, NamedKeys},
37    execution::Effects,
38    handle_stored_dictionary_value,
39    system::auction::EraInfo,
40    AccessRights, AddressableEntity, AddressableEntityHash, BlockTime, CLType, CLValue,
41    CLValueDictionary, ContextAccessRights, Contract, EntityAddr, EntryPointAddr, EntryPointType,
42    EntryPointValue, EntryPoints, Gas, GrantedAccess, HashAddr, Key, KeyTag, Motes, Package,
43    PackageHash, Phase, ProtocolVersion, RuntimeArgs, RuntimeFootprint, StoredValue,
44    StoredValueTypeMismatch, SystemHashRegistry, TransactionHash, Transfer, URef, URefAddr,
45    DICTIONARY_ITEM_KEY_MAX_LENGTH, KEY_HASH_LENGTH, U512,
46};
47
48use crate::{
49    engine_state::{BlockInfo, EngineConfig},
50    execution::ExecError,
51};
52
53/// Number of bytes returned from the `random_bytes` function.
54pub const RANDOM_BYTES_COUNT: usize = 32;
55
56/// Whether the execution is permitted to call FFI `casper_add_contract_version()` or not.
57#[derive(Copy, Clone, PartialEq, Eq, Debug)]
58pub enum AllowInstallUpgrade {
59    /// Allowed.
60    Allowed,
61    /// Forbidden.
62    Forbidden,
63}
64
65/// Holds information specific to the deployed contract.
66pub struct RuntimeContext<'a, R> {
67    tracking_copy: Rc<RefCell<TrackingCopy<R>>>,
68    // Enables look up of specific uref based on human-readable name
69    named_keys: &'a mut NamedKeys,
70    // Used to check uref is known before use (prevents forging urefs)
71    access_rights: ContextAccessRights,
72    args: RuntimeArgs,
73    authorization_keys: BTreeSet<AccountHash>,
74    block_info: BlockInfo,
75    transaction_hash: TransactionHash,
76    gas_limit: Gas,
77    gas_counter: Gas,
78    address_generator: Rc<RefCell<AddressGenerator>>,
79    phase: Phase,
80    engine_config: EngineConfig,
81    entry_point_type: EntryPointType,
82    transfers: Vec<Transfer>,
83    remaining_spending_limit: U512,
84
85    // Original account/contract for read only tasks taken before execution
86    runtime_footprint: Rc<RefCell<RuntimeFootprint>>,
87    // Key pointing to the account / contract / entity context this instance is tied to
88    context_key: Key,
89    account_hash: AccountHash,
90    emit_message_cost: U512,
91    allow_install_upgrade: AllowInstallUpgrade,
92    payment_purse: Option<URef>,
93}
94
95impl<'a, R> RuntimeContext<'a, R>
96where
97    R: StateReader<Key, StoredValue, Error = GlobalStateError>,
98{
99    /// Creates new runtime context where we don't already have one.
100    ///
101    /// Where we already have a runtime context, consider using `new_from_self()`.
102    #[allow(clippy::too_many_arguments)]
103    pub fn new(
104        named_keys: &'a mut NamedKeys,
105        runtime_footprint: Rc<RefCell<RuntimeFootprint>>,
106        context_key: Key,
107        authorization_keys: BTreeSet<AccountHash>,
108        access_rights: ContextAccessRights,
109        account_hash: AccountHash,
110        address_generator: Rc<RefCell<AddressGenerator>>,
111        tracking_copy: Rc<RefCell<TrackingCopy<R>>>,
112        engine_config: EngineConfig,
113        block_info: BlockInfo,
114        transaction_hash: TransactionHash,
115        phase: Phase,
116        args: RuntimeArgs,
117        gas_limit: Gas,
118        gas_counter: Gas,
119        transfers: Vec<Transfer>,
120        remaining_spending_limit: U512,
121        entry_point_type: EntryPointType,
122        allow_install_upgrade: AllowInstallUpgrade,
123    ) -> Self {
124        let emit_message_cost = (*engine_config.wasm_config().v1())
125            .take_host_function_costs()
126            .emit_message
127            .cost()
128            .into();
129        RuntimeContext {
130            tracking_copy,
131            entry_point_type,
132            named_keys,
133            access_rights,
134            args,
135            runtime_footprint,
136            context_key,
137            authorization_keys,
138            account_hash,
139            block_info,
140            transaction_hash,
141            gas_limit,
142            gas_counter,
143            address_generator,
144            phase,
145            engine_config,
146            transfers,
147            remaining_spending_limit,
148            emit_message_cost,
149            allow_install_upgrade,
150            payment_purse: None,
151        }
152    }
153
154    /// Creates new runtime context cloning values from self.
155    #[allow(clippy::too_many_arguments)]
156    pub fn new_from_self(
157        &self,
158        context_key: Key,
159        entry_point_type: EntryPointType,
160        named_keys: &'a mut NamedKeys,
161        access_rights: ContextAccessRights,
162        runtime_args: RuntimeArgs,
163    ) -> Self {
164        let runtime_footprint = self.runtime_footprint.clone();
165        let authorization_keys = self.authorization_keys.clone();
166        let account_hash = self.account_hash;
167
168        let address_generator = self.address_generator.clone();
169        let tracking_copy = self.state();
170        let engine_config = self.engine_config.clone();
171
172        let block_info = self.block_info;
173        let transaction_hash = self.transaction_hash;
174        let phase = self.phase;
175
176        let gas_limit = self.gas_limit;
177        let gas_counter = self.gas_counter;
178        let remaining_spending_limit = self.remaining_spending_limit();
179
180        let transfers = self.transfers.clone();
181        let payment_purse = self.payment_purse;
182
183        RuntimeContext {
184            tracking_copy,
185            entry_point_type,
186            named_keys,
187            access_rights,
188            args: runtime_args,
189            runtime_footprint,
190            context_key,
191            authorization_keys,
192            account_hash,
193            block_info,
194            transaction_hash,
195            gas_limit,
196            gas_counter,
197            address_generator,
198            phase,
199            engine_config,
200            transfers,
201            remaining_spending_limit,
202            emit_message_cost: self.emit_message_cost,
203            allow_install_upgrade: self.allow_install_upgrade,
204            payment_purse,
205        }
206    }
207
208    /// Returns all authorization keys for this deploy.
209    pub fn authorization_keys(&self) -> &BTreeSet<AccountHash> {
210        &self.authorization_keys
211    }
212
213    /// Returns a named key by a name if it exists.
214    pub fn named_keys_get(&self, name: &str) -> Option<&Key> {
215        self.named_keys.get(name)
216    }
217
218    /// Returns named keys.
219    pub fn named_keys(&self) -> &NamedKeys {
220        self.named_keys
221    }
222
223    /// Returns a mutable reference to named keys.
224    pub fn named_keys_mut(&mut self) -> &mut NamedKeys {
225        self.named_keys
226    }
227
228    /// Checks if named keys contains a key referenced by name.
229    pub fn named_keys_contains_key(&self, name: &str) -> bool {
230        self.named_keys.contains(name)
231    }
232
233    /// Returns the payment purse, if set.
234    pub fn maybe_payment_purse(&self) -> Option<URef> {
235        self.payment_purse
236    }
237
238    /// Sets the payment purse to the imputed uref.
239    pub fn set_payment_purse(&mut self, uref: URef) {
240        self.payment_purse = Some(uref);
241    }
242
243    /// Returns an instance of the engine config.
244    pub fn engine_config(&self) -> &EngineConfig {
245        &self.engine_config
246    }
247
248    /// Helper function to avoid duplication in `remove_uref`.
249    fn remove_key_from_contract(
250        &mut self,
251        key: Key,
252        mut contract: Contract,
253        name: &str,
254    ) -> Result<(), ExecError> {
255        if contract.remove_named_key(name).is_none() {
256            return Ok(());
257        }
258        self.metered_write_gs_unsafe(key, contract)?;
259        Ok(())
260    }
261
262    /// Helper function to avoid duplication in `remove_uref`.
263    fn remove_key_from_entity(&mut self, name: &str) -> Result<(), ExecError> {
264        let key = self.context_key;
265        match key {
266            Key::AddressableEntity(entity_addr) => {
267                let named_key =
268                    NamedKeyAddr::new_from_string(entity_addr, name.to_string())?.into();
269                if let Some(StoredValue::NamedKey(_)) = self.read_gs(&named_key)? {
270                    self.prune_gs_unsafe(named_key);
271                }
272            }
273            account_hash @ Key::Account(_) => {
274                let account: Account = {
275                    let mut account: Account = self.read_gs_typed(&account_hash)?;
276                    account.named_keys_mut().remove(name);
277                    account
278                };
279                self.named_keys.remove(name);
280                let account_value = self.account_to_validated_value(account)?;
281                self.metered_write_gs_unsafe(account_hash, account_value)?;
282            }
283            contract_uref @ Key::URef(_) => {
284                let contract: Contract = {
285                    let value: StoredValue = self
286                        .tracking_copy
287                        .borrow_mut()
288                        .read(&contract_uref)?
289                        .ok_or(ExecError::KeyNotFound(contract_uref))?;
290
291                    value.try_into().map_err(ExecError::TypeMismatch)?
292                };
293
294                self.named_keys.remove(name);
295                self.remove_key_from_contract(contract_uref, contract, name)?
296            }
297            contract_hash @ Key::Hash(_) => {
298                let contract: Contract = self.read_gs_typed(&contract_hash)?;
299                self.named_keys.remove(name);
300                self.remove_key_from_contract(contract_hash, contract, name)?
301            }
302            _ => return Err(ExecError::UnexpectedKeyVariant(key)),
303        }
304        Ok(())
305    }
306
307    /// Remove Key from the `named_keys` map of the current context.
308    /// It removes both from the ephemeral map (RuntimeContext::named_keys) but
309    /// also the to-be-persisted map (in the TrackingCopy/GlobalState).
310    pub fn remove_key(&mut self, name: &str) -> Result<(), ExecError> {
311        self.named_keys.remove(name);
312        self.remove_key_from_entity(name)
313    }
314
315    /// Returns block info.
316    pub fn get_block_info(&self) -> BlockInfo {
317        self.block_info
318    }
319
320    /// Returns the transaction hash.
321    pub fn get_transaction_hash(&self) -> TransactionHash {
322        self.transaction_hash
323    }
324
325    /// Extends access rights with a new map.
326    pub fn access_rights_extend(&mut self, urefs: &[URef]) {
327        self.access_rights.extend(urefs);
328    }
329
330    /// Returns a mapping of access rights for each [`URef`]s address.
331    pub fn access_rights(&self) -> &ContextAccessRights {
332        &self.access_rights
333    }
334
335    /// Returns footprint of the caller.
336    pub fn runtime_footprint(&self) -> Rc<RefCell<RuntimeFootprint>> {
337        Rc::clone(&self.runtime_footprint)
338    }
339
340    /// Returns arguments.
341    pub fn args(&self) -> &RuntimeArgs {
342        &self.args
343    }
344
345    pub(crate) fn set_args(&mut self, args: RuntimeArgs) {
346        self.args = args
347    }
348
349    /// Returns new shared instance of an address generator.
350    pub fn address_generator(&self) -> Rc<RefCell<AddressGenerator>> {
351        Rc::clone(&self.address_generator)
352    }
353
354    /// Returns new shared instance of a tracking copy.
355    pub(super) fn state(&self) -> Rc<RefCell<TrackingCopy<R>>> {
356        Rc::clone(&self.tracking_copy)
357    }
358
359    /// Returns the gas limit.
360    pub fn gas_limit(&self) -> Gas {
361        self.gas_limit
362    }
363
364    /// Returns the current gas counter.
365    pub fn gas_counter(&self) -> Gas {
366        self.gas_counter
367    }
368
369    /// Sets the gas counter to a new value.
370    pub fn set_gas_counter(&mut self, new_gas_counter: Gas) {
371        self.gas_counter = new_gas_counter;
372    }
373
374    /// Returns the context key for this instance.
375    pub fn get_context_key(&self) -> Key {
376        self.context_key
377    }
378
379    /// Returns the initiator of the call chain.
380    pub fn get_initiator(&self) -> AccountHash {
381        self.account_hash
382    }
383
384    /// Returns the protocol version.
385    pub fn protocol_version(&self) -> ProtocolVersion {
386        self.block_info.protocol_version()
387    }
388
389    /// Returns the current phase.
390    pub fn phase(&self) -> Phase {
391        self.phase
392    }
393
394    /// Returns `true` if the execution is permitted to call `casper_add_contract_version()`.
395    pub fn install_upgrade_allowed(&self) -> bool {
396        self.allow_install_upgrade == AllowInstallUpgrade::Allowed
397    }
398
399    /// Generates new deterministic hash for uses as an address.
400    pub fn new_hash_address(&mut self) -> Result<[u8; KEY_HASH_LENGTH], ExecError> {
401        Ok(self.address_generator.borrow_mut().new_hash_address())
402    }
403
404    /// Returns 32 pseudo random bytes.
405    pub fn random_bytes(&mut self) -> Result<[u8; RANDOM_BYTES_COUNT], ExecError> {
406        Ok(self.address_generator.borrow_mut().create_address())
407    }
408
409    /// Creates new [`URef`] instance.
410    pub fn new_uref(&mut self, value: StoredValue) -> Result<URef, ExecError> {
411        let uref = self
412            .address_generator
413            .borrow_mut()
414            .new_uref(AccessRights::READ_ADD_WRITE);
415        self.insert_uref(uref);
416        self.metered_write_gs(Key::URef(uref), value)?;
417        Ok(uref)
418    }
419
420    /// Creates a new URef where the value it stores is CLType::Unit.
421    pub(crate) fn new_unit_uref(&mut self) -> Result<URef, ExecError> {
422        self.new_uref(StoredValue::CLValue(CLValue::unit()))
423    }
424
425    /// Puts `key` to the map of named keys of current context.
426    pub fn put_key(&mut self, name: String, key: Key) -> Result<(), ExecError> {
427        // No need to perform actual validation on the base key because an account or contract (i.e.
428        // the element stored under `base_key`) is allowed to add new named keys to itself.
429        match self.get_context_key() {
430            Key::Account(_) | Key::Hash(_) => {
431                let named_key_value = StoredValue::CLValue(CLValue::from_t((name.clone(), key))?);
432                self.validate_value(&named_key_value)?;
433                self.metered_add_gs_unsafe(self.get_context_key(), named_key_value)?;
434                self.insert_named_key(name, key);
435            }
436            Key::AddressableEntity(entity_addr) => {
437                let named_key_value =
438                    StoredValue::NamedKey(NamedKeyValue::from_concrete_values(key, name.clone())?);
439                self.validate_value(&named_key_value)?;
440                let named_key_addr = NamedKeyAddr::new_from_string(entity_addr, name.clone())?;
441                self.metered_write_gs_unsafe(Key::NamedKey(named_key_addr), named_key_value)?;
442                self.insert_named_key(name, key);
443            }
444            _ => return Err(ExecError::InvalidContext),
445        }
446
447        Ok(())
448    }
449
450    pub(crate) fn get_message_topics(
451        &mut self,
452        hash_addr: EntityAddr,
453    ) -> Result<MessageTopics, ExecError> {
454        self.tracking_copy
455            .borrow_mut()
456            .get_message_topics(hash_addr)
457            .map_err(Into::into)
458    }
459
460    pub(crate) fn get_named_keys(&mut self, entity_key: Key) -> Result<NamedKeys, ExecError> {
461        let entity_addr = if let Key::AddressableEntity(entity_addr) = entity_key {
462            entity_addr
463        } else {
464            return Err(ExecError::UnexpectedKeyVariant(entity_key));
465        };
466        self.tracking_copy
467            .borrow_mut()
468            .get_named_keys(entity_addr)
469            .map_err(Into::into)
470    }
471
472    pub(crate) fn write_entry_points(
473        &mut self,
474        entity_addr: EntityAddr,
475        entry_points: EntryPoints,
476    ) -> Result<(), ExecError> {
477        if entry_points.is_empty() {
478            return Ok(());
479        }
480
481        for entry_point in entry_points.take_entry_points() {
482            let entry_point_addr =
483                EntryPointAddr::new_v1_entry_point_addr(entity_addr, entry_point.name())?;
484            let entry_point_value =
485                StoredValue::EntryPoint(EntryPointValue::V1CasperVm(entry_point));
486            self.metered_write_gs_unsafe(Key::EntryPoint(entry_point_addr), entry_point_value)?;
487        }
488
489        Ok(())
490    }
491
492    pub(crate) fn get_casper_vm_v1_entry_point(
493        &mut self,
494        entity_key: Key,
495    ) -> Result<EntryPoints, ExecError> {
496        let entity_addr = if let Key::AddressableEntity(entity_addr) = entity_key {
497            entity_addr
498        } else {
499            return Err(ExecError::UnexpectedKeyVariant(entity_key));
500        };
501
502        self.tracking_copy
503            .borrow_mut()
504            .get_v1_entry_points(entity_addr)
505            .map_err(Into::into)
506    }
507
508    /// Reads the total balance of a purse [`URef`].
509    ///
510    /// Currently address of a purse [`URef`] is also a hash in the [`Key::Hash`] space.
511    pub(crate) fn total_balance(&mut self, purse_uref: &URef) -> Result<Motes, ExecError> {
512        let key = Key::URef(*purse_uref);
513        let total = self
514            .tracking_copy
515            .borrow_mut()
516            .get_total_balance(key)
517            .map_err(ExecError::TrackingCopy)?;
518        Ok(total)
519    }
520
521    /// Reads the available balance of a purse [`URef`].
522    ///
523    /// Currently address of a purse [`URef`] is also a hash in the [`Key::Hash`] space.
524    pub(crate) fn available_balance(&mut self, purse_uref: &URef) -> Result<Motes, ExecError> {
525        let key = Key::URef(*purse_uref);
526        self.tracking_copy
527            .borrow_mut()
528            .get_available_balance(key)
529            .map_err(ExecError::TrackingCopy)
530    }
531
532    /// Read a stored value under a [`Key`].
533    pub fn read_gs(&mut self, key: &Key) -> Result<Option<StoredValue>, ExecError> {
534        self.validate_readable(key)?;
535        self.validate_key(key)?;
536
537        let maybe_stored_value = self.tracking_copy.borrow_mut().read(key)?;
538
539        let stored_value = match maybe_stored_value {
540            Some(stored_value) => handle_stored_dictionary_value(*key, stored_value)?,
541            None => return Ok(None),
542        };
543
544        Ok(Some(stored_value))
545    }
546
547    /// Reads a value from a global state directly.
548    ///
549    /// # Usage
550    ///
551    /// DO NOT EXPOSE THIS VIA THE FFI - This function bypasses security checks and should be used
552    /// with caution.
553    pub fn read_gs_unsafe(&mut self, key: &Key) -> Result<Option<StoredValue>, ExecError> {
554        self.tracking_copy
555            .borrow_mut()
556            .read(key)
557            .map_err(Into::into)
558    }
559
560    /// This method is a wrapper over `read_gs` in the sense that it extracts the type held by a
561    /// `StoredValue` stored in the global state in a type safe manner.
562    ///
563    /// This is useful if you want to get the exact type from global state.
564    pub fn read_gs_typed<T>(&mut self, key: &Key) -> Result<T, ExecError>
565    where
566        T: TryFrom<StoredValue, Error = StoredValueTypeMismatch>,
567        T::Error: Debug,
568    {
569        let value = match self.read_gs(key)? {
570            None => return Err(ExecError::KeyNotFound(*key)),
571            Some(value) => value,
572        };
573
574        value
575            .try_into()
576            .map_err(|error| ExecError::TrackingCopy(TrackingCopyError::TypeMismatch(error)))
577    }
578
579    /// Returns all keys based on the tag prefix.
580    pub fn get_keys(&mut self, key_tag: &KeyTag) -> Result<BTreeSet<Key>, ExecError> {
581        self.tracking_copy
582            .borrow_mut()
583            .get_keys(key_tag)
584            .map_err(Into::into)
585    }
586
587    /// Returns all key's that start with prefix, if any.
588    pub fn get_keys_with_prefix(&mut self, prefix: &[u8]) -> Result<Vec<Key>, ExecError> {
589        self.tracking_copy
590            .borrow_mut()
591            .reader()
592            .keys_with_prefix(prefix)
593            .map_err(Into::into)
594    }
595
596    /// Write an era info instance to the global state.
597    pub fn write_era_info(&mut self, key: Key, value: EraInfo) {
598        if let Key::EraSummary = key {
599            // Writing an `EraInfo` for 100 validators will not exceed write size limit.
600            self.tracking_copy
601                .borrow_mut()
602                .write(key, StoredValue::EraInfo(value));
603        } else {
604            panic!("Do not use this function for writing non-era-info keys")
605        }
606    }
607
608    /// Creates validated instance of `StoredValue` from `account`.
609    fn account_to_validated_value(&self, account: Account) -> Result<StoredValue, ExecError> {
610        let value = StoredValue::Account(account);
611        self.validate_value(&value)?;
612        Ok(value)
613    }
614
615    /// Write an account to the global state.
616    pub fn write_account(&mut self, key: Key, account: Account) -> Result<(), ExecError> {
617        if let Key::Account(_) = key {
618            self.validate_key(&key)?;
619            let account_value = self.account_to_validated_value(account)?;
620            self.metered_write_gs_unsafe(key, account_value)?;
621            Ok(())
622        } else {
623            panic!("Do not use this function for writing non-account keys")
624        }
625    }
626
627    /// Read an account from the global state.
628    pub fn read_account(&mut self, key: &Key) -> Result<Option<StoredValue>, ExecError> {
629        if let Key::Account(_) = key {
630            self.validate_key(key)?;
631            self.tracking_copy
632                .borrow_mut()
633                .read(key)
634                .map_err(Into::into)
635        } else {
636            panic!("Do not use this function for reading from non-account keys")
637        }
638    }
639
640    /// Adds a named key.
641    ///
642    /// If given `Key` refers to an [`URef`] then it extends the runtime context's access rights
643    /// with the URef's access rights.
644    fn insert_named_key(&mut self, name: String, key: Key) {
645        if let Key::URef(uref) = key {
646            self.insert_uref(uref);
647        }
648        self.named_keys.insert(name, key);
649    }
650
651    /// Adds a new [`URef`] into the context.
652    ///
653    /// Once an [`URef`] is inserted, it's considered a valid [`URef`] in this runtime context.
654    fn insert_uref(&mut self, uref: URef) {
655        self.access_rights.extend(&[uref])
656    }
657
658    /// Grants access to a [`URef`]; unless access was pre-existing.
659    pub fn grant_access(&mut self, uref: URef) -> GrantedAccess {
660        self.access_rights.grant_access(uref)
661    }
662
663    /// Removes an access right from the current runtime context.
664    pub fn remove_access(&mut self, uref_addr: URefAddr, access_rights: AccessRights) {
665        self.access_rights.remove_access(uref_addr, access_rights)
666    }
667
668    /// Returns a copy of the current effects of a tracking copy.
669    pub fn effects(&self) -> Effects {
670        self.tracking_copy.borrow().effects()
671    }
672
673    /// Returns a copy of the current messages of a tracking copy.
674    pub fn messages(&self) -> Messages {
675        self.tracking_copy.borrow().messages()
676    }
677
678    /// Returns a copy of the current named keys of a tracking copy.
679    pub fn cache(&self) -> TrackingCopyCache {
680        self.tracking_copy.borrow().cache()
681    }
682
683    /// Returns the cost charged for the last emitted message.
684    pub fn emit_message_cost(&self) -> U512 {
685        self.emit_message_cost
686    }
687
688    /// Sets the cost charged for the last emitted message.
689    pub fn set_emit_message_cost(&mut self, cost: U512) {
690        self.emit_message_cost = cost
691    }
692
693    /// Returns list of transfers.
694    pub fn transfers(&self) -> &Vec<Transfer> {
695        &self.transfers
696    }
697
698    /// Returns mutable list of transfers.
699    pub fn transfers_mut(&mut self) -> &mut Vec<Transfer> {
700        &mut self.transfers
701    }
702
703    fn validate_cl_value(&self, cl_value: &CLValue) -> Result<(), ExecError> {
704        match cl_value.cl_type() {
705            CLType::Bool
706            | CLType::I32
707            | CLType::I64
708            | CLType::U8
709            | CLType::U32
710            | CLType::U64
711            | CLType::U128
712            | CLType::U256
713            | CLType::U512
714            | CLType::Unit
715            | CLType::String
716            | CLType::Option(_)
717            | CLType::List(_)
718            | CLType::ByteArray(..)
719            | CLType::Result { .. }
720            | CLType::Map { .. }
721            | CLType::Tuple1(_)
722            | CLType::Tuple3(_)
723            | CLType::Any
724            | CLType::PublicKey => Ok(()),
725            CLType::Key => {
726                let key: Key = cl_value.to_t()?;
727                self.validate_key(&key)
728            }
729            CLType::URef => {
730                let uref: URef = cl_value.to_t()?;
731                self.validate_uref(&uref)
732            }
733            tuple @ CLType::Tuple2(_) if *tuple == casper_types::named_key_type() => {
734                let (_name, key): (String, Key) = cl_value.to_t()?;
735                self.validate_key(&key)
736            }
737            CLType::Tuple2(_) => Ok(()),
738        }
739    }
740
741    /// Validates whether keys used in the `value` are not forged.
742    pub(crate) fn validate_value(&self, value: &StoredValue) -> Result<(), ExecError> {
743        match value {
744            StoredValue::CLValue(cl_value) => self.validate_cl_value(cl_value),
745            StoredValue::NamedKey(named_key_value) => {
746                self.validate_cl_value(named_key_value.get_key_as_cl_value())?;
747                self.validate_cl_value(named_key_value.get_name_as_cl_value())
748            }
749            StoredValue::Account(_)
750            | StoredValue::ByteCode(_)
751            | StoredValue::Contract(_)
752            | StoredValue::AddressableEntity(_)
753            | StoredValue::SmartContract(_)
754            | StoredValue::Transfer(_)
755            | StoredValue::DeployInfo(_)
756            | StoredValue::EraInfo(_)
757            | StoredValue::Bid(_)
758            | StoredValue::BidKind(_)
759            | StoredValue::Withdraw(_)
760            | StoredValue::Unbonding(_)
761            | StoredValue::ContractPackage(_)
762            | StoredValue::ContractWasm(_)
763            | StoredValue::MessageTopic(_)
764            | StoredValue::Message(_)
765            | StoredValue::Prepayment(_)
766            | StoredValue::EntryPoint(_)
767            | StoredValue::RawBytes(_) => Ok(()),
768        }
769    }
770
771    pub(crate) fn context_key_to_entity_addr(&self) -> Result<EntityAddr, ExecError> {
772        match self.context_key {
773            Key::Account(account_hash) => Ok(EntityAddr::Account(account_hash.value())),
774            Key::Hash(hash) => {
775                if self.is_system_addressable_entity(&hash)? {
776                    Ok(EntityAddr::System(hash))
777                } else {
778                    Ok(EntityAddr::SmartContract(hash))
779                }
780            }
781            Key::AddressableEntity(addr) => Ok(addr),
782            _ => Err(ExecError::UnexpectedKeyVariant(self.context_key)),
783        }
784    }
785
786    /// Validates whether key is not forged (whether it can be found in the
787    /// `named_keys`) and whether the version of a key that contract wants
788    /// to use, has access rights that are less powerful than access rights'
789    /// of the key in the `named_keys`.
790    pub(crate) fn validate_key(&self, key: &Key) -> Result<(), ExecError> {
791        let uref = match key {
792            Key::URef(uref) => uref,
793            _ => return Ok(()),
794        };
795        self.validate_uref(uref)
796    }
797
798    /// Validate [`URef`] access rights.
799    ///
800    /// Returns unit if [`URef`]s address exists in the context, and has correct access rights bit
801    /// set.
802    pub(crate) fn validate_uref(&self, uref: &URef) -> Result<(), ExecError> {
803        if self.access_rights.has_access_rights_to_uref(uref) {
804            Ok(())
805        } else {
806            Err(ExecError::ForgedReference(*uref))
807        }
808    }
809
810    /// Validates if a [`Key`] refers to a [`URef`] and has a read bit set.
811    fn validate_readable(&self, key: &Key) -> Result<(), ExecError> {
812        if self.is_readable(key) {
813            Ok(())
814        } else {
815            Err(ExecError::InvalidAccess {
816                required: AccessRights::READ,
817            })
818        }
819    }
820
821    /// Validates if a [`Key`] refers to a [`URef`] and has a add bit set.
822    fn validate_addable(&self, key: &Key) -> Result<(), ExecError> {
823        if self.is_addable(key) {
824            Ok(())
825        } else {
826            Err(ExecError::InvalidAccess {
827                required: AccessRights::ADD,
828            })
829        }
830    }
831
832    /// Validates if a [`Key`] refers to a [`URef`] and has a write bit set.
833    pub(crate) fn validate_writeable(&self, key: &Key) -> Result<(), ExecError> {
834        if self.is_writeable(key) {
835            Ok(())
836        } else {
837            Err(ExecError::InvalidAccess {
838                required: AccessRights::WRITE,
839            })
840        }
841    }
842
843    /// Tests whether reading from the `key` is valid.
844    pub fn is_readable(&self, key: &Key) -> bool {
845        match self.context_key_to_entity_addr() {
846            Ok(entity_addr) => key.is_readable(&entity_addr),
847            Err(error) => {
848                error!(?error, "entity_key is unexpected key variant");
849                panic!("is_readable: entity_key is unexpected key variant");
850            }
851        }
852    }
853
854    /// Tests whether addition to `key` is valid.
855    pub fn is_addable(&self, key: &Key) -> bool {
856        match self.context_key_to_entity_addr() {
857            Ok(entity_addr) => key.is_addable(&entity_addr),
858            Err(error) => {
859                error!(?error, "entity_key is unexpected key variant");
860                panic!("is_addable: entity_key is unexpected key variant");
861            }
862        }
863    }
864
865    /// Tests whether writing to `key` is valid.
866    pub fn is_writeable(&self, key: &Key) -> bool {
867        match self.context_key_to_entity_addr() {
868            Ok(entity_addr) => key.is_writeable(&entity_addr),
869            Err(error) => {
870                error!(?error, "entity_key is unexpected key variant");
871                panic!("is_writeable: entity_key is unexpected key variant");
872            }
873        }
874    }
875
876    /// Safely charge the specified amount of gas, up to the available gas limit.
877    ///
878    /// Returns [`Error::GasLimit`] if gas limit exceeded and `()` if not.
879    /// Intuition about the return value sense is to answer the question 'are we
880    /// allowed to continue?'
881    pub(crate) fn charge_gas(&mut self, gas: Gas) -> Result<(), ExecError> {
882        let prev = self.gas_counter();
883        let gas_limit = self.gas_limit();
884        // gas charge overflow protection
885        match prev.checked_add(gas) {
886            None => {
887                self.set_gas_counter(gas_limit);
888                Err(ExecError::GasLimit)
889            }
890            Some(val) if val > gas_limit => {
891                self.set_gas_counter(gas_limit);
892                Err(ExecError::GasLimit)
893            }
894            Some(val) => {
895                self.set_gas_counter(val);
896                Ok(())
897            }
898        }
899    }
900
901    /// Checks if we are calling a system addressable entity.
902    pub(crate) fn is_system_addressable_entity(
903        &self,
904        hash_addr: &HashAddr,
905    ) -> Result<bool, ExecError> {
906        Ok(self.system_entity_registry()?.exists(hash_addr))
907    }
908
909    /// Charges gas for specified amount of bytes used.
910    fn charge_gas_storage(&mut self, bytes_count: usize) -> Result<(), ExecError> {
911        if let Some(hash_addr) = self.get_context_key().into_entity_hash_addr() {
912            if self.is_system_addressable_entity(&hash_addr)? {
913                // Don't charge storage used while executing a system contract.
914                return Ok(());
915            }
916        }
917
918        let storage_costs = self.engine_config.storage_costs();
919
920        let gas_cost = storage_costs.calculate_gas_cost(bytes_count);
921
922        self.charge_gas(gas_cost)
923    }
924
925    /// Charges gas for using a host system contract's entrypoint.
926    pub(crate) fn charge_system_contract_call<T>(&mut self, call_cost: T) -> Result<(), ExecError>
927    where
928        T: Into<Gas>,
929    {
930        let amount: Gas = call_cost.into();
931        self.charge_gas(amount)
932    }
933
934    /// Prune a key from the global state.
935    ///
936    /// Use with caution - there is no validation done as the key is assumed to be validated
937    /// already.
938    pub(crate) fn prune_gs_unsafe<K>(&mut self, key: K)
939    where
940        K: Into<Key>,
941    {
942        self.tracking_copy.borrow_mut().prune(key.into());
943    }
944
945    pub(crate) fn migrate_package(
946        &mut self,
947        contract_package_hash: ContractPackageHash,
948        protocol_version: ProtocolVersion,
949    ) -> Result<(), ExecError> {
950        self.tracking_copy
951            .borrow_mut()
952            .migrate_package(Key::Hash(contract_package_hash.value()), protocol_version)
953            .map_err(ExecError::TrackingCopy)
954    }
955
956    /// Writes data to global state with a measurement.
957    ///
958    /// Use with caution - there is no validation done as the key is assumed to be validated
959    /// already.
960    pub(crate) fn metered_write_gs_unsafe<K, V>(
961        &mut self,
962        key: K,
963        value: V,
964    ) -> Result<(), ExecError>
965    where
966        K: Into<Key>,
967        V: Into<StoredValue>,
968    {
969        let stored_value = value.into();
970
971        // Charge for amount as measured by serialized length
972        let bytes_count = stored_value.serialized_length();
973        self.charge_gas_storage(bytes_count)?;
974
975        self.tracking_copy
976            .borrow_mut()
977            .write(key.into(), stored_value);
978        Ok(())
979    }
980
981    /// Emits message and writes message summary to global state with a measurement.
982    pub(crate) fn metered_emit_message(
983        &mut self,
984        topic_key: Key,
985        block_time: BlockTime,
986        block_message_count: u64,
987        topic_message_count: u32,
988        message: Message,
989    ) -> Result<(), ExecError> {
990        let topic_value = StoredValue::MessageTopic(MessageTopicSummary::new(
991            topic_message_count,
992            block_time,
993            message.topic_name().to_owned(),
994        ));
995        let message_key = message.message_key();
996        let message_value = StoredValue::Message(message.checksum().map_err(ExecError::BytesRepr)?);
997
998        let block_message_count_value =
999            StoredValue::CLValue(CLValue::from_t((block_time, block_message_count))?);
1000
1001        // Charge for amount as measured by serialized length
1002        let bytes_count = topic_value.serialized_length()
1003            + message_value.serialized_length()
1004            + block_message_count_value.serialized_length();
1005        self.charge_gas_storage(bytes_count)?;
1006
1007        self.tracking_copy.borrow_mut().emit_message(
1008            topic_key,
1009            topic_value,
1010            message_key,
1011            message_value,
1012            block_message_count_value,
1013            message,
1014        );
1015        Ok(())
1016    }
1017
1018    /// Writes data to a global state and charges for bytes stored.
1019    ///
1020    /// This method performs full validation of the key to be written.
1021    pub(crate) fn metered_write_gs<T>(&mut self, key: Key, value: T) -> Result<(), ExecError>
1022    where
1023        T: Into<StoredValue>,
1024    {
1025        let stored_value = value.into();
1026        self.validate_writeable(&key)?;
1027        self.validate_key(&key)?;
1028        self.validate_value(&stored_value)?;
1029        self.metered_write_gs_unsafe(key, stored_value)
1030    }
1031
1032    /// Adds data to a global state key and charges for bytes stored.
1033    pub(crate) fn metered_add_gs_unsafe(
1034        &mut self,
1035        key: Key,
1036        value: StoredValue,
1037    ) -> Result<(), ExecError> {
1038        let value_bytes_count = value.serialized_length();
1039        self.charge_gas_storage(value_bytes_count)?;
1040
1041        match self.tracking_copy.borrow_mut().add(key, value) {
1042            Err(storage_error) => Err(storage_error.into()),
1043            Ok(AddResult::Success) => Ok(()),
1044            Ok(AddResult::KeyNotFound(key)) => Err(ExecError::KeyNotFound(key)),
1045            Ok(AddResult::TypeMismatch(type_mismatch)) => {
1046                Err(ExecError::TypeMismatch(type_mismatch))
1047            }
1048            Ok(AddResult::Serialization(error)) => Err(ExecError::BytesRepr(error)),
1049            Ok(AddResult::Transform(error)) => Err(ExecError::Transform(error)),
1050        }
1051    }
1052
1053    /// Adds `value` to the `key`. The premise for being able to `add` value is
1054    /// that the type of it value can be added (is a Monoid). If the
1055    /// values can't be added, either because they're not a Monoid or if the
1056    /// value stored under `key` has different type, then `TypeMismatch`
1057    /// errors is returned.
1058    pub(crate) fn metered_add_gs<K, V>(&mut self, key: K, value: V) -> Result<(), ExecError>
1059    where
1060        K: Into<Key>,
1061        V: Into<StoredValue>,
1062    {
1063        let key = key.into();
1064        let value = value.into();
1065        self.validate_addable(&key)?;
1066        self.validate_key(&key)?;
1067        self.validate_value(&value)?;
1068        self.metered_add_gs_unsafe(key, value)
1069    }
1070
1071    /// Adds new associated key.
1072    pub(crate) fn add_associated_key(
1073        &mut self,
1074        account_hash: AccountHash,
1075        weight: Weight,
1076    ) -> Result<(), ExecError> {
1077        let context_key = self.context_key;
1078        let entity_addr = self.context_key_to_entity_addr()?;
1079
1080        if EntryPointType::Caller == self.entry_point_type
1081            && entity_addr.tag() != EntityKindTag::Account
1082        {
1083            // Exit early with error to avoid mutations
1084            return Err(AddKeyFailure::PermissionDenied.into());
1085        }
1086
1087        if self.engine_config.enable_entity {
1088            // Get the current entity record
1089            let entity = {
1090                let mut entity: AddressableEntity = self.read_gs_typed(&context_key)?;
1091                // enforce max keys limit
1092                if entity.associated_keys().len()
1093                    >= (self.engine_config.max_associated_keys() as usize)
1094                {
1095                    return Err(ExecError::AddKeyFailure(AddKeyFailure::MaxKeysLimit));
1096                }
1097
1098                // Exit early in case of error without updating global state
1099                entity
1100                    .add_associated_key(account_hash, weight)
1101                    .map_err(ExecError::from)?;
1102                entity
1103            };
1104
1105            self.metered_write_gs_unsafe(
1106                context_key,
1107                self.addressable_entity_to_validated_value(entity)?,
1108            )?;
1109        } else {
1110            // Take an account out of the global state
1111            let account = {
1112                let mut account: Account = self.read_gs_typed(&context_key)?;
1113
1114                if account.associated_keys().len() as u32
1115                    >= (self.engine_config.max_associated_keys())
1116                {
1117                    return Err(ExecError::AddKeyFailure(AddKeyFailure::MaxKeysLimit));
1118                }
1119
1120                // Exit early in case of error without updating global state
1121                let result = account.add_associated_key(
1122                    account_hash,
1123                    casper_types::account::Weight::new(weight.value()),
1124                );
1125
1126                result.map_err(ExecError::from)?;
1127                account
1128            };
1129
1130            let account_value = self.account_to_validated_value(account)?;
1131
1132            self.metered_write_gs_unsafe(context_key, account_value)?;
1133        }
1134
1135        Ok(())
1136    }
1137
1138    /// Remove associated key.
1139    pub(crate) fn remove_associated_key(
1140        &mut self,
1141        account_hash: AccountHash,
1142    ) -> Result<(), ExecError> {
1143        let context_key = self.context_key;
1144        let entity_addr = self.context_key_to_entity_addr()?;
1145
1146        if EntryPointType::Caller == self.entry_point_type
1147            && entity_addr.tag() != EntityKindTag::Account
1148        {
1149            // Exit early with error to avoid mutations
1150            return Err(RemoveKeyFailure::PermissionDenied.into());
1151        }
1152
1153        if !self
1154            .runtime_footprint()
1155            .borrow()
1156            .can_manage_keys_with(&self.authorization_keys)
1157        {
1158            // Exit early if authorization keys weight doesn't exceed required
1159            // key management threshold
1160            return Err(RemoveKeyFailure::PermissionDenied.into());
1161        }
1162
1163        if self.engine_config.enable_entity {
1164            // Get the current entity record
1165            let entity = {
1166                let mut entity: AddressableEntity = self.read_gs_typed(&context_key)?;
1167
1168                // Exit early in case of error without updating global state
1169                entity
1170                    .remove_associated_key(account_hash)
1171                    .map_err(ExecError::from)?;
1172                entity
1173            };
1174
1175            self.metered_write_gs_unsafe(
1176                context_key,
1177                self.addressable_entity_to_validated_value(entity)?,
1178            )?;
1179        } else {
1180            // Take an account out of the global state
1181            let account = {
1182                let mut account: Account = self.read_gs_typed(&context_key)?;
1183
1184                // Exit early in case of error without updating global state
1185                account
1186                    .remove_associated_key(account_hash)
1187                    .map_err(ExecError::from)?;
1188                account
1189            };
1190
1191            let account_value = self.account_to_validated_value(account)?;
1192
1193            self.metered_write_gs_unsafe(context_key, account_value)?;
1194        }
1195
1196        Ok(())
1197    }
1198
1199    /// Update associated key.
1200    pub(crate) fn update_associated_key(
1201        &mut self,
1202        account_hash: AccountHash,
1203        weight: Weight,
1204    ) -> Result<(), ExecError> {
1205        let context_key = self.context_key;
1206        let entity_addr = self.context_key_to_entity_addr()?;
1207
1208        if EntryPointType::Caller == self.entry_point_type
1209            && entity_addr.tag() != EntityKindTag::Account
1210        {
1211            // Exit early with error to avoid mutations
1212            return Err(UpdateKeyFailure::PermissionDenied.into());
1213        }
1214
1215        if !self
1216            .runtime_footprint()
1217            .borrow()
1218            .can_manage_keys_with(&self.authorization_keys)
1219        {
1220            // Exit early if authorization keys weight doesn't exceed required
1221            // key management threshold
1222            return Err(UpdateKeyFailure::PermissionDenied.into());
1223        }
1224
1225        if self.engine_config.enable_entity {
1226            // Get the current entity record
1227            let entity = {
1228                let mut entity: AddressableEntity = self.read_gs_typed(&context_key)?;
1229
1230                // Exit early in case of error without updating global state
1231                entity
1232                    .update_associated_key(account_hash, weight)
1233                    .map_err(ExecError::from)?;
1234                entity
1235            };
1236
1237            self.metered_write_gs_unsafe(
1238                context_key,
1239                self.addressable_entity_to_validated_value(entity)?,
1240            )?;
1241        } else {
1242            // Take an account out of the global state
1243            let account = {
1244                let mut account: Account = self.read_gs_typed(&context_key)?;
1245
1246                // Exit early in case of error without updating global state
1247                account
1248                    .update_associated_key(
1249                        account_hash,
1250                        casper_types::account::Weight::new(weight.value()),
1251                    )
1252                    .map_err(ExecError::from)?;
1253                account
1254            };
1255
1256            let account_value = self.account_to_validated_value(account)?;
1257
1258            self.metered_write_gs_unsafe(context_key, account_value)?;
1259        }
1260
1261        Ok(())
1262    }
1263
1264    pub(crate) fn is_authorized_by_admin(&self) -> bool {
1265        self.engine_config
1266            .administrative_accounts()
1267            .intersection(&self.authorization_keys)
1268            .next()
1269            .is_some()
1270    }
1271    /// Gets given contract package with its access_key validated against current context.
1272    pub(crate) fn get_validated_contract_package(
1273        &mut self,
1274        package_hash: HashAddr,
1275    ) -> Result<ContractPackage, ExecError> {
1276        let package_hash_key = Key::Hash(package_hash);
1277        self.validate_key(&package_hash_key)?;
1278        let contract_package: ContractPackage = self.read_gs_typed(&package_hash_key)?;
1279
1280        if !self.is_authorized_by_admin() {
1281            self.validate_uref(&contract_package.access_key())?;
1282        }
1283
1284        Ok(contract_package)
1285    }
1286
1287    /// Set threshold of an associated key.
1288    pub(crate) fn set_action_threshold(
1289        &mut self,
1290        action_type: ActionType,
1291        threshold: Weight,
1292    ) -> Result<(), ExecError> {
1293        let context_key = self.context_key;
1294        let entity_addr = self.context_key_to_entity_addr()?;
1295
1296        if EntryPointType::Caller == self.entry_point_type
1297            && entity_addr.tag() != EntityKindTag::Account
1298        {
1299            // Exit early with error to avoid mutations
1300            return Err(SetThresholdFailure::PermissionDeniedError.into());
1301        }
1302
1303        if self.engine_config.enable_entity {
1304            // Take an addressable entity out of the global state
1305            let mut entity: AddressableEntity = self.read_gs_typed(&context_key)?;
1306
1307            // Exit early in case of error without updating global state
1308            if self.is_authorized_by_admin() {
1309                entity.set_action_threshold_unchecked(action_type, threshold)
1310            } else {
1311                entity.set_action_threshold(action_type, threshold)
1312            }
1313            .map_err(ExecError::from)?;
1314
1315            let entity_value = self.addressable_entity_to_validated_value(entity)?;
1316
1317            self.metered_write_gs_unsafe(context_key, entity_value)?;
1318        } else {
1319            // Converts an account's public key into a URef
1320            let key = Key::Account(AccountHash::new(entity_addr.value()));
1321
1322            // Take an account out of the global state
1323            let mut account: Account = self.read_gs_typed(&key)?;
1324
1325            // Exit early in case of error without updating global state
1326            let action_type = match action_type {
1327                ActionType::Deployment => casper_types::account::ActionType::Deployment,
1328                ActionType::KeyManagement => casper_types::account::ActionType::KeyManagement,
1329                ActionType::UpgradeManagement => return Err(ExecError::InvalidContext),
1330            };
1331
1332            let threshold = casper_types::account::Weight::new(threshold.value());
1333
1334            if self.is_authorized_by_admin() {
1335                account.set_action_threshold_unchecked(action_type, threshold)
1336            } else {
1337                account.set_action_threshold(action_type, threshold)
1338            }
1339            .map_err(ExecError::from)?;
1340
1341            let account_value = self.account_to_validated_value(account)?;
1342
1343            self.metered_write_gs_unsafe(key, account_value)?;
1344        }
1345
1346        Ok(())
1347    }
1348
1349    fn addressable_entity_to_validated_value(
1350        &self,
1351        entity: AddressableEntity,
1352    ) -> Result<StoredValue, ExecError> {
1353        let value = StoredValue::AddressableEntity(entity);
1354        self.validate_value(&value)?;
1355        Ok(value)
1356    }
1357
1358    pub(crate) fn runtime_footprint_by_account_hash(
1359        &mut self,
1360        account_hash: AccountHash,
1361    ) -> Result<Option<RuntimeFootprint>, ExecError> {
1362        if self.engine_config.enable_entity {
1363            match self.read_gs(&Key::Account(account_hash))? {
1364                Some(StoredValue::CLValue(cl_value)) => {
1365                    let key: Key = cl_value.into_t().map_err(ExecError::CLValue)?;
1366                    match self.read_gs(&key)? {
1367                        Some(StoredValue::AddressableEntity(addressable_entity)) => {
1368                            let entity_addr = EntityAddr::Account(account_hash.value());
1369                            let named_keys = self.get_named_keys(key)?;
1370                            let entry_points = self.get_casper_vm_v1_entry_point(key)?;
1371                            let footprint = RuntimeFootprint::new_entity_footprint(
1372                                entity_addr,
1373                                addressable_entity,
1374                                named_keys,
1375                                entry_points,
1376                            );
1377                            Ok(Some(footprint))
1378                        }
1379                        Some(_other_variant_2) => Err(ExecError::UnexpectedStoredValueVariant),
1380                        None => Ok(None),
1381                    }
1382                }
1383                Some(_other_variant_1) => Err(ExecError::UnexpectedStoredValueVariant),
1384                None => Ok(None),
1385            }
1386        } else {
1387            match self.read_gs(&Key::Account(account_hash))? {
1388                Some(StoredValue::Account(account)) => {
1389                    Ok(Some(RuntimeFootprint::new_account_footprint(account)))
1390                }
1391                Some(_other_variant_1) => Err(ExecError::UnexpectedStoredValueVariant),
1392                None => Ok(None),
1393            }
1394        }
1395    }
1396
1397    /// Gets main purse id
1398    pub fn get_main_purse(&mut self) -> Result<URef, ExecError> {
1399        let main_purse = self
1400            .runtime_footprint()
1401            .borrow()
1402            .main_purse()
1403            .ok_or(ExecError::InvalidContext)?;
1404        Ok(main_purse)
1405    }
1406
1407    /// Gets entry point type.
1408    pub fn entry_point_type(&self) -> EntryPointType {
1409        self.entry_point_type
1410    }
1411
1412    /// Gets given contract package with its access_key validated against current context.
1413    pub(crate) fn get_validated_package(
1414        &mut self,
1415        package_hash: PackageHash,
1416    ) -> Result<Package, ExecError> {
1417        let package_hash_key = Key::from(package_hash);
1418        self.validate_key(&package_hash_key)?;
1419        let contract_package = if self.engine_config.enable_entity {
1420            self.read_gs_typed::<Package>(&Key::SmartContract(package_hash.value()))?
1421        } else {
1422            let cp = self.read_gs_typed::<ContractPackage>(&Key::Hash(package_hash.value()))?;
1423            cp.into()
1424        };
1425        Ok(contract_package)
1426    }
1427
1428    pub(crate) fn get_package(&mut self, package_hash: HashAddr) -> Result<Package, ExecError> {
1429        self.tracking_copy
1430            .borrow_mut()
1431            .get_package(package_hash)
1432            .map_err(Into::into)
1433    }
1434
1435    pub(crate) fn get_contract(
1436        &mut self,
1437        contract_hash: ContractHash,
1438    ) -> Result<Contract, ExecError> {
1439        self.tracking_copy
1440            .borrow_mut()
1441            .get_contract(contract_hash)
1442            .map_err(Into::into)
1443    }
1444
1445    pub(crate) fn get_contract_entity(
1446        &mut self,
1447        entity_key: Key,
1448    ) -> Result<(AddressableEntity, bool), ExecError> {
1449        let entity_hash = if let Some(entity_hash) = entity_key.into_entity_hash() {
1450            entity_hash
1451        } else {
1452            return Err(ExecError::UnexpectedKeyVariant(entity_key));
1453        };
1454
1455        let mut tc = self.tracking_copy.borrow_mut();
1456
1457        let key = Key::contract_entity_key(entity_hash);
1458        match tc.read(&key)? {
1459            Some(StoredValue::AddressableEntity(entity)) => Ok((entity, false)),
1460            Some(other) => Err(ExecError::TypeMismatch(StoredValueTypeMismatch::new(
1461                "AddressableEntity".to_string(),
1462                other.type_name(),
1463            ))),
1464            None => match tc.read(&Key::Hash(entity_hash.value()))? {
1465                Some(StoredValue::Contract(contract)) => Ok((contract.into(), true)),
1466                Some(other) => Err(ExecError::TypeMismatch(StoredValueTypeMismatch::new(
1467                    "Contract".to_string(),
1468                    other.type_name(),
1469                ))),
1470                None => Err(TrackingCopyError::KeyNotFound(key).into()),
1471            },
1472        }
1473    }
1474
1475    /// Gets a dictionary item key from a dictionary referenced by a `uref`.
1476    pub(crate) fn dictionary_get(
1477        &mut self,
1478        uref: URef,
1479        dictionary_item_key: &str,
1480    ) -> Result<Option<CLValue>, ExecError> {
1481        self.validate_readable(&uref.into())?;
1482        self.validate_key(&uref.into())?;
1483        let dictionary_item_key_bytes = dictionary_item_key.as_bytes();
1484
1485        if dictionary_item_key_bytes.len() > DICTIONARY_ITEM_KEY_MAX_LENGTH {
1486            return Err(ExecError::DictionaryItemKeyExceedsLength);
1487        }
1488
1489        let dictionary_key = Key::dictionary(uref, dictionary_item_key_bytes);
1490        self.dictionary_read(dictionary_key)
1491    }
1492
1493    /// Gets a dictionary value from a dictionary `Key`.
1494    pub(crate) fn dictionary_read(
1495        &mut self,
1496        dictionary_key: Key,
1497    ) -> Result<Option<CLValue>, ExecError> {
1498        let maybe_stored_value = self
1499            .tracking_copy
1500            .borrow_mut()
1501            .read(&dictionary_key)
1502            .map_err(Into::<ExecError>::into)?;
1503
1504        if let Some(stored_value) = maybe_stored_value {
1505            let stored_value = handle_stored_dictionary_value(dictionary_key, stored_value)?;
1506            let cl_value = CLValue::try_from(stored_value).map_err(ExecError::TypeMismatch)?;
1507            Ok(Some(cl_value))
1508        } else {
1509            Ok(None)
1510        }
1511    }
1512
1513    /// Puts a dictionary item key from a dictionary referenced by a `uref`.
1514    pub fn dictionary_put(
1515        &mut self,
1516        seed_uref: URef,
1517        dictionary_item_key: &str,
1518        cl_value: CLValue,
1519    ) -> Result<(), ExecError> {
1520        let dictionary_item_key_bytes = dictionary_item_key.as_bytes();
1521
1522        if dictionary_item_key_bytes.len() > DICTIONARY_ITEM_KEY_MAX_LENGTH {
1523            return Err(ExecError::DictionaryItemKeyExceedsLength);
1524        }
1525
1526        self.validate_writeable(&seed_uref.into())?;
1527        self.validate_uref(&seed_uref)?;
1528
1529        self.validate_cl_value(&cl_value)?;
1530
1531        let wrapped_cl_value = {
1532            let dictionary_value = CLValueDictionary::new(
1533                cl_value,
1534                seed_uref.addr().to_vec(),
1535                dictionary_item_key_bytes.to_vec(),
1536            );
1537            CLValue::from_t(dictionary_value).map_err(ExecError::from)?
1538        };
1539
1540        let dictionary_key = Key::dictionary(seed_uref, dictionary_item_key_bytes);
1541        self.metered_write_gs_unsafe(dictionary_key, wrapped_cl_value)?;
1542        Ok(())
1543    }
1544
1545    /// Gets system contract by name.
1546    pub(crate) fn get_system_contract(
1547        &self,
1548        name: &str,
1549    ) -> Result<AddressableEntityHash, ExecError> {
1550        let registry = self.system_entity_registry()?;
1551        let hash = registry.get(name).ok_or_else(|| {
1552            error!("Missing system contract hash: {}", name);
1553            ExecError::MissingSystemContractHash(name.to_string())
1554        })?;
1555        Ok(AddressableEntityHash::new(*hash))
1556    }
1557
1558    pub(crate) fn get_system_entity_key(&self, name: &str) -> Result<Key, ExecError> {
1559        let system_entity_hash = self.get_system_contract(name)?;
1560        if self.engine_config.enable_entity {
1561            Ok(Key::addressable_entity_key(
1562                EntityKindTag::System,
1563                system_entity_hash,
1564            ))
1565        } else {
1566            Ok(Key::Hash(system_entity_hash.value()))
1567        }
1568    }
1569
1570    /// Returns system entity registry by querying the global state.
1571    pub fn system_entity_registry(&self) -> Result<SystemHashRegistry, ExecError> {
1572        self.tracking_copy
1573            .borrow_mut()
1574            .get_system_entity_registry()
1575            .map_err(|err| {
1576                error!("Missing system entity registry");
1577                ExecError::TrackingCopy(err)
1578            })
1579    }
1580
1581    pub(super) fn remaining_spending_limit(&self) -> U512 {
1582        self.remaining_spending_limit
1583    }
1584
1585    /// Subtract spent amount from the main purse spending limit.
1586    pub(crate) fn subtract_amount_spent(&mut self, amount: U512) -> Option<U512> {
1587        if let Some(res) = self.remaining_spending_limit.checked_sub(amount) {
1588            self.remaining_spending_limit = res;
1589            Some(self.remaining_spending_limit)
1590        } else {
1591            error!(
1592                limit = %self.remaining_spending_limit,
1593                spent = %amount,
1594                "exceeded main purse spending limit"
1595            );
1596            self.remaining_spending_limit = U512::zero();
1597            None
1598        }
1599    }
1600
1601    /// Sets a new spending limit.
1602    /// Should be called after inner context returns - if tokens were spent there, it must count
1603    /// towards global limit for the whole deploy execution.
1604    pub(crate) fn set_remaining_spending_limit(&mut self, amount: U512) {
1605        self.remaining_spending_limit = amount;
1606    }
1607
1608    /// Adds new message topic.
1609    pub(crate) fn add_message_topic(
1610        &mut self,
1611        topic_name: &str,
1612        topic_name_hash: TopicNameHash,
1613    ) -> Result<Result<(), MessageTopicError>, ExecError> {
1614        let entity_addr = self.context_key_to_entity_addr()?;
1615
1616        // Take the addressable entity out of the global state
1617        {
1618            let mut message_topics = self
1619                .tracking_copy
1620                .borrow_mut()
1621                .get_message_topics(entity_addr)?;
1622
1623            let max_topics_per_contract = self
1624                .engine_config
1625                .wasm_config()
1626                .messages_limits()
1627                .max_topics_per_contract();
1628
1629            if message_topics.len() >= max_topics_per_contract as usize {
1630                return Ok(Err(MessageTopicError::MaxTopicsExceeded));
1631            }
1632
1633            if let Err(e) = message_topics.add_topic(topic_name, topic_name_hash) {
1634                return Ok(Err(e));
1635            }
1636        }
1637
1638        let topic_key = Key::Message(MessageAddr::new_topic_addr(entity_addr, topic_name_hash));
1639        let block_time = self.block_info.block_time();
1640        let summary = StoredValue::MessageTopic(MessageTopicSummary::new(
1641            0,
1642            block_time,
1643            topic_name.to_string(),
1644        ));
1645
1646        self.metered_write_gs_unsafe(topic_key, summary)?;
1647
1648        Ok(Ok(()))
1649    }
1650}