casper_execution_engine/runtime/
mod.rs

1//! This module contains executor state of the WASM code.
2mod args;
3mod auction_internal;
4pub mod cryptography;
5mod externals;
6mod handle_payment_internal;
7mod host_function_flag;
8mod mint_internal;
9pub mod stack;
10mod utils;
11pub(crate) mod wasm_prep;
12
13use std::{
14    cmp,
15    collections::{BTreeMap, BTreeSet},
16    convert::{TryFrom, TryInto},
17    iter::FromIterator,
18};
19
20use casper_wasm::elements::Module;
21use casper_wasmi::{MemoryRef, Trap, TrapCode};
22use tracing::{debug, error, warn};
23
24#[cfg(feature = "test-support")]
25use casper_wasmi::RuntimeValue;
26use itertools::Itertools;
27use num_rational::Ratio;
28
29use casper_storage::{
30    global_state::{error::Error as GlobalStateError, state::StateReader},
31    system::{auction::Auction, handle_payment::HandlePayment, mint::Mint},
32    tracking_copy::TrackingCopyExt,
33};
34use casper_types::{
35    account::{
36        Account, AccountHash, AddKeyFailure, RemoveKeyFailure, SetThresholdFailure,
37        UpdateKeyFailure,
38    },
39    addressable_entity::{
40        self, ActionThresholds, ActionType, AddressableEntity, AddressableEntityHash,
41        AssociatedKeys, ContractRuntimeTag, EntityEntryPoint, EntryPointAccess, EntryPointType,
42        EntryPoints, MessageTopicError, MessageTopics, NamedKeyAddr, NamedKeyValue, Parameter,
43        Weight, DEFAULT_ENTRY_POINT_NAME,
44    },
45    bytesrepr::{self, Bytes, FromBytes, ToBytes},
46    contract_messages::{
47        Message, MessageAddr, MessagePayload, MessageTopicOperation, MessageTopicSummary,
48    },
49    contracts::{
50        ContractHash, ContractPackage, ContractPackageHash, ContractPackageStatus,
51        ContractVersions, DisabledVersions, NamedKeys, ProtocolVersionMajor,
52    },
53    system::{
54        self,
55        auction::{self, DelegatorKind, EraInfo},
56        handle_payment, mint, CallStackElement, Caller, CallerInfo, SystemEntityType, AUCTION,
57        HANDLE_PAYMENT, MINT, STANDARD_PAYMENT,
58    },
59    AccessRights, ApiError, BlockGlobalAddr, BlockTime, ByteCode, ByteCodeAddr, ByteCodeHash,
60    ByteCodeKind, CLTyped, CLValue, ContextAccessRights, Contract, ContractWasm, EntityAddr,
61    EntityKind, EntityVersion, EntityVersionKey, EntityVersions, Gas, GrantedAccess, Group, Groups,
62    HashAddr, HostFunction, HostFunctionCost, InitiatorAddr, Key, NamedArg, Package, PackageHash,
63    PackageStatus, Phase, PublicKey, RuntimeArgs, RuntimeFootprint, StoredValue, Transfer,
64    TransferResult, TransferV2, TransferredTo, URef, DICTIONARY_ITEM_KEY_MAX_LENGTH, U512,
65};
66
67use crate::{
68    execution::ExecError, runtime::host_function_flag::HostFunctionFlag,
69    runtime_context::RuntimeContext,
70};
71pub use stack::{RuntimeStack, RuntimeStackFrame, RuntimeStackOverflow};
72pub use wasm_prep::{
73    cycles_for_instruction, preprocess, PreprocessingError, WasmValidationError,
74    DEFAULT_BR_TABLE_MAX_SIZE, DEFAULT_MAX_GLOBALS, DEFAULT_MAX_PARAMETER_COUNT,
75    DEFAULT_MAX_TABLE_SIZE,
76};
77
78#[derive(Debug)]
79enum CallContractIdentifier {
80    Contract {
81        contract_hash: HashAddr,
82    },
83    ContractPackage {
84        contract_package_hash: HashAddr,
85        version: Option<EntityVersion>,
86        protocol_version_major: Option<ProtocolVersionMajor>,
87    },
88}
89
90#[repr(u8)]
91enum CallerInformation {
92    Initiator = 0,
93    Immediate = 1,
94    FullCallChain = 2,
95}
96
97impl TryFrom<u8> for CallerInformation {
98    type Error = ApiError;
99
100    fn try_from(value: u8) -> Result<Self, Self::Error> {
101        match value {
102            0 => Ok(CallerInformation::Initiator),
103            1 => Ok(CallerInformation::Immediate),
104            2 => Ok(CallerInformation::FullCallChain),
105            _ => Err(ApiError::InvalidCallerInfoRequest),
106        }
107    }
108}
109
110/// Represents the runtime properties of a WASM execution.
111pub struct Runtime<'a, R> {
112    context: RuntimeContext<'a, R>,
113    memory: Option<MemoryRef>,
114    module: Option<Module>,
115    host_buffer: Option<CLValue>,
116    stack: Option<RuntimeStack>,
117    host_function_flag: HostFunctionFlag,
118}
119
120impl<'a, R> Runtime<'a, R>
121where
122    R: StateReader<Key, StoredValue, Error = GlobalStateError>,
123{
124    /// Creates a new runtime instance.
125    pub(crate) fn new(context: RuntimeContext<'a, R>) -> Self {
126        Runtime {
127            context,
128            memory: None,
129            module: None,
130            host_buffer: None,
131            stack: None,
132            host_function_flag: HostFunctionFlag::default(),
133        }
134    }
135
136    /// Creates a new runtime instance by cloning the config, and host function flag from `self`.
137    fn new_invocation_runtime(
138        &self,
139        context: RuntimeContext<'a, R>,
140        module: Module,
141        memory: MemoryRef,
142        stack: RuntimeStack,
143    ) -> Self {
144        Self::check_preconditions(&stack);
145        Runtime {
146            context,
147            memory: Some(memory),
148            module: Some(module),
149            host_buffer: None,
150            stack: Some(stack),
151            host_function_flag: self.host_function_flag.clone(),
152        }
153    }
154
155    /// Creates a new runtime instance with a stack from `self`.
156    pub(crate) fn new_with_stack(
157        &self,
158        context: RuntimeContext<'a, R>,
159        stack: RuntimeStack,
160    ) -> Self {
161        Self::check_preconditions(&stack);
162        Runtime {
163            context,
164            memory: None,
165            module: None,
166            host_buffer: None,
167            stack: Some(stack),
168            host_function_flag: self.host_function_flag.clone(),
169        }
170    }
171
172    /// Preconditions that would render the system inconsistent if violated. Those are strictly
173    /// programming errors.
174    fn check_preconditions(stack: &RuntimeStack) {
175        if stack.is_empty() {
176            error!("Call stack should not be empty while creating a new Runtime instance");
177            debug_assert!(false);
178        }
179
180        if stack.first_frame().unwrap().contract_hash().is_some() {
181            error!("First element of the call stack should always represent a Session call");
182            debug_assert!(false);
183        }
184    }
185
186    /// Returns the context.
187    pub(crate) fn context(&self) -> &RuntimeContext<'a, R> {
188        &self.context
189    }
190
191    fn gas(&mut self, amount: Gas) -> Result<(), ExecError> {
192        self.context.charge_gas(amount)
193    }
194
195    /// Returns current gas counter.
196    fn gas_counter(&self) -> Gas {
197        self.context.gas_counter()
198    }
199
200    /// Sets new gas counter value.
201    fn set_gas_counter(&mut self, new_gas_counter: Gas) {
202        self.context.set_gas_counter(new_gas_counter);
203    }
204
205    /// Charge for a system contract call.
206    ///
207    /// This method does not charge for system contract calls if the immediate caller is a system
208    /// contract or if we're currently within the scope of a host function call. This avoids
209    /// misleading gas charges if one system contract calls other system contract (e.g. auction
210    /// contract calls into mint to create new purses).
211    pub(crate) fn charge_system_contract_call<T>(&mut self, amount: T) -> Result<(), ExecError>
212    where
213        T: Into<Gas>,
214    {
215        if self.is_system_immediate_caller()? || self.host_function_flag.is_in_host_function_scope()
216        {
217            return Ok(());
218        }
219
220        self.context.charge_system_contract_call(amount)
221    }
222
223    fn checked_memory_slice<Ret>(
224        &self,
225        offset: usize,
226        size: usize,
227        func: impl FnOnce(&[u8]) -> Ret,
228    ) -> Result<Ret, ExecError> {
229        // This is mostly copied from a private function `MemoryInstance::checked_memory_region`
230        // that calls a user defined function with a validated slice of memory. This allows
231        // usage patterns that does not involve copying data onto heap first i.e. deserialize
232        // values without copying data first, etc.
233        // NOTE: Depending on the VM backend used in future, this may change, as not all VMs may
234        // support direct memory access.
235        self.try_get_memory()?
236            .with_direct_access(|buffer| {
237                let end = offset.checked_add(size).ok_or_else(|| {
238                    casper_wasmi::Error::Memory(format!(
239                        "trying to access memory block of size {} from offset {}",
240                        size, offset
241                    ))
242                })?;
243
244                if end > buffer.len() {
245                    return Err(casper_wasmi::Error::Memory(format!(
246                        "trying to access region [{}..{}] in memory [0..{}]",
247                        offset,
248                        end,
249                        buffer.len(),
250                    )));
251                }
252
253                Ok(func(&buffer[offset..end]))
254            })
255            .map_err(Into::into)
256    }
257
258    /// Returns bytes from the WASM memory instance.
259    #[inline]
260    fn bytes_from_mem(&self, ptr: u32, size: usize) -> Result<Vec<u8>, ExecError> {
261        self.checked_memory_slice(ptr as usize, size, |data| data.to_vec())
262    }
263
264    /// Returns a deserialized type from the WASM memory instance.
265    #[inline]
266    fn t_from_mem<T: FromBytes>(&self, ptr: u32, size: u32) -> Result<T, ExecError> {
267        let result = self.checked_memory_slice(ptr as usize, size as usize, |data| {
268            bytesrepr::deserialize_from_slice(data)
269        })?;
270        Ok(result?)
271    }
272
273    /// Reads key (defined as `key_ptr` and `key_size` tuple) from Wasm memory.
274    #[inline]
275    fn key_from_mem(&mut self, key_ptr: u32, key_size: u32) -> Result<Key, ExecError> {
276        self.t_from_mem(key_ptr, key_size)
277    }
278
279    /// Reads `CLValue` (defined as `cl_value_ptr` and `cl_value_size` tuple) from Wasm memory.
280    #[inline]
281    fn cl_value_from_mem(
282        &mut self,
283        cl_value_ptr: u32,
284        cl_value_size: u32,
285    ) -> Result<CLValue, ExecError> {
286        self.t_from_mem(cl_value_ptr, cl_value_size)
287    }
288
289    /// Returns a deserialized string from the WASM memory instance.
290    #[inline]
291    fn string_from_mem(&self, ptr: u32, size: u32) -> Result<String, Trap> {
292        self.t_from_mem(ptr, size).map_err(Trap::from)
293    }
294
295    fn get_module_from_entry_points(
296        &mut self,
297        entry_points: &EntryPoints,
298    ) -> Result<Vec<u8>, ExecError> {
299        let module = self.try_get_module()?.clone();
300        let entry_point_names: Vec<&str> = entry_points.keys().map(|s| s.as_str()).collect();
301        let module_bytes = wasm_prep::get_module_from_entry_points(entry_point_names, module)?;
302        Ok(module_bytes)
303    }
304
305    #[allow(clippy::wrong_self_convention)]
306    fn is_valid_uref(&self, uref_ptr: u32, uref_size: u32) -> Result<bool, Trap> {
307        let uref: URef = self.t_from_mem(uref_ptr, uref_size)?;
308        Ok(self.context.validate_uref(&uref).is_ok())
309    }
310
311    /// Load the uref known by the given name into the Wasm memory
312    fn load_key(
313        &mut self,
314        name_ptr: u32,
315        name_size: u32,
316        output_ptr: u32,
317        output_size: usize,
318        bytes_written_ptr: u32,
319    ) -> Result<Result<(), ApiError>, Trap> {
320        let name = self.string_from_mem(name_ptr, name_size)?;
321
322        // Get a key and serialize it
323        let key = match self.context.named_keys_get(&name) {
324            Some(key) => key,
325            None => {
326                return Ok(Err(ApiError::MissingKey));
327            }
328        };
329
330        let key_bytes = match key.to_bytes() {
331            Ok(bytes) => bytes,
332            Err(error) => return Ok(Err(error.into())),
333        };
334
335        // `output_size` has to be greater or equal to the actual length of serialized Key bytes
336        if output_size < key_bytes.len() {
337            return Ok(Err(ApiError::BufferTooSmall));
338        }
339
340        // Set serialized Key bytes into the output buffer
341        if let Err(error) = self.try_get_memory()?.set(output_ptr, &key_bytes) {
342            return Err(ExecError::Interpreter(error.into()).into());
343        }
344
345        // SAFETY: For all practical purposes following conversion is assumed to be safe
346        let bytes_size: u32 = key_bytes
347            .len()
348            .try_into()
349            .expect("Keys should not serialize to many bytes");
350        let size_bytes = bytes_size.to_le_bytes(); // Wasm is little-endian
351        if let Err(error) = self.try_get_memory()?.set(bytes_written_ptr, &size_bytes) {
352            return Err(ExecError::Interpreter(error.into()).into());
353        }
354
355        Ok(Ok(()))
356    }
357
358    fn has_key(&mut self, name_ptr: u32, name_size: u32) -> Result<i32, Trap> {
359        let name = self.string_from_mem(name_ptr, name_size)?;
360        if self.context.named_keys_contains_key(&name) {
361            Ok(0)
362        } else {
363            Ok(1)
364        }
365    }
366
367    fn put_key(
368        &mut self,
369        name_ptr: u32,
370        name_size: u32,
371        key_ptr: u32,
372        key_size: u32,
373    ) -> Result<(), Trap> {
374        let name = self.string_from_mem(name_ptr, name_size)?;
375        let key = self.key_from_mem(key_ptr, key_size)?;
376
377        if let Some(payment_purse) = self.context.maybe_payment_purse() {
378            if Key::URef(payment_purse).normalize() == key.normalize() {
379                warn!("attempt to put_key payment purse");
380                return Err(Into::into(ExecError::Revert(ApiError::HandlePayment(
381                    handle_payment::Error::AttemptToPersistPaymentPurse as u8,
382                ))));
383            }
384        }
385        self.context.put_key(name, key).map_err(Into::into)
386    }
387
388    fn remove_key(&mut self, name_ptr: u32, name_size: u32) -> Result<(), Trap> {
389        let name = self.string_from_mem(name_ptr, name_size)?;
390        self.context.remove_key(&name)?;
391        Ok(())
392    }
393
394    /// Writes runtime context's account main purse to dest_ptr in the Wasm memory.
395    fn get_main_purse(&mut self, dest_ptr: u32) -> Result<(), Trap> {
396        let purse = self.context.get_main_purse()?;
397        let purse_bytes = purse.into_bytes().map_err(ExecError::BytesRepr)?;
398        self.try_get_memory()?
399            .set(dest_ptr, &purse_bytes)
400            .map_err(|e| ExecError::Interpreter(e.into()).into())
401    }
402
403    /// Writes caller (deploy) account public key to output_size_ptr in the Wasm
404    /// memory.
405    fn get_caller(&mut self, output_size_ptr: u32) -> Result<Result<(), ApiError>, Trap> {
406        if !self.can_write_to_host_buffer() {
407            // Exit early if the host buffer is already occupied
408            return Ok(Err(ApiError::HostBufferFull));
409        }
410        let value = CLValue::from_t(self.context.get_initiator()).map_err(ExecError::CLValue)?;
411        let value_size = value.inner_bytes().len();
412
413        // Save serialized public key into host buffer
414        if let Err(error) = self.write_host_buffer(value) {
415            return Ok(Err(error));
416        }
417
418        // Write output
419        let output_size_bytes = value_size.to_le_bytes(); // Wasm is little-endian
420        if let Err(error) = self
421            .try_get_memory()?
422            .set(output_size_ptr, &output_size_bytes)
423        {
424            return Err(ExecError::Interpreter(error.into()).into());
425        }
426        Ok(Ok(()))
427    }
428
429    /// Gets the immediate caller of the current execution
430    fn get_immediate_caller(&self) -> Option<&RuntimeStackFrame> {
431        self.stack.as_ref().and_then(|stack| stack.previous_frame())
432    }
433
434    /// Checks if immediate caller is of session type of the same account as the provided account
435    /// hash.
436    fn is_allowed_session_caller(&self, provided_account_hash: &AccountHash) -> bool {
437        if self.context.get_initiator() == PublicKey::System.to_account_hash() {
438            return true;
439        }
440
441        if let Some(Caller::Initiator { account_hash }) = self.get_immediate_caller() {
442            return account_hash == provided_account_hash;
443        }
444        false
445    }
446
447    /// Writes runtime context's phase to dest_ptr in the Wasm memory.
448    fn get_phase(&mut self, dest_ptr: u32) -> Result<(), Trap> {
449        let phase = self.context.phase();
450        let bytes = phase.into_bytes().map_err(ExecError::BytesRepr)?;
451        self.try_get_memory()?
452            .set(dest_ptr, &bytes)
453            .map_err(|e| ExecError::Interpreter(e.into()).into())
454    }
455
456    /// Writes requested field from runtime context's block info to dest_ptr in the Wasm memory.
457    fn get_block_info(&self, field_idx: u8, dest_ptr: u32) -> Result<(), Trap> {
458        if field_idx == 0 {
459            // original functionality
460            return self.get_blocktime(dest_ptr);
461        }
462        let block_info = self.context.get_block_info();
463
464        let mut data: Vec<u8> = vec![];
465        if field_idx == 1 {
466            data = block_info
467                .block_height()
468                .into_bytes()
469                .map_err(ExecError::BytesRepr)?;
470        }
471        if field_idx == 2 {
472            data = block_info
473                .parent_block_hash()
474                .into_bytes()
475                .map_err(ExecError::BytesRepr)?;
476        }
477        if field_idx == 3 {
478            data = block_info
479                .state_hash()
480                .into_bytes()
481                .map_err(ExecError::BytesRepr)?;
482        }
483        if field_idx == 4 {
484            data = self
485                .context
486                .protocol_version()
487                .into_bytes()
488                .map_err(ExecError::BytesRepr)?;
489        }
490        if field_idx == 5 {
491            data = self
492                .context
493                .engine_config()
494                .enable_entity
495                .into_bytes()
496                .map_err(ExecError::BytesRepr)?;
497        }
498        if data.is_empty() {
499            Err(ExecError::InvalidImputedOperation.into())
500        } else {
501            Ok(self
502                .try_get_memory()?
503                .set(dest_ptr, &data)
504                .map_err(|e| ExecError::Interpreter(e.into()))?)
505        }
506    }
507
508    /// Writes current blocktime to dest_ptr in Wasm memory.
509    fn get_blocktime(&self, dest_ptr: u32) -> Result<(), Trap> {
510        let block_info = self.context.get_block_info();
511        let blocktime = block_info
512            .block_time()
513            .into_bytes()
514            .map_err(ExecError::BytesRepr)?;
515        self.try_get_memory()?
516            .set(dest_ptr, &blocktime)
517            .map_err(|e| ExecError::Interpreter(e.into()).into())
518    }
519
520    /// Load the uref known by the given name into the Wasm memory
521    fn load_call_stack(
522        &mut self,
523        // (Output) Pointer to number of elements in the call stack.
524        call_stack_len_ptr: u32,
525        // (Output) Pointer to size in bytes of the serialized call stack.
526        result_size_ptr: u32,
527    ) -> Result<Result<(), ApiError>, Trap> {
528        if !self.can_write_to_host_buffer() {
529            // Exit early if the host buffer is already occupied
530            return Ok(Err(ApiError::HostBufferFull));
531        }
532        let call_stack: Vec<CallStackElement> = match self.try_get_stack() {
533            Ok(stack) => {
534                let caller = stack.call_stack_elements();
535                caller.iter().map_into().collect_vec()
536            }
537            Err(_error) => return Ok(Err(ApiError::Unhandled)),
538        };
539        let call_stack_len: u32 = match call_stack.len().try_into() {
540            Ok(value) => value,
541            Err(_) => return Ok(Err(ApiError::OutOfMemory)),
542        };
543        let call_stack_len_bytes = call_stack_len.to_le_bytes();
544
545        if let Err(error) = self
546            .try_get_memory()?
547            .set(call_stack_len_ptr, &call_stack_len_bytes)
548        {
549            return Err(ExecError::Interpreter(error.into()).into());
550        }
551
552        if call_stack_len == 0 {
553            return Ok(Ok(()));
554        }
555
556        let call_stack_cl_value = CLValue::from_t(call_stack).map_err(ExecError::CLValue)?;
557
558        let call_stack_cl_value_bytes_len: u32 =
559            match call_stack_cl_value.inner_bytes().len().try_into() {
560                Ok(value) => value,
561                Err(_) => return Ok(Err(ApiError::OutOfMemory)),
562            };
563
564        if let Err(error) = self.write_host_buffer(call_stack_cl_value) {
565            return Ok(Err(error));
566        }
567
568        let call_stack_cl_value_bytes_len_bytes = call_stack_cl_value_bytes_len.to_le_bytes();
569
570        if let Err(error) = self
571            .try_get_memory()?
572            .set(result_size_ptr, &call_stack_cl_value_bytes_len_bytes)
573        {
574            return Err(ExecError::Interpreter(error.into()).into());
575        }
576
577        Ok(Ok(()))
578    }
579
580    /// Returns information about the call stack based on a given action.
581    fn load_caller_information(
582        &mut self,
583        information: u8,
584        // (Output) Pointer to number of elements in the call stack.
585        call_stack_len_ptr: u32,
586        // (Output) Pointer to size in bytes of the serialized call stack.
587        result_size_ptr: u32,
588    ) -> Result<Result<(), ApiError>, Trap> {
589        if !self.can_write_to_host_buffer() {
590            // Exit early if the host buffer is already occupied
591            return Ok(Err(ApiError::HostBufferFull));
592        }
593
594        let caller_info = match CallerInformation::try_from(information) {
595            Ok(info) => info,
596            Err(error) => return Ok(Err(error)),
597        };
598
599        let caller = match caller_info {
600            CallerInformation::Initiator => {
601                let initiator_account_hash = self.context.get_initiator();
602                let caller = Caller::initiator(initiator_account_hash);
603                match CallerInfo::try_from(caller) {
604                    Ok(caller_info) => {
605                        vec![caller_info]
606                    }
607                    Err(_) => return Ok(Err(ApiError::CLTypeMismatch)),
608                }
609            }
610            CallerInformation::Immediate => match self.get_immediate_caller() {
611                Some(frame) => match CallerInfo::try_from(*frame) {
612                    Ok(immediate_info) => {
613                        vec![immediate_info]
614                    }
615                    Err(_) => return Ok(Err(ApiError::CLTypeMismatch)),
616                },
617                None => return Ok(Err(ApiError::Unhandled)),
618            },
619            CallerInformation::FullCallChain => match self.try_get_stack() {
620                Ok(call_stack) => {
621                    let call_stack = call_stack.call_stack_elements().clone();
622
623                    let mut ret = vec![];
624                    for caller in call_stack {
625                        match CallerInfo::try_from(caller) {
626                            Ok(info) => ret.push(info),
627                            Err(_) => return Ok(Err(ApiError::CLTypeMismatch)),
628                        }
629                    }
630                    ret
631                }
632                Err(_) => return Ok(Err(ApiError::Unhandled)),
633            },
634        };
635
636        let call_stack_len: u32 = match caller.len().try_into() {
637            Ok(value) => value,
638            Err(_) => return Ok(Err(ApiError::OutOfMemory)),
639        };
640        let call_stack_len_bytes = call_stack_len.to_le_bytes();
641
642        if let Err(error) = self
643            .try_get_memory()?
644            .set(call_stack_len_ptr, &call_stack_len_bytes)
645        {
646            return Err(ExecError::Interpreter(error.into()).into());
647        }
648
649        if call_stack_len == 0 {
650            return Ok(Ok(()));
651        }
652
653        let call_stack_cl_value = CLValue::from_t(caller).map_err(ExecError::CLValue)?;
654
655        let call_stack_cl_value_bytes_len: u32 =
656            match call_stack_cl_value.inner_bytes().len().try_into() {
657                Ok(value) => value,
658                Err(_) => return Ok(Err(ApiError::OutOfMemory)),
659            };
660
661        if let Err(error) = self.write_host_buffer(call_stack_cl_value) {
662            return Ok(Err(error));
663        }
664
665        let call_stack_cl_value_bytes_len_bytes = call_stack_cl_value_bytes_len.to_le_bytes();
666
667        if let Err(error) = self
668            .try_get_memory()?
669            .set(result_size_ptr, &call_stack_cl_value_bytes_len_bytes)
670        {
671            return Err(ExecError::Interpreter(error.into()).into());
672        }
673
674        Ok(Ok(()))
675    }
676
677    /// Return some bytes from the memory and terminate the current `sub_call`. Note that the return
678    /// type is `Trap`, indicating that this function will always kill the current Wasm instance.
679    fn ret(&mut self, value_ptr: u32, value_size: usize) -> Trap {
680        self.host_buffer = None;
681
682        let mem_get =
683            self.checked_memory_slice(value_ptr as usize, value_size, |data| data.to_vec());
684
685        match mem_get {
686            Ok(buf) => {
687                // Set the result field in the runtime and return the proper element of the `Error`
688                // enum indicating that the reason for exiting the module was a call to ret.
689                self.host_buffer = bytesrepr::deserialize_from_slice(buf).ok();
690
691                let urefs = match &self.host_buffer {
692                    Some(buf) => utils::extract_urefs(buf),
693                    None => Ok(vec![]),
694                };
695                match urefs {
696                    Ok(urefs) => {
697                        for uref in &urefs {
698                            if let Err(error) = self.context.validate_uref(uref) {
699                                return Trap::from(error);
700                            }
701                        }
702                        ExecError::Ret(urefs).into()
703                    }
704                    Err(e) => e.into(),
705                }
706            }
707            Err(e) => e.into(),
708        }
709    }
710
711    /// Checks if a [`HashAddr`] corresponds to a system contract.
712    fn is_system_contract(&self, hash_addr: HashAddr) -> Result<bool, ExecError> {
713        self.context.is_system_addressable_entity(&hash_addr)
714    }
715
716    fn get_named_argument<T: FromBytes + CLTyped>(
717        args: &RuntimeArgs,
718        name: &str,
719    ) -> Result<T, ExecError> {
720        let arg: CLValue = args
721            .get(name)
722            .cloned()
723            .ok_or(ExecError::Revert(ApiError::MissingArgument))?;
724        arg.into_t()
725            .map_err(|_| ExecError::Revert(ApiError::InvalidArgument))
726    }
727
728    fn try_get_named_argument<T: FromBytes + CLTyped>(
729        args: &RuntimeArgs,
730        name: &str,
731    ) -> Result<Option<T>, ExecError> {
732        match args.get(name) {
733            Some(arg) => {
734                let arg = arg
735                    .clone()
736                    .into_t()
737                    .map_err(|_| ExecError::Revert(ApiError::InvalidArgument))?;
738                Ok(Some(arg))
739            }
740            None => Ok(None),
741        }
742    }
743
744    fn reverter<T: Into<ApiError>>(error: T) -> ExecError {
745        let api_error: ApiError = error.into();
746        // NOTE: This is special casing needed to keep the native system contracts propagate
747        // GasLimit properly to the user. Once support for wasm system contract will be dropped this
748        // won't be necessary anymore.
749        match api_error {
750            ApiError::Mint(mint_error) if mint_error == mint::Error::GasLimit as u8 => {
751                ExecError::GasLimit
752            }
753            ApiError::AuctionError(auction_error)
754                if auction_error == auction::Error::GasLimit as u8 =>
755            {
756                ExecError::GasLimit
757            }
758            ApiError::HandlePayment(handle_payment_error)
759                if handle_payment_error == handle_payment::Error::GasLimit as u8 =>
760            {
761                ExecError::GasLimit
762            }
763            api_error => ExecError::Revert(api_error),
764        }
765    }
766
767    /// Calls host mint contract.
768    fn call_host_mint(
769        &mut self,
770        entry_point_name: &str,
771        runtime_args: &RuntimeArgs,
772        access_rights: ContextAccessRights,
773        stack: RuntimeStack,
774    ) -> Result<CLValue, ExecError> {
775        let gas_counter = self.gas_counter();
776
777        let mint_hash = self.context.get_system_contract(MINT)?;
778        let mint_addr = EntityAddr::new_system(mint_hash.value());
779        let mint_key = if self.context.engine_config().enable_entity {
780            Key::AddressableEntity(EntityAddr::System(mint_hash.value()))
781        } else {
782            Key::Hash(mint_hash.value())
783        };
784
785        let mint_named_keys = self
786            .context
787            .state()
788            .borrow_mut()
789            .get_named_keys(mint_addr)?;
790
791        let mut named_keys = mint_named_keys;
792
793        let runtime_context = self.context.new_from_self(
794            mint_key,
795            EntryPointType::Called,
796            &mut named_keys,
797            access_rights,
798            runtime_args.to_owned(),
799        );
800
801        let mut mint_runtime = self.new_with_stack(runtime_context, stack);
802
803        let engine_config = self.context.engine_config();
804        let system_config = engine_config.system_config();
805        let mint_costs = system_config.mint_costs();
806
807        let result = match entry_point_name {
808            // Type: `fn mint(amount: U512) -> Result<URef, ExecError>`
809            mint::METHOD_MINT => (|| {
810                mint_runtime.charge_system_contract_call(mint_costs.mint)?;
811
812                let amount: U512 = Self::get_named_argument(runtime_args, mint::ARG_AMOUNT)?;
813                let result: Result<URef, mint::Error> = mint_runtime.mint(amount);
814                if let Err(mint::Error::GasLimit) = result {
815                    return Err(ExecError::GasLimit);
816                }
817                CLValue::from_t(result).map_err(Self::reverter)
818            })(),
819            mint::METHOD_REDUCE_TOTAL_SUPPLY => (|| {
820                mint_runtime.charge_system_contract_call(mint_costs.reduce_total_supply)?;
821
822                let amount: U512 = Self::get_named_argument(runtime_args, mint::ARG_AMOUNT)?;
823                let result: Result<(), mint::Error> = mint_runtime.reduce_total_supply(amount);
824                CLValue::from_t(result).map_err(Self::reverter)
825            })(),
826            mint::METHOD_BURN => (|| {
827                mint_runtime.charge_system_contract_call(mint_costs.burn)?;
828
829                let purse: URef = Self::get_named_argument(runtime_args, mint::ARG_PURSE)?;
830                let amount: U512 = Self::get_named_argument(runtime_args, mint::ARG_AMOUNT)?;
831                let result: Result<(), mint::Error> = mint_runtime.burn(purse, amount);
832                CLValue::from_t(result).map_err(Self::reverter)
833            })(),
834            // Type: `fn create() -> URef`
835            mint::METHOD_CREATE => (|| {
836                mint_runtime.charge_system_contract_call(mint_costs.create)?;
837
838                let uref = mint_runtime.mint(U512::zero()).map_err(Self::reverter)?;
839                CLValue::from_t(uref).map_err(Self::reverter)
840            })(),
841            // Type: `fn balance(purse: URef) -> Option<U512>`
842            mint::METHOD_BALANCE => (|| {
843                mint_runtime.charge_system_contract_call(mint_costs.balance)?;
844
845                let uref: URef = Self::get_named_argument(runtime_args, mint::ARG_PURSE)?;
846
847                let maybe_balance: Option<U512> =
848                    mint_runtime.balance(uref).map_err(Self::reverter)?;
849                CLValue::from_t(maybe_balance).map_err(Self::reverter)
850            })(),
851            // Type: `fn transfer(maybe_to: Option<AccountHash>, source: URef, target: URef, amount:
852            // U512, id: Option<u64>) -> Result<(), ExecError>`
853            mint::METHOD_TRANSFER => (|| {
854                mint_runtime.charge_system_contract_call(mint_costs.transfer)?;
855
856                let maybe_to: Option<AccountHash> =
857                    Self::get_named_argument(runtime_args, mint::ARG_TO)?;
858                let source: URef = Self::get_named_argument(runtime_args, mint::ARG_SOURCE)?;
859                let target: URef = Self::get_named_argument(runtime_args, mint::ARG_TARGET)?;
860                let amount: U512 = Self::get_named_argument(runtime_args, mint::ARG_AMOUNT)?;
861                let id: Option<u64> = Self::get_named_argument(runtime_args, mint::ARG_ID)?;
862                let result: Result<(), mint::Error> =
863                    mint_runtime.transfer(maybe_to, source, target, amount, id);
864
865                CLValue::from_t(result).map_err(Self::reverter)
866            })(),
867            // Type: `fn read_base_round_reward() -> Result<U512, ExecError>`
868            mint::METHOD_READ_BASE_ROUND_REWARD => (|| {
869                mint_runtime.charge_system_contract_call(mint_costs.read_base_round_reward)?;
870
871                let result: U512 = mint_runtime
872                    .read_base_round_reward()
873                    .map_err(Self::reverter)?;
874                CLValue::from_t(result).map_err(Self::reverter)
875            })(),
876            mint::METHOD_MINT_INTO_EXISTING_PURSE => (|| {
877                mint_runtime.charge_system_contract_call(mint_costs.mint_into_existing_purse)?;
878
879                let amount: U512 = Self::get_named_argument(runtime_args, mint::ARG_AMOUNT)?;
880                let existing_purse: URef = Self::get_named_argument(runtime_args, mint::ARG_PURSE)?;
881
882                let result: Result<(), mint::Error> =
883                    mint_runtime.mint_into_existing_purse(existing_purse, amount);
884                CLValue::from_t(result).map_err(Self::reverter)
885            })(),
886            _ => {
887                // Code should never reach this point as existence of the entrypoint is validated
888                // before reaching this point.
889                Ok(CLValue::unit())
890            }
891        };
892
893        // Charge just for the amount that particular entry point cost - using gas cost from the
894        // isolated runtime might have a recursive costs whenever system contract calls other system
895        // contract.
896        self.gas(
897            mint_runtime
898                .gas_counter()
899                .checked_sub(gas_counter)
900                .unwrap_or(gas_counter),
901        )?;
902
903        // Result still contains a result, but the entrypoints logic does not exit early on errors.
904        let ret = result?;
905
906        // Update outer spending approved limit.
907        self.context
908            .set_remaining_spending_limit(mint_runtime.context.remaining_spending_limit());
909
910        let urefs = utils::extract_urefs(&ret)?;
911        self.context.access_rights_extend(&urefs);
912        {
913            let transfers = self.context.transfers_mut();
914            mint_runtime.context.transfers().clone_into(transfers);
915        }
916        Ok(ret)
917    }
918
919    /// Calls host `handle_payment` contract.
920    fn call_host_handle_payment(
921        &mut self,
922        entry_point_name: &str,
923        runtime_args: &RuntimeArgs,
924        access_rights: ContextAccessRights,
925        stack: RuntimeStack,
926    ) -> Result<CLValue, ExecError> {
927        let gas_counter = self.gas_counter();
928
929        let handle_payment_hash = self.context.get_system_contract(HANDLE_PAYMENT)?;
930        let handle_payment_key = if self.context.engine_config().enable_entity {
931            Key::AddressableEntity(EntityAddr::System(handle_payment_hash.value()))
932        } else {
933            Key::Hash(handle_payment_hash.value())
934        };
935
936        let handle_payment_named_keys = self
937            .context
938            .state()
939            .borrow_mut()
940            .get_named_keys(EntityAddr::System(handle_payment_hash.value()))?;
941
942        let mut named_keys = handle_payment_named_keys;
943
944        let runtime_context = self.context.new_from_self(
945            handle_payment_key,
946            EntryPointType::Called,
947            &mut named_keys,
948            access_rights,
949            runtime_args.to_owned(),
950        );
951
952        let mut runtime = self.new_with_stack(runtime_context, stack);
953
954        let engine_config = self.context.engine_config();
955        let system_config = engine_config.system_config();
956        let handle_payment_costs = system_config.handle_payment_costs();
957
958        let result = match entry_point_name {
959            handle_payment::METHOD_GET_PAYMENT_PURSE => {
960                runtime.charge_system_contract_call(handle_payment_costs.get_payment_purse)?;
961                match self.context.maybe_payment_purse() {
962                    Some(payment_purse) => CLValue::from_t(payment_purse).map_err(Self::reverter),
963                    None => {
964                        let payment_purse = runtime.get_payment_purse().map_err(Self::reverter)?;
965                        self.context.set_payment_purse(payment_purse);
966                        CLValue::from_t(payment_purse).map_err(Self::reverter)
967                    }
968                }
969            }
970            handle_payment::METHOD_SET_REFUND_PURSE => (|| {
971                runtime.charge_system_contract_call(handle_payment_costs.set_refund_purse)?;
972
973                let purse: URef =
974                    Self::get_named_argument(runtime_args, handle_payment::ARG_PURSE)?;
975                runtime.set_refund_purse(purse).map_err(Self::reverter)?;
976                CLValue::from_t(()).map_err(Self::reverter)
977            })(),
978            handle_payment::METHOD_GET_REFUND_PURSE => (|| {
979                runtime.charge_system_contract_call(handle_payment_costs.get_refund_purse)?;
980
981                let maybe_purse = runtime.get_refund_purse().map_err(Self::reverter)?;
982                CLValue::from_t(maybe_purse).map_err(Self::reverter)
983            })(),
984            _ => {
985                // Code should never reach here as existence of the entrypoint is validated before
986                // reaching this point.
987                Ok(CLValue::unit())
988            }
989        };
990
991        self.gas(
992            runtime
993                .gas_counter()
994                .checked_sub(gas_counter)
995                .unwrap_or(gas_counter),
996        )?;
997
998        let ret = result?;
999
1000        let urefs = utils::extract_urefs(&ret)?;
1001        self.context.access_rights_extend(&urefs);
1002        {
1003            let transfers = self.context.transfers_mut();
1004            runtime.context.transfers().clone_into(transfers);
1005        }
1006        Ok(ret)
1007    }
1008
1009    /// Calls host auction contract.
1010    fn call_host_auction(
1011        &mut self,
1012        entry_point_name: &str,
1013        runtime_args: &RuntimeArgs,
1014        access_rights: ContextAccessRights,
1015        stack: RuntimeStack,
1016    ) -> Result<CLValue, ExecError> {
1017        let gas_counter = self.gas_counter();
1018
1019        let auction_hash = self.context.get_system_contract(AUCTION)?;
1020        let auction_key = if self.context.engine_config().enable_entity {
1021            Key::AddressableEntity(EntityAddr::System(auction_hash.value()))
1022        } else {
1023            Key::Hash(auction_hash.value())
1024        };
1025
1026        let auction_named_keys = self
1027            .context
1028            .state()
1029            .borrow_mut()
1030            .get_named_keys(EntityAddr::System(auction_hash.value()))?;
1031
1032        let mut named_keys = auction_named_keys;
1033
1034        let runtime_context = self.context.new_from_self(
1035            auction_key,
1036            EntryPointType::Called,
1037            &mut named_keys,
1038            access_rights,
1039            runtime_args.to_owned(),
1040        );
1041
1042        let mut runtime = self.new_with_stack(runtime_context, stack);
1043
1044        let engine_config = self.context.engine_config();
1045        let system_config = engine_config.system_config();
1046        let auction_costs = system_config.auction_costs();
1047
1048        let result = match entry_point_name {
1049            auction::METHOD_GET_ERA_VALIDATORS => (|| {
1050                runtime.charge_system_contract_call::<u64>(auction_costs.get_era_validators)?;
1051
1052                let result = runtime.get_era_validators().map_err(Self::reverter)?;
1053
1054                CLValue::from_t(result).map_err(Self::reverter)
1055            })(),
1056
1057            auction::METHOD_ADD_BID => (|| {
1058                runtime.charge_system_contract_call(auction_costs.add_bid)?;
1059                let public_key = Self::get_named_argument(runtime_args, auction::ARG_PUBLIC_KEY)?;
1060                let delegation_rate =
1061                    Self::get_named_argument(runtime_args, auction::ARG_DELEGATION_RATE)?;
1062                let amount = Self::get_named_argument(runtime_args, auction::ARG_AMOUNT)?;
1063
1064                let global_minimum_delegation_amount =
1065                    self.context.engine_config().minimum_delegation_amount();
1066                let minimum_delegation_amount = Self::try_get_named_argument(
1067                    runtime_args,
1068                    auction::ARG_MINIMUM_DELEGATION_AMOUNT,
1069                )?
1070                .unwrap_or(global_minimum_delegation_amount);
1071
1072                let global_maximum_delegation_amount =
1073                    self.context.engine_config().maximum_delegation_amount();
1074                let maximum_delegation_amount = Self::try_get_named_argument(
1075                    runtime_args,
1076                    auction::ARG_MAXIMUM_DELEGATION_AMOUNT,
1077                )?
1078                .unwrap_or(global_maximum_delegation_amount);
1079
1080                if minimum_delegation_amount < global_minimum_delegation_amount
1081                    || maximum_delegation_amount > global_maximum_delegation_amount
1082                    || minimum_delegation_amount > maximum_delegation_amount
1083                {
1084                    return Err(ExecError::Revert(ApiError::InvalidDelegationAmountLimits));
1085                }
1086                let reserved_slots =
1087                    Self::try_get_named_argument(runtime_args, auction::ARG_RESERVED_SLOTS)?
1088                        .unwrap_or(0);
1089
1090                let max_delegators_per_validator =
1091                    self.context.engine_config().max_delegators_per_validator();
1092
1093                let minimum_bid_amount = self.context().engine_config().minimum_bid_amount();
1094
1095                let result = runtime
1096                    .add_bid(
1097                        public_key,
1098                        delegation_rate,
1099                        amount,
1100                        minimum_delegation_amount,
1101                        maximum_delegation_amount,
1102                        minimum_bid_amount,
1103                        max_delegators_per_validator,
1104                        reserved_slots,
1105                    )
1106                    .map_err(Self::reverter)?;
1107
1108                CLValue::from_t(result).map_err(Self::reverter)
1109            })(),
1110
1111            auction::METHOD_WITHDRAW_BID => (|| {
1112                runtime.charge_system_contract_call(auction_costs.withdraw_bid)?;
1113
1114                let public_key = Self::get_named_argument(runtime_args, auction::ARG_PUBLIC_KEY)?;
1115                let amount = Self::get_named_argument(runtime_args, auction::ARG_AMOUNT)?;
1116                let min_bid_amount = self.context.engine_config().minimum_bid_amount();
1117
1118                let result = runtime
1119                    .withdraw_bid(public_key, amount, min_bid_amount)
1120                    .map_err(Self::reverter)?;
1121                CLValue::from_t(result).map_err(Self::reverter)
1122            })(),
1123
1124            auction::METHOD_DELEGATE => (|| {
1125                runtime.charge_system_contract_call(auction_costs.delegate)?;
1126
1127                let delegator = {
1128                    match Self::get_named_argument(runtime_args, auction::ARG_DELEGATOR) {
1129                        Ok(pk) => DelegatorKind::PublicKey(pk),
1130                        Err(_) => {
1131                            let uref: URef = match Self::get_named_argument(
1132                                runtime_args,
1133                                auction::ARG_DELEGATOR_PURSE,
1134                            ) {
1135                                Ok(uref) => uref,
1136                                Err(err) => {
1137                                    debug!(%err, "failed to get delegator purse argument");
1138                                    return Err(err);
1139                                }
1140                            };
1141                            DelegatorKind::Purse(uref.addr())
1142                        }
1143                    }
1144                };
1145                let validator = Self::get_named_argument(runtime_args, auction::ARG_VALIDATOR)?;
1146                let amount = Self::get_named_argument(runtime_args, auction::ARG_AMOUNT)?;
1147
1148                let max_delegators_per_validator =
1149                    self.context.engine_config().max_delegators_per_validator();
1150
1151                let result = runtime
1152                    .delegate(delegator, validator, amount, max_delegators_per_validator)
1153                    .map_err(Self::reverter)?;
1154
1155                CLValue::from_t(result).map_err(Self::reverter)
1156            })(),
1157
1158            auction::METHOD_UNDELEGATE => (|| {
1159                runtime.charge_system_contract_call(auction_costs.undelegate)?;
1160
1161                let delegator = {
1162                    match Self::get_named_argument(runtime_args, auction::ARG_DELEGATOR) {
1163                        Ok(pk) => DelegatorKind::PublicKey(pk),
1164                        Err(_) => {
1165                            let uref: URef = match Self::get_named_argument(
1166                                runtime_args,
1167                                auction::ARG_DELEGATOR_PURSE,
1168                            ) {
1169                                Ok(uref) => uref,
1170                                Err(err) => {
1171                                    debug!(%err, "failed to get delegator purse argument");
1172                                    return Err(err);
1173                                }
1174                            };
1175                            DelegatorKind::Purse(uref.addr())
1176                        }
1177                    }
1178                };
1179                let validator = Self::get_named_argument(runtime_args, auction::ARG_VALIDATOR)?;
1180                let amount = Self::get_named_argument(runtime_args, auction::ARG_AMOUNT)?;
1181
1182                let result = runtime
1183                    .undelegate(delegator, validator, amount)
1184                    .map_err(Self::reverter)?;
1185
1186                CLValue::from_t(result).map_err(Self::reverter)
1187            })(),
1188
1189            auction::METHOD_REDELEGATE => (|| {
1190                runtime.charge_system_contract_call(auction_costs.redelegate)?;
1191
1192                let delegator = {
1193                    match Self::get_named_argument(runtime_args, auction::ARG_DELEGATOR) {
1194                        Ok(pk) => DelegatorKind::PublicKey(pk),
1195                        Err(_) => {
1196                            let uref: URef = match Self::get_named_argument(
1197                                runtime_args,
1198                                auction::ARG_DELEGATOR_PURSE,
1199                            ) {
1200                                Ok(uref) => uref,
1201                                Err(err) => {
1202                                    debug!(%err, "failed to get delegator purse argument");
1203                                    return Err(err);
1204                                }
1205                            };
1206                            DelegatorKind::Purse(uref.addr())
1207                        }
1208                    }
1209                };
1210                let validator = Self::get_named_argument(runtime_args, auction::ARG_VALIDATOR)?;
1211                let amount = Self::get_named_argument(runtime_args, auction::ARG_AMOUNT)?;
1212                let new_validator =
1213                    Self::get_named_argument(runtime_args, auction::ARG_NEW_VALIDATOR)?;
1214
1215                let result = runtime
1216                    .redelegate(delegator, validator, amount, new_validator)
1217                    .map_err(Self::reverter)?;
1218
1219                CLValue::from_t(result).map_err(Self::reverter)
1220            })(),
1221
1222            auction::METHOD_RUN_AUCTION => (|| {
1223                runtime.charge_system_contract_call(auction_costs.run_auction)?;
1224
1225                let era_end_timestamp_millis =
1226                    Self::get_named_argument(runtime_args, auction::ARG_ERA_END_TIMESTAMP_MILLIS)?;
1227                let evicted_validators =
1228                    Self::get_named_argument(runtime_args, auction::ARG_EVICTED_VALIDATORS)?;
1229
1230                let max_delegators_per_validator =
1231                    self.context.engine_config().max_delegators_per_validator();
1232                let minimum_bid_amount = self.context.engine_config().minimum_bid_amount();
1233                runtime
1234                    .run_auction(
1235                        era_end_timestamp_millis,
1236                        evicted_validators,
1237                        max_delegators_per_validator,
1238                        true,
1239                        Ratio::new_raw(U512::from(1), U512::from(5)),
1240                        minimum_bid_amount,
1241                    )
1242                    .map_err(Self::reverter)?;
1243
1244                CLValue::from_t(()).map_err(Self::reverter)
1245            })(),
1246
1247            // Type: `fn slash(validator_public_keys: &[PublicKey]) -> Result<(), ExecError>`
1248            auction::METHOD_SLASH => (|| {
1249                runtime.charge_system_contract_call(auction_costs.slash)?;
1250
1251                let validator_public_keys =
1252                    Self::get_named_argument(runtime_args, auction::ARG_VALIDATOR_PUBLIC_KEYS)?;
1253                runtime
1254                    .slash(validator_public_keys)
1255                    .map_err(Self::reverter)?;
1256                CLValue::from_t(()).map_err(Self::reverter)
1257            })(),
1258
1259            // Type: `fn distribute(reward_factors: BTreeMap<PublicKey, u512>) -> Result<(),
1260            // ExecError>`
1261            auction::METHOD_DISTRIBUTE => (|| {
1262                runtime.charge_system_contract_call(auction_costs.distribute)?;
1263                let rewards = Self::get_named_argument(runtime_args, auction::ARG_REWARDS_MAP)?;
1264                runtime.distribute(rewards).map_err(Self::reverter)?;
1265                CLValue::from_t(()).map_err(Self::reverter)
1266            })(),
1267
1268            // Type: `fn read_era_id() -> Result<EraId, ExecError>`
1269            auction::METHOD_READ_ERA_ID => (|| {
1270                runtime.charge_system_contract_call(auction_costs.read_era_id)?;
1271
1272                let result = runtime.read_era_id().map_err(Self::reverter)?;
1273                CLValue::from_t(result).map_err(Self::reverter)
1274            })(),
1275
1276            auction::METHOD_ACTIVATE_BID => (|| {
1277                runtime.charge_system_contract_call(auction_costs.activate_bid)?;
1278
1279                let validator = Self::get_named_argument(runtime_args, auction::ARG_VALIDATOR)?;
1280
1281                runtime
1282                    .activate_bid(validator, engine_config.minimum_bid_amount())
1283                    .map_err(Self::reverter)?;
1284
1285                CLValue::from_t(()).map_err(Self::reverter)
1286            })(),
1287            auction::METHOD_CHANGE_BID_PUBLIC_KEY => (|| {
1288                runtime.charge_system_contract_call(auction_costs.change_bid_public_key)?;
1289
1290                let public_key = Self::get_named_argument(runtime_args, auction::ARG_PUBLIC_KEY)?;
1291                let new_public_key =
1292                    Self::get_named_argument(runtime_args, auction::ARG_NEW_PUBLIC_KEY)?;
1293
1294                runtime
1295                    .change_bid_public_key(public_key, new_public_key)
1296                    .map_err(Self::reverter)?;
1297
1298                CLValue::from_t(()).map_err(Self::reverter)
1299            })(),
1300            auction::METHOD_ADD_RESERVATIONS => (|| {
1301                runtime.charge_system_contract_call(auction_costs.add_reservations)?;
1302
1303                let reservations =
1304                    Self::get_named_argument(runtime_args, auction::ARG_RESERVATIONS)?;
1305
1306                runtime
1307                    .add_reservations(reservations)
1308                    .map_err(Self::reverter)?;
1309
1310                CLValue::from_t(()).map_err(Self::reverter)
1311            })(),
1312            auction::METHOD_CANCEL_RESERVATIONS => (|| {
1313                runtime.charge_system_contract_call(auction_costs.cancel_reservations)?;
1314
1315                let validator = Self::get_named_argument(runtime_args, auction::ARG_VALIDATOR)?;
1316                let delegators = Self::get_named_argument(runtime_args, auction::ARG_DELEGATORS)?;
1317                let max_delegators_per_validator =
1318                    self.context.engine_config().max_delegators_per_validator();
1319
1320                runtime
1321                    .cancel_reservations(validator, delegators, max_delegators_per_validator)
1322                    .map_err(Self::reverter)?;
1323
1324                CLValue::from_t(()).map_err(Self::reverter)
1325            })(),
1326            _ => {
1327                // Code should never reach here as existence of the entrypoint is validated before
1328                // reaching this point.
1329                Ok(CLValue::unit())
1330            }
1331        };
1332
1333        // Charge for the gas spent during execution in an isolated runtime.
1334        self.gas(
1335            runtime
1336                .gas_counter()
1337                .checked_sub(gas_counter)
1338                .unwrap_or(gas_counter),
1339        )?;
1340
1341        // Result still contains a result, but the entrypoints logic does not exit early on errors.
1342        let ret = result?;
1343
1344        let urefs = utils::extract_urefs(&ret)?;
1345        self.context.access_rights_extend(&urefs);
1346        {
1347            let transfers = self.context.transfers_mut();
1348            runtime.context.transfers().clone_into(transfers);
1349        }
1350
1351        Ok(ret)
1352    }
1353
1354    /// Call a contract by pushing a stack element onto the frame.
1355    pub(crate) fn call_contract_with_stack(
1356        &mut self,
1357        contract_hash: AddressableEntityHash,
1358        entry_point_name: &str,
1359        args: RuntimeArgs,
1360        stack: RuntimeStack,
1361    ) -> Result<CLValue, ExecError> {
1362        self.stack = Some(stack);
1363
1364        self.call_contract(contract_hash, entry_point_name, args)
1365    }
1366
1367    /// Call a version within a package by pushing a stack element onto the frame.
1368    pub fn call_package_version_with_stack(
1369        &mut self,
1370        contract_package_hash: PackageHash,
1371        protocol_version_major: Option<ProtocolVersionMajor>,
1372        version: Option<EntityVersion>,
1373        entry_point_name: String,
1374        args: RuntimeArgs,
1375        stack: RuntimeStack,
1376    ) -> Result<CLValue, ExecError> {
1377        self.stack = Some(stack);
1378
1379        self.call_package_version(
1380            contract_package_hash,
1381            protocol_version_major,
1382            version,
1383            entry_point_name,
1384            args,
1385        )
1386    }
1387
1388    pub(crate) fn execute_module_bytes(
1389        &mut self,
1390        module_bytes: &Bytes,
1391        stack: RuntimeStack,
1392    ) -> Result<CLValue, ExecError> {
1393        let protocol_version = self.context.protocol_version();
1394        let engine_config = self.context.engine_config();
1395        let wasm_config = engine_config.wasm_config();
1396        #[cfg(feature = "test-support")]
1397        let max_stack_height = wasm_config.v1().max_stack_height();
1398        let module = preprocess(*wasm_config, module_bytes)?;
1399        let (instance, memory) =
1400            utils::instance_and_memory(module.clone(), protocol_version, engine_config)?;
1401        self.memory = Some(memory);
1402        self.module = Some(module);
1403        self.stack = Some(stack);
1404        self.context.set_args(utils::attenuate_uref_in_args(
1405            self.context.args().clone(),
1406            self.context
1407                .runtime_footprint()
1408                .borrow()
1409                .main_purse()
1410                .expect("line 1183")
1411                .addr(),
1412            AccessRights::WRITE,
1413        )?);
1414
1415        let result = instance.invoke_export(DEFAULT_ENTRY_POINT_NAME, &[], self);
1416
1417        let error = match result {
1418            Err(error) => error,
1419            // If `Ok` and the `host_buffer` is `None`, the contract's execution succeeded but did
1420            // not explicitly call `runtime::ret()`.  Treat as though the execution
1421            // returned the unit type `()` as per Rust functions which don't specify a
1422            // return value.
1423            Ok(_) => {
1424                return Ok(self.take_host_buffer().unwrap_or(CLValue::from_t(())?));
1425            }
1426        };
1427
1428        #[cfg(feature = "test-support")]
1429        dump_runtime_stack_info(instance, max_stack_height);
1430
1431        if let Some(host_error) = error.as_host_error() {
1432            // If the "error" was in fact a trap caused by calling `ret` then
1433            // this is normal operation and we should return the value captured
1434            // in the Runtime result field.
1435            let downcasted_error = host_error.downcast_ref::<ExecError>();
1436            return match downcasted_error {
1437                Some(ExecError::Ret(ref _ret_urefs)) => self
1438                    .take_host_buffer()
1439                    .ok_or(ExecError::ExpectedReturnValue),
1440                Some(error) => Err(error.clone()),
1441                None => Err(ExecError::Interpreter(host_error.to_string())),
1442            };
1443        }
1444        Err(ExecError::Interpreter(error.into()))
1445    }
1446
1447    /// Calls contract living under a `key`, with supplied `args`.
1448    pub fn call_contract(
1449        &mut self,
1450        contract_hash: AddressableEntityHash,
1451        entry_point_name: &str,
1452        args: RuntimeArgs,
1453    ) -> Result<CLValue, ExecError> {
1454        let contract_hash = contract_hash.value();
1455        let identifier = CallContractIdentifier::Contract { contract_hash };
1456
1457        self.execute_contract(identifier, entry_point_name, args)
1458    }
1459
1460    /// Calls `version` of the contract living at `key`, invoking `method` with
1461    /// supplied `args`. This function also checks the args conform with the
1462    /// types given in the contract header.
1463    pub fn call_versioned_contract(
1464        &mut self,
1465        contract_package_hash: PackageHash,
1466        contract_version: Option<EntityVersion>,
1467        entry_point_name: String,
1468        args: RuntimeArgs,
1469    ) -> Result<CLValue, ExecError> {
1470        self.call_package_version(
1471            contract_package_hash,
1472            None,
1473            contract_version,
1474            entry_point_name,
1475            args,
1476        )
1477    }
1478
1479    /// Calls `version` of the contract living at `key`, invoking `method` with
1480    /// supplied `args`. This function also checks the args conform with the
1481    /// types given in the contract header.
1482    pub fn call_package_version(
1483        &mut self,
1484        contract_package_hash: PackageHash,
1485        protocol_version_major: Option<ProtocolVersionMajor>,
1486        version: Option<EntityVersion>,
1487        entry_point_name: String,
1488        args: RuntimeArgs,
1489    ) -> Result<CLValue, ExecError> {
1490        /*
1491        m e
1492        - - :   pick the highest enabled version, considering the major protocol version first, then the entity version
1493        - + :   walk down from the highest major protocol version, so highest..2.+ then 1.+
1494                   If there is only one, its that one (no guessing)
1495                   If there are more than one, but the entity version is in the range of only one major version
1496                   If there is a collision,
1497                      It would be safer to error on this collision, however
1498                      we are making a best attempt and picking the highest protocol version
1499                      add a chainspec setting to either error or pick the highest in this ambigious case
1500                      pick the highest protocol version
1501        + - :   pick the highest enabled entity version for the given major
1502        + + :   pick the version key based on +.+
1503        */
1504
1505        let contract_package_hash = contract_package_hash.value();
1506        let identifier = CallContractIdentifier::ContractPackage {
1507            contract_package_hash,
1508            version,
1509            protocol_version_major,
1510        };
1511
1512        self.execute_contract(identifier, &entry_point_name, args)
1513    }
1514
1515    fn get_protocol_version_for_entity_version(
1516        &self,
1517        entity_version: EntityVersion,
1518        package: &Package,
1519    ) -> Result<EntityVersionKey, ExecError> {
1520        let enabled_versions = package.enabled_versions();
1521        let current_protocol_version_major = self.context.protocol_version().value().major;
1522
1523        let mut possible_versions = vec![];
1524
1525        for protocol_version_major in (1..=current_protocol_version_major).rev() {
1526            let entity_version_key = EntityVersionKey::new(protocol_version_major, entity_version);
1527            // If there is a corresponding addr then its an enabled valid entity version key
1528            if enabled_versions.get(&entity_version_key).is_some() {
1529                possible_versions.push(entity_version_key)
1530            }
1531        }
1532
1533        if possible_versions.is_empty() {
1534            return Err(ExecError::NoMatchingEntityVersionKey);
1535        }
1536
1537        if possible_versions.len() > 1
1538            && self
1539                .context
1540                .engine_config()
1541                .trap_on_ambiguous_entity_version
1542        {
1543            return Err(ExecError::AmbiguousEntityVersion);
1544        }
1545
1546        // If possible versions has more than one, then the element to be popped
1547        // will be the version key which has the same entity version, but the highest protocol
1548        // version If there is only one version key matching the entity version then we will
1549        // correctly pop the singular element in the possible versions.
1550        // This sort is load bearing.
1551        possible_versions.sort();
1552        // This unwrap is safe as long as we exit early on possible versions being empty
1553        let entity_version_key = possible_versions.pop().unwrap();
1554        Ok(entity_version_key)
1555    }
1556
1557    fn get_key_from_entity_addr(&self, entity_addr: EntityAddr) -> Key {
1558        if self.context().engine_config().enable_entity {
1559            Key::AddressableEntity(entity_addr)
1560        } else {
1561            match entity_addr {
1562                EntityAddr::System(system_hash_addr) => Key::Hash(system_hash_addr),
1563                EntityAddr::Account(hash_addr) => Key::Account(AccountHash::new(hash_addr)),
1564                EntityAddr::SmartContract(contract_hash_addr) => Key::Hash(contract_hash_addr),
1565            }
1566        }
1567    }
1568
1569    fn get_context_key_for_contract_call(
1570        &self,
1571        entity_addr: EntityAddr,
1572        entry_point: &EntityEntryPoint,
1573    ) -> Result<Key, ExecError> {
1574        let current = self.context.entry_point_type();
1575        let next = entry_point.entry_point_type();
1576        match (current, next) {
1577            (EntryPointType::Called, EntryPointType::Caller) => {
1578                // Session code can't be called from Contract code for security reasons.
1579                Err(ExecError::InvalidContext)
1580            }
1581            (EntryPointType::Factory, EntryPointType::Caller) => {
1582                // Session code can't be called from Installer code for security reasons.
1583                Err(ExecError::InvalidContext)
1584            }
1585            (EntryPointType::Caller, EntryPointType::Caller) => {
1586                // Session code called from session reuses current base key
1587                Ok(self.context.get_context_key())
1588            }
1589            (EntryPointType::Caller, EntryPointType::Called)
1590            | (EntryPointType::Called, EntryPointType::Called) => {
1591                Ok(self.get_key_from_entity_addr(entity_addr))
1592            }
1593            _ => {
1594                // Any other combination (installer, normal, etc.) is a contract context.
1595                Ok(self.get_key_from_entity_addr(entity_addr))
1596            }
1597        }
1598    }
1599
1600    fn try_get_memory(&self) -> Result<&MemoryRef, ExecError> {
1601        self.memory.as_ref().ok_or(ExecError::WasmPreprocessing(
1602            PreprocessingError::MissingMemorySection,
1603        ))
1604    }
1605
1606    fn try_get_module(&self) -> Result<&Module, ExecError> {
1607        self.module.as_ref().ok_or(ExecError::WasmPreprocessing(
1608            PreprocessingError::MissingModule,
1609        ))
1610    }
1611
1612    fn try_get_stack(&self) -> Result<&RuntimeStack, ExecError> {
1613        self.stack.as_ref().ok_or(ExecError::MissingRuntimeStack)
1614    }
1615
1616    fn maybe_system_type(&self, hash_addr: HashAddr) -> Option<SystemEntityType> {
1617        let is_mint = self.is_mint(hash_addr);
1618        if is_mint.is_some() {
1619            return is_mint;
1620        };
1621
1622        let is_auction = self.is_auction(hash_addr);
1623        if is_auction.is_some() {
1624            return is_auction;
1625        };
1626        let is_handle = self.is_handle_payment(hash_addr);
1627        if is_handle.is_some() {
1628            return is_handle;
1629        };
1630
1631        None
1632    }
1633
1634    fn is_mint(&self, hash_addr: HashAddr) -> Option<SystemEntityType> {
1635        let hash = match self.context.get_system_contract(MINT) {
1636            Ok(hash) => hash,
1637            Err(_) => {
1638                error!("Failed to get system mint contract hash");
1639                return None;
1640            }
1641        };
1642        if hash.value() == hash_addr {
1643            Some(SystemEntityType::Mint)
1644        } else {
1645            None
1646        }
1647    }
1648
1649    /// Checks if current context is the `handle_payment` system contract.
1650    fn is_handle_payment(&self, hash_addr: HashAddr) -> Option<SystemEntityType> {
1651        let hash = match self.context.get_system_contract(HANDLE_PAYMENT) {
1652            Ok(hash) => hash,
1653            Err(_) => {
1654                error!("Failed to get system handle payment contract hash");
1655                return None;
1656            }
1657        };
1658        if hash.value() == hash_addr {
1659            Some(SystemEntityType::HandlePayment)
1660        } else {
1661            None
1662        }
1663    }
1664
1665    /// Checks if given hash is the auction system contract.
1666    fn is_auction(&self, hash_addr: HashAddr) -> Option<SystemEntityType> {
1667        let hash = match self.context.get_system_contract(AUCTION) {
1668            Ok(hash) => hash,
1669            Err(_) => {
1670                error!("Failed to get system auction contract hash");
1671                return None;
1672            }
1673        };
1674
1675        if hash.value() == hash_addr {
1676            Some(SystemEntityType::Auction)
1677        } else {
1678            None
1679        }
1680    }
1681
1682    fn execute_contract(
1683        &mut self,
1684        identifier: CallContractIdentifier,
1685        entry_point_name: &str,
1686        args: RuntimeArgs,
1687    ) -> Result<CLValue, ExecError> {
1688        let (footprint, entity_addr, package) = match identifier {
1689            CallContractIdentifier::Contract { contract_hash } => {
1690                let entity_addr = if self.context.is_system_addressable_entity(&contract_hash)? {
1691                    EntityAddr::new_system(contract_hash)
1692                } else {
1693                    EntityAddr::new_smart_contract(contract_hash)
1694                };
1695                let footprint = match self.context.read_gs(&Key::Hash(contract_hash))? {
1696                    Some(StoredValue::Contract(contract)) => {
1697                        if self.context.engine_config().enable_entity {
1698                            self.migrate_contract_and_contract_package(contract_hash)?;
1699                        };
1700
1701                        let maybe_system_entity_type = self.maybe_system_type(contract_hash);
1702
1703                        RuntimeFootprint::new_contract_footprint(
1704                            ContractHash::new(contract_hash),
1705                            contract,
1706                            maybe_system_entity_type,
1707                        )
1708                    }
1709                    Some(_) | None => {
1710                        if !self.context.engine_config().enable_entity {
1711                            return Err(ExecError::KeyNotFound(Key::Hash(contract_hash)));
1712                        }
1713                        let key = Key::AddressableEntity(entity_addr);
1714                        let entity = self.context.read_gs_typed::<AddressableEntity>(&key)?;
1715                        let entity_named_keys = self
1716                            .context
1717                            .state()
1718                            .borrow_mut()
1719                            .get_named_keys(entity_addr)?;
1720                        let entry_points = self.context.get_casper_vm_v1_entry_point(key)?;
1721                        RuntimeFootprint::new_entity_footprint(
1722                            entity_addr,
1723                            entity,
1724                            entity_named_keys,
1725                            entry_points,
1726                        )
1727                    }
1728                };
1729
1730                let package_hash = footprint.package_hash().ok_or(ExecError::InvalidContext)?;
1731                let package: Package = self.context.get_package(package_hash)?;
1732
1733                // System contract hashes are disabled at upgrade point
1734                let is_calling_system_contract = self.is_system_contract(contract_hash)?;
1735
1736                let entity_hash = AddressableEntityHash::new(contract_hash);
1737
1738                // Check if provided contract hash is disabled
1739                let is_contract_enabled = package.is_entity_enabled(&entity_addr);
1740
1741                if !is_calling_system_contract && !is_contract_enabled {
1742                    return Err(ExecError::DisabledEntity(entity_hash));
1743                }
1744
1745                (footprint, entity_addr, package)
1746            }
1747            CallContractIdentifier::ContractPackage {
1748                contract_package_hash,
1749                version,
1750                protocol_version_major,
1751            } => {
1752                let package = self.context.get_package(contract_package_hash)?;
1753                let entity_version_key = match (version, protocol_version_major) {
1754                    (Some(entity_version), Some(major)) => {
1755                        EntityVersionKey::new(major, entity_version)
1756                    }
1757                    (None, Some(major)) => package.current_entity_version_for(major),
1758                    (Some(entity_version), None) => {
1759                        match self.get_protocol_version_for_entity_version(entity_version, &package)
1760                        {
1761                            Ok(entity_version_key) => entity_version_key,
1762                            Err(err) => {
1763                                return Err(err);
1764                            }
1765                        }
1766                    }
1767                    (None, None) => match package.current_entity_version() {
1768                        Some(v) => v,
1769                        None => {
1770                            return Err(ExecError::NoActiveEntityVersions(
1771                                contract_package_hash.into(),
1772                            ));
1773                        }
1774                    },
1775                };
1776
1777                if package.is_version_missing(entity_version_key) {
1778                    return Err(ExecError::MissingEntityVersion(entity_version_key));
1779                }
1780
1781                if !package.is_version_enabled(entity_version_key) {
1782                    return Err(ExecError::DisabledEntityVersion(entity_version_key));
1783                }
1784
1785                let hash_addr = package
1786                    .lookup_entity_hash(entity_version_key)
1787                    .copied()
1788                    .ok_or(ExecError::MissingEntityVersion(entity_version_key))?
1789                    .value();
1790
1791                let entity_addr = if self.context.is_system_addressable_entity(&hash_addr)? {
1792                    EntityAddr::new_system(hash_addr)
1793                } else {
1794                    EntityAddr::new_smart_contract(hash_addr)
1795                };
1796
1797                let footprint = match self.context.read_gs(&Key::Hash(hash_addr))? {
1798                    Some(StoredValue::Contract(contract)) => {
1799                        if self.context.engine_config().enable_entity {
1800                            self.migrate_contract_and_contract_package(hash_addr)?;
1801                        };
1802                        let maybe_system_entity_type = self.maybe_system_type(hash_addr);
1803                        RuntimeFootprint::new_contract_footprint(
1804                            ContractHash::new(hash_addr),
1805                            contract,
1806                            maybe_system_entity_type,
1807                        )
1808                    }
1809                    Some(_) | None => {
1810                        if !self.context.engine_config().enable_entity {
1811                            return Err(ExecError::KeyNotFound(Key::Hash(hash_addr)));
1812                        }
1813                        let key = Key::AddressableEntity(entity_addr);
1814                        let entity = self.context.read_gs_typed::<AddressableEntity>(&key)?;
1815                        let entity_named_keys = self
1816                            .context
1817                            .state()
1818                            .borrow_mut()
1819                            .get_named_keys(entity_addr)?;
1820                        let entry_points = self.context.get_casper_vm_v1_entry_point(key)?;
1821                        RuntimeFootprint::new_entity_footprint(
1822                            entity_addr,
1823                            entity,
1824                            entity_named_keys,
1825                            entry_points,
1826                        )
1827                    }
1828                };
1829
1830                (footprint, entity_addr, package)
1831            }
1832        };
1833
1834        if let EntityKind::Account(_) = footprint.entity_kind() {
1835            return Err(ExecError::InvalidContext);
1836        }
1837
1838        let entry_point = match footprint.entry_points().get(entry_point_name) {
1839            Some(entry_point) => entry_point,
1840            None => {
1841                match footprint.entity_kind() {
1842                    EntityKind::System(_) => {
1843                        self.charge_system_contract_call(
1844                            self.context()
1845                                .engine_config()
1846                                .system_config()
1847                                .no_such_entrypoint(),
1848                        )?;
1849                    }
1850                    EntityKind::Account(_) => {}
1851                    EntityKind::SmartContract(_) => {}
1852                }
1853                return Err(ExecError::NoSuchMethod(entry_point_name.to_owned()));
1854            }
1855        };
1856
1857        let entry_point_type = entry_point.entry_point_type();
1858
1859        if self.context.engine_config().enable_entity && entry_point_type.is_invalid_context() {
1860            return Err(ExecError::InvalidContext);
1861        }
1862
1863        // Get contract entry point hash
1864        // if public, allowed
1865        // if group, restricted to user group access
1866        // if template, not allowed
1867        self.validate_entry_point_access(&package, entry_point_name, entry_point.access())?;
1868        if self.context.engine_config().strict_argument_checking() {
1869            let entry_point_args_lookup: BTreeMap<&str, &Parameter> = entry_point
1870                .args()
1871                .iter()
1872                .map(|param| (param.name(), param))
1873                .collect();
1874
1875            let args_lookup: BTreeMap<&str, &NamedArg> = args
1876                .named_args()
1877                .map(|named_arg| (named_arg.name(), named_arg))
1878                .collect();
1879
1880            // variable ensure args type(s) match defined args of entry point
1881            for (param_name, param) in entry_point_args_lookup {
1882                if let Some(named_arg) = args_lookup.get(param_name) {
1883                    if param.cl_type() != named_arg.cl_value().cl_type() {
1884                        return Err(ExecError::type_mismatch(
1885                            param.cl_type().clone(),
1886                            named_arg.cl_value().cl_type().clone(),
1887                        ));
1888                    }
1889                } else if !param.cl_type().is_option() {
1890                    return Err(ExecError::MissingArgument {
1891                        name: param.name().to_string(),
1892                    });
1893                }
1894            }
1895        }
1896
1897        let entity_hash = AddressableEntityHash::new(entity_addr.value());
1898
1899        if !self
1900            .context
1901            .engine_config()
1902            .administrative_accounts()
1903            .is_empty()
1904            && !package.is_entity_enabled(&entity_addr)
1905            && !self
1906                .context
1907                .is_system_addressable_entity(&entity_addr.value())?
1908        {
1909            return Err(ExecError::DisabledEntity(entity_hash));
1910        }
1911
1912        // if session the caller's context
1913        // else the called contract's context
1914        let context_entity_key =
1915            self.get_context_key_for_contract_call(entity_addr, entry_point)?;
1916
1917        let context_entity_hash = context_entity_key
1918            .into_entity_hash_addr()
1919            .ok_or(ExecError::UnexpectedKeyVariant(context_entity_key))?;
1920
1921        let (should_attenuate_urefs, should_validate_urefs) = {
1922            // Determines if this call originated from the system account based on a first
1923            // element of the call stack.
1924            let is_system_account =
1925                self.context.get_initiator() == PublicKey::System.to_account_hash();
1926            // Is the immediate caller a system contract, such as when the auction calls the mint.
1927            let is_caller_system_contract =
1928                self.is_system_contract(self.context.access_rights().context_key())?;
1929            // Checks if the contract we're about to call is a system contract.
1930            let is_calling_system_contract = self.is_system_contract(context_entity_hash)?;
1931            // uref attenuation is necessary in the following circumstances:
1932            //   the originating account (aka the caller) is not the system account and
1933            //   the immediate caller is either a normal account or a normal contract and
1934            //   the target contract about to be called is a normal contract
1935            let should_attenuate_urefs =
1936                !is_system_account && !is_caller_system_contract && !is_calling_system_contract;
1937            let should_validate_urefs = !is_caller_system_contract || !is_calling_system_contract;
1938            (should_attenuate_urefs, should_validate_urefs)
1939        };
1940        let runtime_args = if should_attenuate_urefs {
1941            // Main purse URefs should be attenuated only when a non-system contract is executed by
1942            // a non-system account to avoid possible phishing attack scenarios.
1943            utils::attenuate_uref_in_args(
1944                args,
1945                self.context
1946                    .runtime_footprint()
1947                    .borrow()
1948                    .main_purse()
1949                    .expect("need purse for attenuation")
1950                    .addr(),
1951                AccessRights::WRITE,
1952            )?
1953        } else {
1954            args
1955        };
1956
1957        let extended_access_rights = {
1958            let mut all_urefs = vec![];
1959            for arg in runtime_args.to_values() {
1960                let urefs = utils::extract_urefs(arg)?;
1961                if should_validate_urefs {
1962                    for uref in &urefs {
1963                        self.context.validate_uref(uref)?;
1964                    }
1965                }
1966                all_urefs.extend(urefs);
1967            }
1968            all_urefs
1969        };
1970
1971        let (mut named_keys, access_rights) = match entry_point_type {
1972            EntryPointType::Caller => {
1973                let mut access_rights = self
1974                    .context
1975                    .runtime_footprint()
1976                    .borrow()
1977                    .extract_access_rights(context_entity_hash);
1978                access_rights.extend(&extended_access_rights);
1979
1980                let named_keys = self
1981                    .context
1982                    .runtime_footprint()
1983                    .borrow()
1984                    .named_keys()
1985                    .clone();
1986
1987                (named_keys, access_rights)
1988            }
1989            EntryPointType::Called | EntryPointType::Factory => {
1990                let mut access_rights = footprint.extract_access_rights(entity_hash.value());
1991                access_rights.extend(&extended_access_rights);
1992                let named_keys = footprint.named_keys().clone();
1993                (named_keys, access_rights)
1994            }
1995        };
1996
1997        let stack = {
1998            let mut stack = self.try_get_stack()?.clone();
1999
2000            let package_hash = match footprint.package_hash() {
2001                Some(hash) => PackageHash::new(hash),
2002                None => {
2003                    return Err(ExecError::UnexpectedStoredValueVariant);
2004                }
2005            };
2006
2007            let caller = if self.context.engine_config().enable_entity {
2008                Caller::entity(package_hash, entity_addr)
2009            } else {
2010                Caller::smart_contract(
2011                    ContractPackageHash::new(package_hash.value()),
2012                    ContractHash::new(entity_addr.value()),
2013                )
2014            };
2015
2016            stack.push(caller)?;
2017
2018            stack
2019        };
2020
2021        if let EntityKind::System(system_contract_type) = footprint.entity_kind() {
2022            let entry_point_name = entry_point.name();
2023
2024            match system_contract_type {
2025                SystemEntityType::Mint => {
2026                    return self.call_host_mint(
2027                        entry_point_name,
2028                        &runtime_args,
2029                        access_rights,
2030                        stack,
2031                    );
2032                }
2033                SystemEntityType::HandlePayment => {
2034                    return self.call_host_handle_payment(
2035                        entry_point_name,
2036                        &runtime_args,
2037                        access_rights,
2038                        stack,
2039                    );
2040                }
2041                SystemEntityType::Auction => {
2042                    return self.call_host_auction(
2043                        entry_point_name,
2044                        &runtime_args,
2045                        access_rights,
2046                        stack,
2047                    );
2048                }
2049                // Not callable
2050                SystemEntityType::StandardPayment => {}
2051            }
2052        }
2053
2054        let module: Module = {
2055            let byte_code_addr = footprint.wasm_hash().ok_or(ExecError::InvalidContext)?;
2056
2057            let byte_code_key = match footprint.entity_kind() {
2058                EntityKind::System(_) | EntityKind::Account(_) => {
2059                    Key::ByteCode(ByteCodeAddr::Empty)
2060                }
2061                EntityKind::SmartContract(ContractRuntimeTag::VmCasperV1) => {
2062                    if self.context.engine_config().enable_entity {
2063                        Key::ByteCode(ByteCodeAddr::new_wasm_addr(byte_code_addr))
2064                    } else {
2065                        Key::Hash(byte_code_addr)
2066                    }
2067                }
2068                EntityKind::SmartContract(runtime @ ContractRuntimeTag::VmCasperV2) => {
2069                    return Err(ExecError::IncompatibleRuntime(runtime));
2070                }
2071            };
2072
2073            let byte_code: ByteCode = match self.context.read_gs(&byte_code_key)? {
2074                Some(StoredValue::ContractWasm(wasm)) => {
2075                    ByteCode::new(ByteCodeKind::V1CasperWasm, wasm.take_bytes())
2076                }
2077                Some(StoredValue::ByteCode(byte_code)) => byte_code,
2078                Some(_) => {
2079                    return Err(ExecError::InvalidByteCode(ByteCodeHash::new(
2080                        byte_code_addr,
2081                    )))
2082                }
2083                None => return Err(ExecError::KeyNotFound(byte_code_key)),
2084            };
2085
2086            casper_wasm::deserialize_buffer(byte_code.bytes())?
2087        };
2088
2089        let context = self.context.new_from_self(
2090            context_entity_key,
2091            entry_point.entry_point_type(),
2092            &mut named_keys,
2093            access_rights,
2094            runtime_args,
2095        );
2096
2097        let (instance, memory) = utils::instance_and_memory(
2098            module.clone(),
2099            self.context.protocol_version(),
2100            self.context.engine_config(),
2101        )?;
2102        let runtime = &mut Runtime::new_invocation_runtime(self, context, module, memory, stack);
2103        let result = instance.invoke_export(entry_point.name(), &[], runtime);
2104        // The `runtime`'s context was initialized with our counter from before the call and any gas
2105        // charged by the sub-call was added to its counter - so let's copy the correct value of the
2106        // counter from there to our counter. Do the same for the message cost tracking.
2107        self.context.set_gas_counter(runtime.context.gas_counter());
2108        self.context
2109            .set_emit_message_cost(runtime.context.emit_message_cost());
2110        let transfers = self.context.transfers_mut();
2111        runtime.context.transfers().clone_into(transfers);
2112
2113        match result {
2114            Ok(_) => {
2115                // If `Ok` and the `host_buffer` is `None`, the contract's execution succeeded but
2116                // did not explicitly call `runtime::ret()`.  Treat as though the
2117                // execution returned the unit type `()` as per Rust functions which
2118                // don't specify a return value.
2119                if self.context.entry_point_type() == EntryPointType::Caller
2120                    && runtime.context.entry_point_type() == EntryPointType::Caller
2121                {
2122                    // Overwrites parent's named keys with child's new named key but only when
2123                    // running session code.
2124                    *self.context.named_keys_mut() = runtime.context.named_keys().clone();
2125                }
2126                self.context
2127                    .set_remaining_spending_limit(runtime.context.remaining_spending_limit());
2128                Ok(runtime.take_host_buffer().unwrap_or(CLValue::from_t(())?))
2129            }
2130            Err(error) => {
2131                #[cfg(feature = "test-support")]
2132                dump_runtime_stack_info(
2133                    instance,
2134                    self.context
2135                        .engine_config()
2136                        .wasm_config()
2137                        .v1()
2138                        .max_stack_height(),
2139                );
2140                if let Some(host_error) = error.as_host_error() {
2141                    // If the "error" was in fact a trap caused by calling `ret` then this is normal
2142                    // operation and we should return the value captured in the Runtime result
2143                    // field.
2144                    let downcasted_error = host_error.downcast_ref::<ExecError>();
2145                    return match downcasted_error {
2146                        Some(ExecError::Ret(ref ret_urefs)) => {
2147                            // Insert extra urefs returned from call.
2148                            // Those returned URef's are guaranteed to be valid as they were already
2149                            // validated in the `ret` call inside context we ret from.
2150                            self.context.access_rights_extend(ret_urefs);
2151                            if self.context.entry_point_type() == EntryPointType::Caller
2152                                && runtime.context.entry_point_type() == EntryPointType::Caller
2153                            {
2154                                // Overwrites parent's named keys with child's new named key but
2155                                // only when running session code.
2156                                *self.context.named_keys_mut() =
2157                                    runtime.context.named_keys().clone();
2158                            }
2159                            // Stored contracts are expected to always call a `ret` function,
2160                            // otherwise it's an error.
2161                            runtime
2162                                .take_host_buffer()
2163                                .ok_or(ExecError::ExpectedReturnValue)
2164                        }
2165                        Some(error) => Err(error.clone()),
2166                        None => Err(ExecError::Interpreter(host_error.to_string())),
2167                    };
2168                }
2169                Err(ExecError::Interpreter(error.into()))
2170            }
2171        }
2172    }
2173
2174    fn call_contract_host_buffer(
2175        &mut self,
2176        contract_hash: AddressableEntityHash,
2177        entry_point_name: &str,
2178        args_bytes: &[u8],
2179        result_size_ptr: u32,
2180    ) -> Result<Result<(), ApiError>, ExecError> {
2181        // Exit early if the host buffer is already occupied
2182        if let Err(err) = self.check_host_buffer() {
2183            return Ok(Err(err));
2184        }
2185        let args: RuntimeArgs = bytesrepr::deserialize_from_slice(args_bytes)?;
2186
2187        if let Some(payment_purse) = self.context.maybe_payment_purse() {
2188            for named_arg in args.named_args() {
2189                if utils::extract_urefs(named_arg.cl_value())?
2190                    .into_iter()
2191                    .any(|uref| uref.remove_access_rights() == payment_purse.remove_access_rights())
2192                {
2193                    warn!("attempt to call_contract with payment purse");
2194
2195                    return Err(Into::into(ExecError::Revert(ApiError::HandlePayment(
2196                        handle_payment::Error::AttemptToPersistPaymentPurse as u8,
2197                    ))));
2198                }
2199            }
2200        }
2201
2202        let result = self.call_contract(contract_hash, entry_point_name, args)?;
2203        self.manage_call_contract_host_buffer(result_size_ptr, result)
2204    }
2205
2206    fn call_versioned_contract_host_buffer(
2207        &mut self,
2208        contract_package_hash: PackageHash,
2209        contract_version: Option<EntityVersion>,
2210        entry_point_name: String,
2211        args_bytes: &[u8],
2212        result_size_ptr: u32,
2213    ) -> Result<Result<(), ApiError>, ExecError> {
2214        // Exit early if the host buffer is already occupied
2215        if let Err(err) = self.check_host_buffer() {
2216            return Ok(Err(err));
2217        }
2218        let args: RuntimeArgs = bytesrepr::deserialize_from_slice(args_bytes)?;
2219
2220        if let Some(payment_purse) = self.context.maybe_payment_purse() {
2221            for named_arg in args.named_args() {
2222                if utils::extract_urefs(named_arg.cl_value())?
2223                    .into_iter()
2224                    .any(|uref| uref.remove_access_rights() == payment_purse.remove_access_rights())
2225                {
2226                    warn!("attempt to call_versioned_contract with payment purse");
2227
2228                    return Err(Into::into(ExecError::Revert(ApiError::HandlePayment(
2229                        handle_payment::Error::AttemptToPersistPaymentPurse as u8,
2230                    ))));
2231                }
2232            }
2233        }
2234
2235        let result = self.call_versioned_contract(
2236            contract_package_hash,
2237            contract_version,
2238            entry_point_name,
2239            args,
2240        )?;
2241        self.manage_call_contract_host_buffer(result_size_ptr, result)
2242    }
2243
2244    fn call_package_version_host_buffer(
2245        &mut self,
2246        contract_package_hash: PackageHash,
2247        protocol_version_major: Option<ProtocolVersionMajor>,
2248        contract_version: Option<EntityVersion>,
2249        entry_point_name: String,
2250        args_bytes: &[u8],
2251        result_size_ptr: u32,
2252    ) -> Result<Result<(), ApiError>, ExecError> {
2253        // Exit early if the host buffer is already occupied
2254        if let Err(err) = self.check_host_buffer() {
2255            return Ok(Err(err));
2256        }
2257        let args: RuntimeArgs = bytesrepr::deserialize_from_slice(args_bytes)?;
2258
2259        if let Some(payment_purse) = self.context.maybe_payment_purse() {
2260            for named_arg in args.named_args() {
2261                if utils::extract_urefs(named_arg.cl_value())?
2262                    .into_iter()
2263                    .any(|uref| uref.remove_access_rights() == payment_purse.remove_access_rights())
2264                {
2265                    warn!("attempt to call_versioned_contract with payment purse");
2266
2267                    return Err(Into::into(ExecError::Revert(ApiError::HandlePayment(
2268                        handle_payment::Error::AttemptToPersistPaymentPurse as u8,
2269                    ))));
2270                }
2271            }
2272        }
2273
2274        let result = self.call_package_version(
2275            contract_package_hash,
2276            protocol_version_major,
2277            contract_version,
2278            entry_point_name,
2279            args,
2280        )?;
2281        self.manage_call_contract_host_buffer(result_size_ptr, result)
2282    }
2283
2284    fn check_host_buffer(&mut self) -> Result<(), ApiError> {
2285        if !self.can_write_to_host_buffer() {
2286            Err(ApiError::HostBufferFull)
2287        } else {
2288            Ok(())
2289        }
2290    }
2291
2292    fn manage_call_contract_host_buffer(
2293        &mut self,
2294        result_size_ptr: u32,
2295        result: CLValue,
2296    ) -> Result<Result<(), ApiError>, ExecError> {
2297        let result_size: u32 = match result.inner_bytes().len().try_into() {
2298            Ok(value) => value,
2299            Err(_) => return Ok(Err(ApiError::OutOfMemory)),
2300        };
2301
2302        // leave the host buffer set to `None` if there's nothing to write there
2303        if result_size != 0 {
2304            if let Err(error) = self.write_host_buffer(result) {
2305                return Ok(Err(error));
2306            }
2307        }
2308
2309        let result_size_bytes = result_size.to_le_bytes(); // Wasm is little-endian
2310        if let Err(error) = self
2311            .try_get_memory()?
2312            .set(result_size_ptr, &result_size_bytes)
2313        {
2314            return Err(ExecError::Interpreter(error.into()));
2315        }
2316
2317        Ok(Ok(()))
2318    }
2319
2320    fn load_named_keys(
2321        &mut self,
2322        total_keys_ptr: u32,
2323        result_size_ptr: u32,
2324    ) -> Result<Result<(), ApiError>, Trap> {
2325        if !self.can_write_to_host_buffer() {
2326            // Exit early if the host buffer is already occupied
2327            return Ok(Err(ApiError::HostBufferFull));
2328        }
2329
2330        let total_keys: u32 = match self.context.named_keys().len().try_into() {
2331            Ok(value) => value,
2332            Err(_) => return Ok(Err(ApiError::OutOfMemory)),
2333        };
2334
2335        let total_keys_bytes = total_keys.to_le_bytes();
2336        if let Err(error) = self
2337            .try_get_memory()?
2338            .set(total_keys_ptr, &total_keys_bytes)
2339        {
2340            return Err(ExecError::Interpreter(error.into()).into());
2341        }
2342
2343        if total_keys == 0 {
2344            // No need to do anything else, we leave host buffer empty.
2345            return Ok(Ok(()));
2346        }
2347
2348        let named_keys =
2349            CLValue::from_t(self.context.named_keys().clone()).map_err(ExecError::CLValue)?;
2350
2351        let length: u32 = match named_keys.inner_bytes().len().try_into() {
2352            Ok(value) => value,
2353            Err(_) => return Ok(Err(ApiError::BufferTooSmall)),
2354        };
2355
2356        if let Err(error) = self.write_host_buffer(named_keys) {
2357            return Ok(Err(error));
2358        }
2359
2360        let length_bytes = length.to_le_bytes();
2361        if let Err(error) = self.try_get_memory()?.set(result_size_ptr, &length_bytes) {
2362            return Err(ExecError::Interpreter(error.into()).into());
2363        }
2364
2365        Ok(Ok(()))
2366    }
2367
2368    fn create_contract_package(
2369        &mut self,
2370        is_locked: PackageStatus,
2371    ) -> Result<(ContractPackage, URef), ExecError> {
2372        let access_key = self.context.new_unit_uref()?;
2373        let package_status = match is_locked {
2374            PackageStatus::Locked => ContractPackageStatus::Locked,
2375            PackageStatus::Unlocked => ContractPackageStatus::Unlocked,
2376        };
2377
2378        let contract_package = ContractPackage::new(
2379            access_key,
2380            ContractVersions::default(),
2381            DisabledVersions::default(),
2382            Groups::default(),
2383            package_status,
2384        );
2385
2386        Ok((contract_package, access_key))
2387    }
2388
2389    fn create_package(&mut self, is_locked: PackageStatus) -> Result<(Package, URef), ExecError> {
2390        let access_key = self.context.new_unit_uref()?;
2391        let contract_package = Package::new(
2392            EntityVersions::new(),
2393            BTreeSet::new(),
2394            Groups::new(),
2395            is_locked,
2396        );
2397
2398        Ok((contract_package, access_key))
2399    }
2400
2401    fn create_contract_package_at_hash(
2402        &mut self,
2403        lock_status: PackageStatus,
2404    ) -> Result<([u8; 32], [u8; 32]), ExecError> {
2405        let addr = self.context.new_hash_address()?;
2406        let access_key = if self.context.engine_config().enable_entity {
2407            let (package, access_key) = self.create_package(lock_status)?;
2408            self.context
2409                .metered_write_gs_unsafe(Key::SmartContract(addr), package)?;
2410            access_key
2411        } else {
2412            let (package, access_key) = self.create_contract_package(lock_status)?;
2413            self.context
2414                .metered_write_gs_unsafe(Key::Hash(addr), package)?;
2415            access_key
2416        };
2417        Ok((addr, access_key.addr()))
2418    }
2419
2420    fn create_contract_user_group_by_contract_package(
2421        &mut self,
2422        contract_package_hash: PackageHash,
2423        label: String,
2424        num_new_urefs: u32,
2425        mut existing_urefs: BTreeSet<URef>,
2426        output_size_ptr: u32,
2427    ) -> Result<Result<(), ApiError>, ExecError> {
2428        let mut contract_package: ContractPackage = self
2429            .context
2430            .get_validated_contract_package(contract_package_hash.value())?;
2431
2432        let groups = contract_package.groups_mut();
2433        let new_group = Group::new(label);
2434
2435        // Ensure group does not already exist
2436        if groups.contains(&new_group) {
2437            return Ok(Err(addressable_entity::Error::GroupAlreadyExists.into()));
2438        }
2439
2440        // Ensure there are not too many groups
2441        if groups.len() >= (addressable_entity::MAX_GROUPS as usize) {
2442            return Ok(Err(addressable_entity::Error::MaxGroupsExceeded.into()));
2443        }
2444
2445        // Ensure there are not too many urefs
2446        let total_urefs: usize =
2447            groups.total_urefs() + (num_new_urefs as usize) + existing_urefs.len();
2448        if total_urefs > addressable_entity::MAX_TOTAL_UREFS {
2449            let err = addressable_entity::Error::MaxTotalURefsExceeded;
2450            return Ok(Err(ApiError::ContractHeader(err as u8)));
2451        }
2452
2453        // Proceed with creating user group
2454        let mut new_urefs = Vec::with_capacity(num_new_urefs as usize);
2455        for _ in 0..num_new_urefs {
2456            let u = self.context.new_unit_uref()?;
2457            new_urefs.push(u);
2458        }
2459
2460        for u in new_urefs.iter().cloned() {
2461            existing_urefs.insert(u);
2462        }
2463        groups.insert(new_group, existing_urefs);
2464
2465        // check we can write to the host buffer
2466        if let Err(err) = self.check_host_buffer() {
2467            return Ok(Err(err));
2468        }
2469        // create CLValue for return value
2470        let new_urefs_value = CLValue::from_t(new_urefs)?;
2471        let value_size = new_urefs_value.inner_bytes().len();
2472        // write return value to buffer
2473        if let Err(err) = self.write_host_buffer(new_urefs_value) {
2474            return Ok(Err(err));
2475        }
2476        // Write return value size to output location
2477        let output_size_bytes = value_size.to_le_bytes(); // Wasm is little-endian
2478        if let Err(error) = self
2479            .try_get_memory()?
2480            .set(output_size_ptr, &output_size_bytes)
2481        {
2482            return Err(ExecError::Interpreter(error.into()));
2483        }
2484
2485        // Write updated package to the global state
2486        self.context.metered_write_gs_unsafe(
2487            ContractPackageHash::new(contract_package_hash.value()),
2488            contract_package,
2489        )?;
2490
2491        Ok(Ok(()))
2492    }
2493
2494    fn create_contract_user_group(
2495        &mut self,
2496        contract_package_hash: PackageHash,
2497        label: String,
2498        num_new_urefs: u32,
2499        mut existing_urefs: BTreeSet<URef>,
2500        output_size_ptr: u32,
2501    ) -> Result<Result<(), ApiError>, ExecError> {
2502        if !self.context.engine_config().enable_entity {
2503            return self.create_contract_user_group_by_contract_package(
2504                contract_package_hash,
2505                label,
2506                num_new_urefs,
2507                existing_urefs,
2508                output_size_ptr,
2509            );
2510        };
2511
2512        let mut contract_package: Package =
2513            self.context.get_validated_package(contract_package_hash)?;
2514
2515        let groups = contract_package.groups_mut();
2516        let new_group = Group::new(label);
2517
2518        // Ensure group does not already exist
2519        if groups.contains(&new_group) {
2520            return Ok(Err(addressable_entity::Error::GroupAlreadyExists.into()));
2521        }
2522
2523        // Ensure there are not too many groups
2524        if groups.len() >= (addressable_entity::MAX_GROUPS as usize) {
2525            return Ok(Err(addressable_entity::Error::MaxGroupsExceeded.into()));
2526        }
2527
2528        // Ensure there are not too many urefs
2529        let total_urefs: usize =
2530            groups.total_urefs() + (num_new_urefs as usize) + existing_urefs.len();
2531        if total_urefs > addressable_entity::MAX_TOTAL_UREFS {
2532            let err = addressable_entity::Error::MaxTotalURefsExceeded;
2533            return Ok(Err(ApiError::ContractHeader(err as u8)));
2534        }
2535
2536        // Proceed with creating user group
2537        let mut new_urefs = Vec::with_capacity(num_new_urefs as usize);
2538        for _ in 0..num_new_urefs {
2539            let u = self.context.new_unit_uref()?;
2540            new_urefs.push(u);
2541        }
2542
2543        for u in new_urefs.iter().cloned() {
2544            existing_urefs.insert(u);
2545        }
2546        groups.insert(new_group, existing_urefs);
2547
2548        // check we can write to the host buffer
2549        if let Err(err) = self.check_host_buffer() {
2550            return Ok(Err(err));
2551        }
2552        // create CLValue for return value
2553        let new_urefs_value = CLValue::from_t(new_urefs)?;
2554        let value_size = new_urefs_value.inner_bytes().len();
2555        // write return value to buffer
2556        if let Err(err) = self.write_host_buffer(new_urefs_value) {
2557            return Ok(Err(err));
2558        }
2559        // Write return value size to output location
2560        let output_size_bytes = value_size.to_le_bytes(); // Wasm is little-endian
2561        if let Err(error) = self
2562            .try_get_memory()?
2563            .set(output_size_ptr, &output_size_bytes)
2564        {
2565            return Err(ExecError::Interpreter(error.into()));
2566        }
2567
2568        // Write updated package to the global state
2569        self.context
2570            .metered_write_gs_unsafe(contract_package_hash, contract_package)?;
2571
2572        Ok(Ok(()))
2573    }
2574
2575    #[allow(clippy::too_many_arguments)]
2576    fn add_contract_version(
2577        &mut self,
2578        package_hash: PackageHash,
2579        version_ptr: u32,
2580        entry_points: EntryPoints,
2581        named_keys: NamedKeys,
2582        message_topics: BTreeMap<String, MessageTopicOperation>,
2583        output_ptr: u32,
2584    ) -> Result<Result<(), ApiError>, ExecError> {
2585        if self.context.engine_config().enable_entity {
2586            self.add_contract_version_by_package(
2587                package_hash,
2588                version_ptr,
2589                entry_points,
2590                named_keys,
2591                message_topics,
2592                output_ptr,
2593            )
2594        } else {
2595            self.add_contract_version_by_contract_package(
2596                package_hash.value(),
2597                version_ptr,
2598                entry_points,
2599                named_keys,
2600                message_topics,
2601                output_ptr,
2602            )
2603        }
2604    }
2605
2606    #[allow(clippy::too_many_arguments)]
2607    fn add_contract_version_by_contract_package(
2608        &mut self,
2609        contract_package_hash: HashAddr,
2610        version_ptr: u32,
2611        entry_points: EntryPoints,
2612        mut named_keys: NamedKeys,
2613        message_topics: BTreeMap<String, MessageTopicOperation>,
2614        output_ptr: u32,
2615    ) -> Result<Result<(), ApiError>, ExecError> {
2616        if !self.context.install_upgrade_allowed() {
2617            // NOTE: This is not a permission check on the caller,
2618            // it is enforcing the rule that only legacy standard deploys (which are grandfathered)
2619            // and install / upgrade transactions are allowed to call this method
2620            return Ok(Err(ApiError::NotAllowedToAddContractVersion));
2621        }
2622
2623        // if entry_points.contains_stored_session() {
2624        //     // As of 2.0 we do not allow stored session logic to be
2625        //     // installed or upgraded. Pre-existing stored
2626        //     // session logic is still callable.
2627        //     return Err(ExecError::InvalidEntryPointType);
2628        // }
2629
2630        self.context
2631            .validate_key(&Key::Hash(contract_package_hash))?;
2632
2633        let mut contract_package: ContractPackage = self
2634            .context
2635            .get_validated_contract_package(contract_package_hash)?;
2636
2637        let version = contract_package.current_contract_version();
2638
2639        // Return an error if the contract is locked and has some version associated with it.
2640        if contract_package.is_locked() && version.is_some() {
2641            return Err(ExecError::LockedEntity(PackageHash::new(
2642                contract_package_hash,
2643            )));
2644        }
2645
2646        for (_, key) in named_keys.iter() {
2647            self.context.validate_key(key)?
2648        }
2649
2650        let contract_wasm_hash = self.context.new_hash_address()?;
2651        let contract_wasm = {
2652            let module_bytes = self.get_module_from_entry_points(&entry_points)?;
2653            ContractWasm::new(module_bytes)
2654        };
2655
2656        let contract_hash_addr: HashAddr = self.context.new_hash_address()?;
2657        let contract_entity_addr = EntityAddr::SmartContract(contract_hash_addr);
2658
2659        let protocol_version = self.context.protocol_version();
2660        let major = protocol_version.value().major;
2661
2662        let maybe_previous_hash =
2663            if let Some(previous_contract_hash) = contract_package.current_contract_hash() {
2664                let previous_contract: Contract =
2665                    self.context.read_gs_typed(&previous_contract_hash.into())?;
2666
2667                let previous_named_keys = previous_contract.take_named_keys();
2668                named_keys.append(previous_named_keys);
2669                Some(EntityAddr::SmartContract(previous_contract_hash.value()))
2670            } else {
2671                None
2672            };
2673
2674        if let Err(err) = self.carry_forward_message_topics(
2675            maybe_previous_hash,
2676            contract_entity_addr,
2677            message_topics,
2678        )? {
2679            return Ok(Err(err));
2680        };
2681
2682        let contract_package_hash = ContractPackageHash::new(contract_package_hash);
2683        let contract = Contract::new(
2684            contract_package_hash,
2685            contract_wasm_hash.into(),
2686            named_keys,
2687            entry_points.into(),
2688            protocol_version,
2689        );
2690
2691        let insert_contract_result =
2692            contract_package.insert_contract_version(major, contract_hash_addr.into());
2693
2694        self.context
2695            .metered_write_gs_unsafe(Key::Hash(contract_wasm_hash), contract_wasm)?;
2696        self.context
2697            .metered_write_gs_unsafe(Key::Hash(contract_hash_addr), contract)?;
2698        self.context
2699            .metered_write_gs_unsafe(Key::Hash(contract_package_hash.value()), contract_package)?;
2700
2701        // set return values to buffer
2702        {
2703            let hash_bytes = match contract_hash_addr.to_bytes() {
2704                Ok(bytes) => bytes,
2705                Err(error) => return Ok(Err(error.into())),
2706            };
2707
2708            // Set serialized hash bytes into the output buffer
2709            if let Err(error) = self.try_get_memory()?.set(output_ptr, &hash_bytes) {
2710                return Err(ExecError::Interpreter(error.into()));
2711            }
2712
2713            // Set version into VM shared memory
2714            let version_value: u32 = insert_contract_result.contract_version();
2715            let version_bytes = version_value.to_le_bytes();
2716            if let Err(error) = self.try_get_memory()?.set(version_ptr, &version_bytes) {
2717                return Err(ExecError::Interpreter(error.into()));
2718            }
2719        }
2720
2721        Ok(Ok(()))
2722    }
2723
2724    #[allow(clippy::too_many_arguments)]
2725    fn add_contract_version_by_package(
2726        &mut self,
2727        package_hash: PackageHash,
2728        version_ptr: u32,
2729        entry_points: EntryPoints,
2730        mut named_keys: NamedKeys,
2731        message_topics: BTreeMap<String, MessageTopicOperation>,
2732        output_ptr: u32,
2733    ) -> Result<Result<(), ApiError>, ExecError> {
2734        if !self.context.install_upgrade_allowed() {
2735            // NOTE: This is not a permission check on the caller,
2736            // it is enforcing the rule that only legacy standard deploys (which are grandfathered)
2737            // and install / upgrade transactions are allowed to call this method
2738            return Ok(Err(ApiError::NotAllowedToAddContractVersion));
2739        }
2740
2741        if entry_points.contains_stored_session() {
2742            // As of 2.0 we do not allow stored session logic to be
2743            // installed or upgraded. Pre-existing stored
2744            // session logic is still callable.
2745            return Err(ExecError::InvalidEntryPointType);
2746        }
2747
2748        let mut package = self.context.get_package(package_hash.value())?;
2749
2750        // Return an error if the contract is locked and has some version associated with it.
2751        if package.is_locked() {
2752            return Err(ExecError::LockedEntity(package_hash));
2753        }
2754
2755        let (
2756            main_purse,
2757            previous_named_keys,
2758            action_thresholds,
2759            associated_keys,
2760            previous_hash_addr,
2761        ) = self.new_version_entity_parts(&package)?;
2762
2763        // We generate the byte code hash because a byte code record
2764        // must exist for a contract record to exist.
2765        let byte_code_hash = self.context.new_hash_address()?;
2766
2767        let hash_addr = self.context.new_hash_address()?;
2768        let entity_addr = EntityAddr::SmartContract(hash_addr);
2769
2770        if let Err(err) =
2771            self.carry_forward_message_topics(previous_hash_addr, entity_addr, message_topics)?
2772        {
2773            return Ok(Err(err));
2774        };
2775
2776        let protocol_version = self.context.protocol_version();
2777
2778        let insert_entity_version_result =
2779            package.insert_entity_version(protocol_version.value().major, entity_addr);
2780
2781        let byte_code = {
2782            let module_bytes = self.get_module_from_entry_points(&entry_points)?;
2783            ByteCode::new(ByteCodeKind::V1CasperWasm, module_bytes)
2784        };
2785
2786        self.context.metered_write_gs_unsafe(
2787            Key::ByteCode(ByteCodeAddr::new_wasm_addr(byte_code_hash)),
2788            byte_code,
2789        )?;
2790
2791        let entity_addr = EntityAddr::new_smart_contract(hash_addr);
2792
2793        {
2794            // DO NOT EXTRACT INTO SEPARATE FUNCTION.
2795            for (_, key) in named_keys.iter() {
2796                // Validate all the imputed named keys
2797                // against the installers permissions
2798                self.context.validate_key(key)?;
2799            }
2800            // Carry forward named keys from previous version
2801            // Grant all the imputed named keys + previous named keys.
2802            named_keys.append(previous_named_keys);
2803            for (name, key) in named_keys.iter() {
2804                let named_key_value =
2805                    StoredValue::NamedKey(NamedKeyValue::from_concrete_values(*key, name.clone())?);
2806                let named_key_addr = NamedKeyAddr::new_from_string(entity_addr, name.clone())?;
2807                self.context
2808                    .metered_write_gs_unsafe(Key::NamedKey(named_key_addr), named_key_value)?;
2809            }
2810            self.context.write_entry_points(entity_addr, entry_points)?;
2811        }
2812
2813        let entity = AddressableEntity::new(
2814            package_hash,
2815            byte_code_hash.into(),
2816            protocol_version,
2817            main_purse,
2818            associated_keys,
2819            action_thresholds,
2820            EntityKind::SmartContract(ContractRuntimeTag::VmCasperV1),
2821        );
2822        let entity_key = Key::AddressableEntity(entity_addr);
2823        self.context.metered_write_gs_unsafe(entity_key, entity)?;
2824        self.context
2825            .metered_write_gs_unsafe(package_hash, package)?;
2826
2827        // set return values to buffer
2828        {
2829            let hash_bytes = match hash_addr.to_bytes() {
2830                Ok(bytes) => bytes,
2831                Err(error) => return Ok(Err(error.into())),
2832            };
2833
2834            // Set serialized hash bytes into the output buffer
2835            if let Err(error) = self.try_get_memory()?.set(output_ptr, &hash_bytes) {
2836                return Err(ExecError::Interpreter(error.into()));
2837            }
2838
2839            // Set version into VM shared memory
2840            let version_value: u32 = insert_entity_version_result.entity_version();
2841            let version_bytes = version_value.to_le_bytes();
2842            if let Err(error) = self.try_get_memory()?.set(version_ptr, &version_bytes) {
2843                return Err(ExecError::Interpreter(error.into()));
2844            }
2845        }
2846
2847        Ok(Ok(()))
2848    }
2849
2850    fn carry_forward_message_topics(
2851        &mut self,
2852        previous_entity_addr: Option<EntityAddr>,
2853        entity_addr: EntityAddr,
2854        message_topics: BTreeMap<String, MessageTopicOperation>,
2855    ) -> Result<Result<(), ApiError>, ExecError> {
2856        let mut previous_message_topics = match previous_entity_addr {
2857            Some(previous_hash) => self.context.get_message_topics(previous_hash)?,
2858            None => MessageTopics::default(),
2859        };
2860
2861        let max_topics_per_contract = self
2862            .context
2863            .engine_config()
2864            .wasm_config()
2865            .messages_limits()
2866            .max_topics_per_contract();
2867
2868        let topics_to_add = message_topics
2869            .iter()
2870            .filter(|(_, operation)| match operation {
2871                MessageTopicOperation::Add => true,
2872            });
2873        // Check if registering the new topics would exceed the limit per contract
2874        if previous_message_topics.len() + topics_to_add.clone().count()
2875            > max_topics_per_contract as usize
2876        {
2877            return Ok(Err(ApiError::from(MessageTopicError::MaxTopicsExceeded)));
2878        }
2879
2880        // Extend the previous topics with the newly added ones.
2881        for (new_topic, _) in topics_to_add {
2882            let topic_name_hash = cryptography::blake2b(new_topic.as_bytes()).into();
2883            if let Err(e) = previous_message_topics.add_topic(new_topic.as_str(), topic_name_hash) {
2884                return Ok(Err(e.into()));
2885            }
2886        }
2887
2888        for (topic_name, topic_hash) in previous_message_topics.iter() {
2889            let topic_key = Key::message_topic(entity_addr, *topic_hash);
2890            let block_time = self.context.get_block_info().block_time();
2891            let summary = StoredValue::MessageTopic(MessageTopicSummary::new(
2892                0,
2893                block_time,
2894                topic_name.clone(),
2895            ));
2896            self.context.metered_write_gs_unsafe(topic_key, summary)?;
2897        }
2898        Ok(Ok(()))
2899    }
2900
2901    fn new_version_entity_parts(
2902        &mut self,
2903        package: &Package,
2904    ) -> Result<
2905        (
2906            URef,
2907            NamedKeys,
2908            ActionThresholds,
2909            AssociatedKeys,
2910            Option<EntityAddr>,
2911        ),
2912        ExecError,
2913    > {
2914        if let Some(previous_entity_hash) = package.current_entity_hash() {
2915            let previous_entity_key = Key::AddressableEntity(previous_entity_hash);
2916            let (mut previous_entity, requires_purse_creation) =
2917                self.context.get_contract_entity(previous_entity_key)?;
2918
2919            let action_thresholds = previous_entity.action_thresholds().clone();
2920
2921            let associated_keys = previous_entity.associated_keys().clone();
2922            // STEP 1: LOAD THE CONTRACT AND CHECK IF CALLER IS IN ASSOCIATED KEYS WITH ENOUGH
2923            // WEIGHT     TO UPGRADE (COMPARE TO THE ACTION THRESHOLD FOR UPGRADE
2924            // ACTION). STEP 2: IF CALLER IS NOT IN CONTRACTS ASSOCIATED KEYS
2925            //    CHECK FOR LEGACY UREFADDR UNDER KEY:HASH(PACKAGEADDR)
2926            //    IF FOUND,
2927            //      call validate_uref(that uref)
2928            //    IF VALID,
2929            //      create the new contract version carrying forward previous state including
2930            // associated keys      BUT add the caller to the associated keys with
2931            // weight == to the action threshold for upgrade ELSE, error
2932            if !previous_entity.can_upgrade_with(self.context.authorization_keys()) {
2933                // Check if the calling entity must be grandfathered into the new
2934                // addressable entity format
2935                let account_hash = self.context.get_initiator();
2936
2937                let access_key = match self
2938                    .context
2939                    .read_gs(&Key::Hash(previous_entity.package_hash().value()))?
2940                {
2941                    Some(StoredValue::ContractPackage(contract_package)) => {
2942                        contract_package.access_key()
2943                    }
2944                    Some(StoredValue::CLValue(cl_value)) => {
2945                        let (_key, uref) = cl_value
2946                            .into_t::<(Key, URef)>()
2947                            .map_err(ExecError::CLValue)?;
2948                        uref
2949                    }
2950                    Some(_other) => return Err(ExecError::UnexpectedStoredValueVariant),
2951                    None => {
2952                        return Err(ExecError::UpgradeAuthorizationFailure);
2953                    }
2954                };
2955
2956                let has_access = self.context.validate_uref(&access_key).is_ok();
2957
2958                if has_access && !associated_keys.contains_key(&account_hash) {
2959                    previous_entity.add_associated_key(
2960                        account_hash,
2961                        *action_thresholds.upgrade_management(),
2962                    )?;
2963                } else {
2964                    return Err(ExecError::UpgradeAuthorizationFailure);
2965                }
2966            }
2967
2968            let main_purse = if requires_purse_creation {
2969                self.create_purse()?
2970            } else {
2971                previous_entity.main_purse()
2972            };
2973
2974            let associated_keys = previous_entity.associated_keys().clone();
2975
2976            let previous_named_keys = self.context.get_named_keys(previous_entity_key)?;
2977
2978            return Ok((
2979                main_purse,
2980                previous_named_keys,
2981                action_thresholds,
2982                associated_keys,
2983                Some(previous_entity_hash),
2984            ));
2985        }
2986
2987        Ok((
2988            self.create_purse()?,
2989            NamedKeys::new(),
2990            ActionThresholds::default(),
2991            AssociatedKeys::new(self.context.get_initiator(), Weight::new(1)),
2992            None,
2993        ))
2994    }
2995
2996    fn disable_contract_version(
2997        &mut self,
2998        contract_package_hash: PackageHash,
2999        contract_hash: AddressableEntityHash,
3000    ) -> Result<Result<(), ApiError>, ExecError> {
3001        if self.context.engine_config().enable_entity {
3002            let contract_package_key = Key::SmartContract(contract_package_hash.value());
3003            self.context.validate_key(&contract_package_key)?;
3004
3005            let mut contract_package: Package =
3006                self.context.get_validated_package(contract_package_hash)?;
3007
3008            if contract_package.is_locked() {
3009                return Err(ExecError::LockedEntity(contract_package_hash));
3010            }
3011
3012            if let Err(err) = contract_package
3013                .disable_entity_version(EntityAddr::SmartContract(contract_hash.value()))
3014            {
3015                return Ok(Err(err.into()));
3016            }
3017
3018            self.context
3019                .metered_write_gs_unsafe(contract_package_key, contract_package)?;
3020        } else {
3021            let contract_package_key = Key::Hash(contract_package_hash.value());
3022            self.context.validate_key(&contract_package_key)?;
3023
3024            let mut contract_package: ContractPackage = self
3025                .context
3026                .get_validated_contract_package(contract_package_hash.value())?;
3027
3028            if contract_package.is_locked() {
3029                return Err(ExecError::LockedEntity(PackageHash::new(
3030                    contract_package_hash.value(),
3031                )));
3032            }
3033            let contract_hash = ContractHash::new(contract_hash.value());
3034
3035            if let Err(err) = contract_package.disable_contract_version(contract_hash) {
3036                return Ok(Err(err.into()));
3037            }
3038
3039            self.context
3040                .metered_write_gs_unsafe(contract_package_key, contract_package)?;
3041        }
3042
3043        Ok(Ok(()))
3044    }
3045
3046    fn enable_contract_version(
3047        &mut self,
3048        contract_package_hash: PackageHash,
3049        contract_hash: AddressableEntityHash,
3050    ) -> Result<Result<(), ApiError>, ExecError> {
3051        if self.context.engine_config().enable_entity {
3052            let contract_package_key = Key::SmartContract(contract_package_hash.value());
3053            self.context.validate_key(&contract_package_key)?;
3054
3055            let mut contract_package: Package =
3056                self.context.get_validated_package(contract_package_hash)?;
3057
3058            if contract_package.is_locked() {
3059                return Err(ExecError::LockedEntity(contract_package_hash));
3060            }
3061
3062            if let Err(err) =
3063                contract_package.enable_version(EntityAddr::SmartContract(contract_hash.value()))
3064            {
3065                return Ok(Err(err.into()));
3066            }
3067
3068            self.context
3069                .metered_write_gs_unsafe(contract_package_key, contract_package)?;
3070        } else {
3071            let contract_package_key = Key::Hash(contract_package_hash.value());
3072            self.context.validate_key(&contract_package_key)?;
3073
3074            let mut contract_package: ContractPackage = self
3075                .context
3076                .get_validated_contract_package(contract_package_hash.value())?;
3077
3078            if contract_package.is_locked() {
3079                return Err(ExecError::LockedEntity(PackageHash::new(
3080                    contract_package_hash.value(),
3081                )));
3082            }
3083            let contract_hash = ContractHash::new(contract_hash.value());
3084
3085            if let Err(err) = contract_package.enable_contract_version(contract_hash) {
3086                return Ok(Err(err.into()));
3087            }
3088
3089            self.context
3090                .metered_write_gs_unsafe(contract_package_key, contract_package)?;
3091        }
3092
3093        Ok(Ok(()))
3094    }
3095
3096    /// Writes function address (`hash_bytes`) into the Wasm memory (at
3097    /// `dest_ptr` pointer).
3098    fn function_address(&mut self, hash_bytes: [u8; 32], dest_ptr: u32) -> Result<(), Trap> {
3099        self.try_get_memory()?
3100            .set(dest_ptr, &hash_bytes)
3101            .map_err(|e| ExecError::Interpreter(e.into()).into())
3102    }
3103
3104    /// Generates new unforgeable reference and adds it to the context's
3105    /// access_rights set.
3106    fn new_uref(&mut self, uref_ptr: u32, value_ptr: u32, value_size: u32) -> Result<(), Trap> {
3107        let cl_value = self.cl_value_from_mem(value_ptr, value_size)?; // read initial value from memory
3108        let uref = self.context.new_uref(StoredValue::CLValue(cl_value))?;
3109        self.try_get_memory()?
3110            .set(uref_ptr, &uref.into_bytes().map_err(ExecError::BytesRepr)?)
3111            .map_err(|e| ExecError::Interpreter(e.into()).into())
3112    }
3113
3114    /// Writes `value` under `key` in GlobalState.
3115    fn write(
3116        &mut self,
3117        key_ptr: u32,
3118        key_size: u32,
3119        value_ptr: u32,
3120        value_size: u32,
3121    ) -> Result<(), Trap> {
3122        let key = self.key_from_mem(key_ptr, key_size)?;
3123        let cl_value = self.cl_value_from_mem(value_ptr, value_size)?;
3124        self.context
3125            .metered_write_gs(key, cl_value)
3126            .map_err(Into::into)
3127    }
3128
3129    /// Records a transfer.
3130    fn record_transfer(
3131        &mut self,
3132        maybe_to: Option<AccountHash>,
3133        source: URef,
3134        target: URef,
3135        amount: U512,
3136        id: Option<u64>,
3137    ) -> Result<(), ExecError> {
3138        if self.context.get_context_key() != self.context.get_system_entity_key(MINT)? {
3139            return Err(ExecError::InvalidContext);
3140        }
3141
3142        if self.context.phase() != Phase::Session {
3143            return Ok(());
3144        }
3145
3146        let txn_hash = self.context.get_transaction_hash();
3147        let from = InitiatorAddr::AccountHash(self.context.get_initiator());
3148        let fee = Gas::from(
3149            self.context
3150                .engine_config()
3151                .system_config()
3152                .mint_costs()
3153                .transfer,
3154        );
3155        let transfer = Transfer::V2(TransferV2::new(
3156            txn_hash, from, maybe_to, source, target, amount, fee, id,
3157        ));
3158        self.context.transfers_mut().push(transfer);
3159        Ok(())
3160    }
3161
3162    /// Records given auction info at a given era id
3163    fn record_era_info(&mut self, era_info: EraInfo) -> Result<(), ExecError> {
3164        if self.context.get_initiator() != PublicKey::System.to_account_hash() {
3165            return Err(ExecError::InvalidContext);
3166        }
3167
3168        if self.context.get_context_key() != self.context.get_system_entity_key(AUCTION)? {
3169            return Err(ExecError::InvalidContext);
3170        }
3171
3172        if self.context.phase() != Phase::Session {
3173            return Ok(());
3174        }
3175
3176        self.context.write_era_info(Key::EraSummary, era_info);
3177
3178        Ok(())
3179    }
3180
3181    /// Adds `value` to the cell that `key` points at.
3182    fn add(
3183        &mut self,
3184        key_ptr: u32,
3185        key_size: u32,
3186        value_ptr: u32,
3187        value_size: u32,
3188    ) -> Result<(), Trap> {
3189        let key = self.key_from_mem(key_ptr, key_size)?;
3190        let cl_value = self.cl_value_from_mem(value_ptr, value_size)?;
3191        self.context
3192            .metered_add_gs(key, cl_value)
3193            .map_err(Into::into)
3194    }
3195
3196    /// Reads value from the GS living under key specified by `key_ptr` and
3197    /// `key_size`. Wasm and host communicate through memory that Wasm
3198    /// module exports. If contract wants to pass data to the host, it has
3199    /// to tell it [the host] where this data lives in the exported memory
3200    /// (pass its pointer and length).
3201    fn read(
3202        &mut self,
3203        key_ptr: u32,
3204        key_size: u32,
3205        output_size_ptr: u32,
3206    ) -> Result<Result<(), ApiError>, Trap> {
3207        if !self.can_write_to_host_buffer() {
3208            // Exit early if the host buffer is already occupied
3209            return Ok(Err(ApiError::HostBufferFull));
3210        }
3211
3212        let key = self.key_from_mem(key_ptr, key_size)?;
3213        let cl_value = match self.context.read_gs(&key)? {
3214            Some(stored_value) => {
3215                CLValue::try_from(stored_value).map_err(ExecError::TypeMismatch)?
3216            }
3217            None => return Ok(Err(ApiError::ValueNotFound)),
3218        };
3219
3220        let value_size: u32 = match cl_value.inner_bytes().len().try_into() {
3221            Ok(value) => value,
3222            Err(_) => return Ok(Err(ApiError::BufferTooSmall)),
3223        };
3224
3225        if let Err(error) = self.write_host_buffer(cl_value) {
3226            return Ok(Err(error));
3227        }
3228
3229        let value_bytes = value_size.to_le_bytes(); // Wasm is little-endian
3230        if let Err(error) = self.try_get_memory()?.set(output_size_ptr, &value_bytes) {
3231            return Err(ExecError::Interpreter(error.into()).into());
3232        }
3233
3234        Ok(Ok(()))
3235    }
3236
3237    /// Reverts contract execution with a status specified.
3238    fn revert(&mut self, status: u32) -> Trap {
3239        ExecError::Revert(status.into()).into()
3240    }
3241
3242    /// Checks if a caller can manage its own associated keys and thresholds.
3243    ///
3244    /// On some private chains with administrator keys configured this requires that the caller is
3245    /// an admin to be able to manage its own keys. If the caller is not an administrator then the
3246    /// deploy has to be signed by an administrator.
3247    fn can_manage_keys(&self) -> bool {
3248        if self
3249            .context
3250            .engine_config()
3251            .administrative_accounts()
3252            .is_empty()
3253        {
3254            // Public chain
3255            return self
3256                .context
3257                .runtime_footprint()
3258                .borrow()
3259                .can_manage_keys_with(self.context.authorization_keys());
3260        }
3261
3262        if self
3263            .context
3264            .engine_config()
3265            .is_administrator(&self.context.get_initiator())
3266        {
3267            return true;
3268        }
3269
3270        // If caller is not an admin, check if deploy was co-signed by admin account.
3271        self.context.is_authorized_by_admin()
3272    }
3273
3274    fn add_associated_key(
3275        &mut self,
3276        account_hash_ptr: u32,
3277        account_hash_size: usize,
3278        weight_value: u8,
3279    ) -> Result<i32, Trap> {
3280        let account_hash = {
3281            // Account hash as serialized bytes
3282            let source_serialized = self.bytes_from_mem(account_hash_ptr, account_hash_size)?;
3283            // Account hash deserialized
3284            let source: AccountHash = bytesrepr::deserialize_from_slice(source_serialized)
3285                .map_err(ExecError::BytesRepr)?;
3286            source
3287        };
3288        let weight = Weight::new(weight_value);
3289
3290        if !self.can_manage_keys() {
3291            return Ok(AddKeyFailure::PermissionDenied as i32);
3292        }
3293
3294        match self.context.add_associated_key(account_hash, weight) {
3295            Ok(_) => Ok(0),
3296            // This relies on the fact that `AddKeyFailure` is represented as
3297            // i32 and first variant start with number `1`, so all other variants
3298            // are greater than the first one, so it's safe to assume `0` is success,
3299            // and any error is greater than 0.
3300            Err(ExecError::AddKeyFailure(e)) => Ok(e as i32),
3301            // Any other variant just pass as `Trap`
3302            Err(e) => Err(e.into()),
3303        }
3304    }
3305
3306    fn remove_associated_key(
3307        &mut self,
3308        account_hash_ptr: u32,
3309        account_hash_size: usize,
3310    ) -> Result<i32, Trap> {
3311        let account_hash = {
3312            // Account hash as serialized bytes
3313            let source_serialized = self.bytes_from_mem(account_hash_ptr, account_hash_size)?;
3314            // Account hash deserialized
3315            let source: AccountHash = bytesrepr::deserialize_from_slice(source_serialized)
3316                .map_err(ExecError::BytesRepr)?;
3317            source
3318        };
3319
3320        if !self.can_manage_keys() {
3321            return Ok(RemoveKeyFailure::PermissionDenied as i32);
3322        }
3323
3324        match self.context.remove_associated_key(account_hash) {
3325            Ok(_) => Ok(0),
3326            Err(ExecError::RemoveKeyFailure(e)) => Ok(e as i32),
3327            Err(e) => Err(e.into()),
3328        }
3329    }
3330
3331    fn update_associated_key(
3332        &mut self,
3333        account_hash_ptr: u32,
3334        account_hash_size: usize,
3335        weight_value: u8,
3336    ) -> Result<i32, Trap> {
3337        let account_hash = {
3338            // Account hash as serialized bytes
3339            let source_serialized = self.bytes_from_mem(account_hash_ptr, account_hash_size)?;
3340            // Account hash deserialized
3341            let source: AccountHash = bytesrepr::deserialize_from_slice(source_serialized)
3342                .map_err(ExecError::BytesRepr)?;
3343            source
3344        };
3345        let weight = Weight::new(weight_value);
3346
3347        if !self.can_manage_keys() {
3348            return Ok(UpdateKeyFailure::PermissionDenied as i32);
3349        }
3350
3351        match self.context.update_associated_key(account_hash, weight) {
3352            Ok(_) => Ok(0),
3353            // This relies on the fact that `UpdateKeyFailure` is represented as
3354            // i32 and first variant start with number `1`, so all other variants
3355            // are greater than the first one, so it's safe to assume `0` is success,
3356            // and any error is greater than 0.
3357            Err(ExecError::UpdateKeyFailure(e)) => Ok(e as i32),
3358            // Any other variant just pass as `Trap`
3359            Err(e) => Err(e.into()),
3360        }
3361    }
3362
3363    fn set_action_threshold(
3364        &mut self,
3365        action_type_value: u32,
3366        threshold_value: u8,
3367    ) -> Result<i32, Trap> {
3368        if !self.can_manage_keys() {
3369            return Ok(SetThresholdFailure::PermissionDeniedError as i32);
3370        }
3371
3372        match ActionType::try_from(action_type_value) {
3373            Ok(action_type) => {
3374                let threshold = Weight::new(threshold_value);
3375                match self.context.set_action_threshold(action_type, threshold) {
3376                    Ok(_) => Ok(0),
3377                    Err(ExecError::SetThresholdFailure(e)) => Ok(e as i32),
3378                    Err(error) => Err(error.into()),
3379                }
3380            }
3381            Err(_) => Err(Trap::Code(TrapCode::Unreachable)),
3382        }
3383    }
3384
3385    /// Looks up the public mint contract key in the context's protocol data.
3386    ///
3387    /// Returned URef is already attenuated depending on the calling account.
3388    fn get_mint_hash(&self) -> Result<AddressableEntityHash, ExecError> {
3389        self.context.get_system_contract(MINT)
3390    }
3391
3392    /// Looks up the public handle payment contract key in the context's protocol data.
3393    ///
3394    /// Returned URef is already attenuated depending on the calling account.
3395    fn get_handle_payment_hash(&self) -> Result<AddressableEntityHash, ExecError> {
3396        self.context.get_system_contract(HANDLE_PAYMENT)
3397    }
3398
3399    /// Looks up the public standard payment contract key in the context's protocol data.
3400    ///
3401    /// Returned URef is already attenuated depending on the calling account.
3402    fn get_standard_payment_hash(&self) -> Result<AddressableEntityHash, ExecError> {
3403        self.context.get_system_contract(STANDARD_PAYMENT)
3404    }
3405
3406    /// Looks up the public auction contract key in the context's protocol data.
3407    ///
3408    /// Returned URef is already attenuated depending on the calling account.
3409    fn get_auction_hash(&self) -> Result<AddressableEntityHash, ExecError> {
3410        self.context.get_system_contract(AUCTION)
3411    }
3412
3413    /// Calls the `read_base_round_reward` method on the mint contract at the given mint
3414    /// contract key
3415    fn mint_read_base_round_reward(
3416        &mut self,
3417        mint_contract_hash: AddressableEntityHash,
3418    ) -> Result<U512, ExecError> {
3419        let gas_counter = self.gas_counter();
3420        let call_result = self.call_contract(
3421            mint_contract_hash,
3422            mint::METHOD_READ_BASE_ROUND_REWARD,
3423            RuntimeArgs::default(),
3424        );
3425        self.set_gas_counter(gas_counter);
3426
3427        let reward = call_result?.into_t()?;
3428        Ok(reward)
3429    }
3430
3431    /// Calls the `mint` method on the mint contract at the given mint
3432    /// contract key
3433    fn mint_mint(
3434        &mut self,
3435        mint_contract_hash: AddressableEntityHash,
3436        amount: U512,
3437    ) -> Result<URef, ExecError> {
3438        let gas_counter = self.gas_counter();
3439        let runtime_args = {
3440            let mut runtime_args = RuntimeArgs::new();
3441            runtime_args.insert(mint::ARG_AMOUNT, amount)?;
3442            runtime_args
3443        };
3444        let call_result = self.call_contract(mint_contract_hash, mint::METHOD_MINT, runtime_args);
3445        self.set_gas_counter(gas_counter);
3446
3447        let result: Result<URef, mint::Error> = call_result?.into_t()?;
3448        Ok(result.map_err(system::Error::from)?)
3449    }
3450
3451    /// Calls the `reduce_total_supply` method on the mint contract at the given mint
3452    /// contract key
3453    fn mint_reduce_total_supply(
3454        &mut self,
3455        mint_contract_hash: AddressableEntityHash,
3456        amount: U512,
3457    ) -> Result<(), ExecError> {
3458        let gas_counter = self.gas_counter();
3459        let runtime_args = {
3460            let mut runtime_args = RuntimeArgs::new();
3461            runtime_args.insert(mint::ARG_AMOUNT, amount)?;
3462            runtime_args
3463        };
3464        let call_result = self.call_contract(
3465            mint_contract_hash,
3466            mint::METHOD_REDUCE_TOTAL_SUPPLY,
3467            runtime_args,
3468        );
3469        self.set_gas_counter(gas_counter);
3470
3471        let result: Result<(), mint::Error> = call_result?.into_t()?;
3472        Ok(result.map_err(system::Error::from)?)
3473    }
3474
3475    /// Calls the "create" method on the mint contract at the given mint
3476    /// contract key
3477    fn mint_create(
3478        &mut self,
3479        mint_contract_hash: AddressableEntityHash,
3480    ) -> Result<URef, ExecError> {
3481        let result =
3482            self.call_contract(mint_contract_hash, mint::METHOD_CREATE, RuntimeArgs::new());
3483        let purse = result?.into_t()?;
3484        Ok(purse)
3485    }
3486
3487    fn create_purse(&mut self) -> Result<URef, ExecError> {
3488        let _scoped_host_function_flag = self.host_function_flag.enter_host_function_scope();
3489        self.mint_create(self.get_mint_hash()?)
3490    }
3491
3492    /// Calls the "transfer" method on the mint contract at the given mint
3493    /// contract key
3494    fn mint_transfer(
3495        &mut self,
3496        mint_contract_hash: AddressableEntityHash,
3497        to: Option<AccountHash>,
3498        source: URef,
3499        target: URef,
3500        amount: U512,
3501        id: Option<u64>,
3502    ) -> Result<Result<(), mint::Error>, ExecError> {
3503        self.context.validate_uref(&source)?;
3504
3505        let args_values = {
3506            let mut runtime_args = RuntimeArgs::new();
3507            runtime_args.insert(mint::ARG_TO, to)?;
3508            runtime_args.insert(mint::ARG_SOURCE, source)?;
3509            runtime_args.insert(mint::ARG_TARGET, target)?;
3510            runtime_args.insert(mint::ARG_AMOUNT, amount)?;
3511            runtime_args.insert(mint::ARG_ID, id)?;
3512            runtime_args
3513        };
3514
3515        let gas_counter = self.gas_counter();
3516        let call_result =
3517            self.call_contract(mint_contract_hash, mint::METHOD_TRANSFER, args_values);
3518        self.set_gas_counter(gas_counter);
3519
3520        Ok(call_result?.into_t()?)
3521    }
3522
3523    /// Creates a new account at `target` hash, transferring `amount`
3524    /// of motes from `source` purse to the new account's main purse.
3525    fn transfer_to_new_account(
3526        &mut self,
3527        source: URef,
3528        target: AccountHash,
3529        amount: U512,
3530        id: Option<u64>,
3531    ) -> Result<TransferResult, ExecError> {
3532        let mint_contract_hash = self.get_mint_hash()?;
3533
3534        let allow_unrestricted_transfers =
3535            self.context.engine_config().allow_unrestricted_transfers();
3536
3537        if !allow_unrestricted_transfers
3538            && self.context.get_initiator() != PublicKey::System.to_account_hash()
3539            && !self
3540                .context
3541                .engine_config()
3542                .is_administrator(&self.context.get_initiator())
3543            && !self.context.engine_config().is_administrator(&target)
3544        {
3545            return Err(ExecError::DisabledUnrestrictedTransfers);
3546        }
3547
3548        // A precondition check that verifies that the transfer can be done
3549        // as the source purse has enough funds to cover the transfer.
3550        if amount > self.available_balance(source)?.unwrap_or_default() {
3551            return Ok(Err(mint::Error::InsufficientFunds.into()));
3552        }
3553
3554        let target_purse = self.mint_create(mint_contract_hash)?;
3555
3556        if source == target_purse {
3557            return Ok(Err(mint::Error::EqualSourceAndTarget.into()));
3558        }
3559
3560        let result = self.mint_transfer(
3561            mint_contract_hash,
3562            Some(target),
3563            source,
3564            target_purse.with_access_rights(AccessRights::ADD),
3565            amount,
3566            id,
3567        );
3568
3569        // We granted a temporary access rights bit to newly created main purse as part of
3570        // `mint_create` call, and we need to remove it to avoid leakage of access rights.
3571
3572        self.context
3573            .remove_access(target_purse.addr(), target_purse.access_rights());
3574
3575        match result? {
3576            Ok(()) => {
3577                let main_purse = target_purse;
3578                if !self.context.engine_config().enable_entity {
3579                    let account = Account::create(target, NamedKeys::new(), target_purse);
3580                    self.context.metered_write_gs_unsafe(
3581                        Key::Account(target),
3582                        StoredValue::Account(account),
3583                    )?;
3584                    return Ok(Ok(TransferredTo::NewAccount));
3585                }
3586
3587                let protocol_version = self.context.protocol_version();
3588                let byte_code_hash = ByteCodeHash::default();
3589                let entity_hash = AddressableEntityHash::new(target.value());
3590                let package_hash = PackageHash::new(self.context.new_hash_address()?);
3591
3592                let associated_keys = AssociatedKeys::new(target, Weight::new(1));
3593
3594                let entity = AddressableEntity::new(
3595                    package_hash,
3596                    byte_code_hash,
3597                    protocol_version,
3598                    main_purse,
3599                    associated_keys,
3600                    ActionThresholds::default(),
3601                    EntityKind::Account(target),
3602                );
3603
3604                let package = {
3605                    let mut package = Package::new(
3606                        EntityVersions::default(),
3607                        BTreeSet::default(),
3608                        Groups::default(),
3609                        PackageStatus::Locked,
3610                    );
3611                    package.insert_entity_version(
3612                        protocol_version.value().major,
3613                        EntityAddr::Account(target.value()),
3614                    );
3615                    package
3616                };
3617
3618                let entity_key: Key = entity.entity_key(entity_hash);
3619
3620                self.context
3621                    .metered_write_gs_unsafe(entity_key, StoredValue::AddressableEntity(entity))?;
3622
3623                let contract_package_key: Key = package_hash.into();
3624
3625                self.context.metered_write_gs_unsafe(
3626                    contract_package_key,
3627                    StoredValue::SmartContract(package),
3628                )?;
3629
3630                let contract_by_account = CLValue::from_t(entity_key)?;
3631
3632                let target_key = Key::Account(target);
3633
3634                self.context.metered_write_gs_unsafe(
3635                    target_key,
3636                    StoredValue::CLValue(contract_by_account),
3637                )?;
3638
3639                Ok(Ok(TransferredTo::NewAccount))
3640            }
3641            Err(mint_error) => Ok(Err(mint_error.into())),
3642        }
3643    }
3644
3645    /// Transferring a given amount of motes from the given source purse to the
3646    /// new account's purse. Requires that the [`URef`]s have already
3647    /// been created by the mint contract (or are the genesis account's).
3648    fn transfer_to_existing_account(
3649        &mut self,
3650        to: Option<AccountHash>,
3651        source: URef,
3652        target: URef,
3653        amount: U512,
3654        id: Option<u64>,
3655    ) -> Result<TransferResult, ExecError> {
3656        let mint_contract_key = self.get_mint_hash()?;
3657
3658        match self.mint_transfer(mint_contract_key, to, source, target, amount, id)? {
3659            Ok(()) => Ok(Ok(TransferredTo::ExistingAccount)),
3660            Err(error) => Ok(Err(error.into())),
3661        }
3662    }
3663
3664    /// Transfers `amount` of motes from default purse of the account to
3665    /// `target` account. If that account does not exist, creates one.
3666    fn transfer_to_account(
3667        &mut self,
3668        target: AccountHash,
3669        amount: U512,
3670        id: Option<u64>,
3671    ) -> Result<TransferResult, ExecError> {
3672        let source = self.context.get_main_purse()?;
3673        self.transfer_from_purse_to_account_hash(source, target, amount, id)
3674    }
3675
3676    /// Transfers `amount` of motes from `source` purse to `target` account's main purse.
3677    /// If that account does not exist, creates one.
3678    fn transfer_from_purse_to_account_hash(
3679        &mut self,
3680        source: URef,
3681        target: AccountHash,
3682        amount: U512,
3683        id: Option<u64>,
3684    ) -> Result<TransferResult, ExecError> {
3685        let _scoped_host_function_flag = self.host_function_flag.enter_host_function_scope();
3686        let target_key = Key::Account(target);
3687
3688        // Look up the account at the given key
3689        match self.context.read_gs(&target_key)? {
3690            None => {
3691                // If no account exists, create a new account and transfer the amount to its
3692                // main purse.
3693
3694                self.transfer_to_new_account(source, target, amount, id)
3695            }
3696            Some(StoredValue::CLValue(entity_key_value)) => {
3697                // Attenuate the target main purse
3698                let entity_key = CLValue::into_t::<Key>(entity_key_value)?;
3699                let target_uref = if let Some(StoredValue::AddressableEntity(entity)) =
3700                    self.context.read_gs(&entity_key)?
3701                {
3702                    entity.main_purse_add_only()
3703                } else {
3704                    let contract_hash = if let Some(entity_hash) = entity_key
3705                        .into_entity_hash_addr()
3706                        .map(AddressableEntityHash::new)
3707                    {
3708                        entity_hash
3709                    } else {
3710                        return Err(ExecError::UnexpectedKeyVariant(entity_key));
3711                    };
3712                    return Err(ExecError::InvalidEntity(contract_hash));
3713                };
3714
3715                if source.with_access_rights(AccessRights::ADD) == target_uref {
3716                    return Ok(Ok(TransferredTo::ExistingAccount));
3717                }
3718
3719                // Upsert ADD access to caller on target allowing deposit of motes; this will be
3720                // revoked after the transfer is completed if caller did not already have ADD access
3721                let granted_access = self.context.grant_access(target_uref);
3722
3723                // If an account exists, transfer the amount to its purse
3724                let transfer_result = self.transfer_to_existing_account(
3725                    Some(target),
3726                    source,
3727                    target_uref,
3728                    amount,
3729                    id,
3730                );
3731
3732                // Remove from caller temporarily granted ADD access on target.
3733                if let GrantedAccess::Granted {
3734                    uref_addr,
3735                    newly_granted_access_rights,
3736                } = granted_access
3737                {
3738                    self.context
3739                        .remove_access(uref_addr, newly_granted_access_rights)
3740                }
3741                transfer_result
3742            }
3743            Some(StoredValue::Account(account)) => {
3744                self.transfer_from_purse_to_account(source, &account, amount, id)
3745            }
3746            Some(_) => {
3747                // If some other value exists, return an error
3748                Err(ExecError::AccountNotFound(target_key))
3749            }
3750        }
3751    }
3752
3753    fn transfer_from_purse_to_account(
3754        &mut self,
3755        source: URef,
3756        target_account: &Account,
3757        amount: U512,
3758        id: Option<u64>,
3759    ) -> Result<TransferResult, ExecError> {
3760        // Attenuate the target main purse
3761        let target_uref = target_account.main_purse_add_only();
3762
3763        if source.with_access_rights(AccessRights::ADD) == target_uref {
3764            return Ok(Ok(TransferredTo::ExistingAccount));
3765        }
3766
3767        // Grant ADD access to caller on target allowing deposit of motes; this will be
3768        // revoked after the transfer is completed if caller did not already have ADD access
3769        let granted_access = self.context.grant_access(target_uref);
3770
3771        // If an account exists, transfer the amount to its purse
3772        let transfer_result = self.transfer_to_existing_account(
3773            Some(target_account.account_hash()),
3774            source,
3775            target_uref,
3776            amount,
3777            id,
3778        );
3779
3780        // Remove from caller temporarily granted ADD access on target.
3781        if let GrantedAccess::Granted {
3782            uref_addr,
3783            newly_granted_access_rights,
3784        } = granted_access
3785        {
3786            self.context
3787                .remove_access(uref_addr, newly_granted_access_rights)
3788        }
3789        transfer_result
3790    }
3791
3792    /// Transfers `amount` of motes from `source` purse to `target` purse.
3793    fn transfer_from_purse_to_purse(
3794        &mut self,
3795        source: URef,
3796        target: URef,
3797        amount: U512,
3798        id: Option<u64>,
3799    ) -> Result<Result<(), mint::Error>, ExecError> {
3800        self.context.validate_uref(&source)?;
3801        let mint_contract_key = self.get_mint_hash()?;
3802        match self.mint_transfer(mint_contract_key, None, source, target, amount, id)? {
3803            Ok(()) => Ok(Ok(())),
3804            Err(mint_error) => Ok(Err(mint_error)),
3805        }
3806    }
3807
3808    fn total_balance(&mut self, purse: URef) -> Result<U512, ExecError> {
3809        match self.context.total_balance(&purse) {
3810            Ok(motes) => Ok(motes.value()),
3811            Err(err) => Err(err),
3812        }
3813    }
3814
3815    fn available_balance(&mut self, purse: URef) -> Result<Option<U512>, ExecError> {
3816        match self.context.available_balance(&purse) {
3817            Ok(motes) => Ok(Some(motes.value())),
3818            Err(err) => Err(err),
3819        }
3820    }
3821
3822    fn get_balance_host_buffer(
3823        &mut self,
3824        purse_ptr: u32,
3825        purse_size: usize,
3826        output_size_ptr: u32,
3827    ) -> Result<Result<(), ApiError>, ExecError> {
3828        if !self.can_write_to_host_buffer() {
3829            // Exit early if the host buffer is already occupied
3830            return Ok(Err(ApiError::HostBufferFull));
3831        }
3832
3833        let purse: URef = {
3834            let bytes = self.bytes_from_mem(purse_ptr, purse_size)?;
3835            match bytesrepr::deserialize_from_slice(bytes) {
3836                Ok(purse) => purse,
3837                Err(error) => return Ok(Err(error.into())),
3838            }
3839        };
3840
3841        let balance = match self.available_balance(purse)? {
3842            Some(balance) => balance,
3843            None => return Ok(Err(ApiError::InvalidPurse)),
3844        };
3845
3846        let balance_cl_value = match CLValue::from_t(balance) {
3847            Ok(cl_value) => cl_value,
3848            Err(error) => return Ok(Err(error.into())),
3849        };
3850
3851        let balance_size = balance_cl_value.inner_bytes().len() as i32;
3852        if let Err(error) = self.write_host_buffer(balance_cl_value) {
3853            return Ok(Err(error));
3854        }
3855
3856        let balance_size_bytes = balance_size.to_le_bytes(); // Wasm is little-endian
3857        if let Err(error) = self
3858            .try_get_memory()?
3859            .set(output_size_ptr, &balance_size_bytes)
3860        {
3861            return Err(ExecError::Interpreter(error.into()));
3862        }
3863
3864        Ok(Ok(()))
3865    }
3866
3867    fn get_system_contract(
3868        &mut self,
3869        system_contract_index: u32,
3870        dest_ptr: u32,
3871        _dest_size: u32,
3872    ) -> Result<Result<(), ApiError>, Trap> {
3873        let hash: AddressableEntityHash = match SystemEntityType::try_from(system_contract_index) {
3874            Ok(SystemEntityType::Mint) => self.get_mint_hash()?,
3875            Ok(SystemEntityType::HandlePayment) => self.get_handle_payment_hash()?,
3876            Ok(SystemEntityType::StandardPayment) => self.get_standard_payment_hash()?,
3877            Ok(SystemEntityType::Auction) => self.get_auction_hash()?,
3878            Err(error) => return Ok(Err(error)),
3879        };
3880
3881        match self.try_get_memory()?.set(dest_ptr, hash.as_ref()) {
3882            Ok(_) => Ok(Ok(())),
3883            Err(error) => Err(ExecError::Interpreter(error.into()).into()),
3884        }
3885    }
3886
3887    /// If host_buffer set, clears the host_buffer and returns value, else None
3888    pub fn take_host_buffer(&mut self) -> Option<CLValue> {
3889        self.host_buffer.take()
3890    }
3891
3892    /// Checks if a write to host buffer can happen.
3893    ///
3894    /// This will check if the host buffer is empty.
3895    fn can_write_to_host_buffer(&self) -> bool {
3896        self.host_buffer.is_none()
3897    }
3898
3899    /// Overwrites data in host buffer only if it's in empty state
3900    fn write_host_buffer(&mut self, data: CLValue) -> Result<(), ApiError> {
3901        match self.host_buffer {
3902            Some(_) => return Err(ApiError::HostBufferFull),
3903            None => self.host_buffer = Some(data),
3904        }
3905        Ok(())
3906    }
3907
3908    fn read_host_buffer(
3909        &mut self,
3910        dest_ptr: u32,
3911        dest_size: usize,
3912        bytes_written_ptr: u32,
3913    ) -> Result<Result<(), ApiError>, ExecError> {
3914        let (_cl_type, serialized_value) = match self.take_host_buffer() {
3915            None => return Ok(Err(ApiError::HostBufferEmpty)),
3916            Some(cl_value) => cl_value.destructure(),
3917        };
3918
3919        if serialized_value.len() > u32::MAX as usize {
3920            return Ok(Err(ApiError::OutOfMemory));
3921        }
3922        if serialized_value.len() > dest_size {
3923            return Ok(Err(ApiError::BufferTooSmall));
3924        }
3925
3926        // Slice data, so if `dest_size` is larger than host_buffer size, it will take host_buffer
3927        // as whole.
3928        let sliced_buf = &serialized_value[..cmp::min(dest_size, serialized_value.len())];
3929        if let Err(error) = self.try_get_memory()?.set(dest_ptr, sliced_buf) {
3930            return Err(ExecError::Interpreter(error.into()));
3931        }
3932
3933        // Never panics because we check that `serialized_value.len()` fits in `u32`.
3934        let bytes_written: u32 = sliced_buf
3935            .len()
3936            .try_into()
3937            .expect("Size of buffer should fit within limit");
3938        let bytes_written_data = bytes_written.to_le_bytes();
3939
3940        if let Err(error) = self
3941            .try_get_memory()?
3942            .set(bytes_written_ptr, &bytes_written_data)
3943        {
3944            return Err(ExecError::Interpreter(error.into()));
3945        }
3946
3947        Ok(Ok(()))
3948    }
3949
3950    #[cfg(feature = "test-support")]
3951    fn print(&mut self, text_ptr: u32, text_size: u32) -> Result<(), Trap> {
3952        let text = self.string_from_mem(text_ptr, text_size)?;
3953        println!("{}", text); // this println! is intentional
3954        Ok(())
3955    }
3956
3957    fn get_named_arg_size(
3958        &mut self,
3959        name_ptr: u32,
3960        name_size: usize,
3961        size_ptr: u32,
3962    ) -> Result<Result<(), ApiError>, Trap> {
3963        let name_bytes = self.bytes_from_mem(name_ptr, name_size)?;
3964        let name = String::from_utf8_lossy(&name_bytes);
3965
3966        let arg_size: u32 = match self.context.args().get(&name) {
3967            Some(arg) if arg.inner_bytes().len() > u32::MAX as usize => {
3968                return Ok(Err(ApiError::OutOfMemory));
3969            }
3970            Some(arg) => {
3971                // SAFETY: Safe to unwrap as we asserted length above
3972                arg.inner_bytes()
3973                    .len()
3974                    .try_into()
3975                    .expect("Should fit within the range")
3976            }
3977            None => return Ok(Err(ApiError::MissingArgument)),
3978        };
3979
3980        let arg_size_bytes = arg_size.to_le_bytes(); // Wasm is little-endian
3981
3982        if let Err(e) = self.try_get_memory()?.set(size_ptr, &arg_size_bytes) {
3983            return Err(ExecError::Interpreter(e.into()).into());
3984        }
3985
3986        Ok(Ok(()))
3987    }
3988
3989    fn get_named_arg(
3990        &mut self,
3991        name_ptr: u32,
3992        name_size: usize,
3993        output_ptr: u32,
3994        output_size: usize,
3995    ) -> Result<Result<(), ApiError>, Trap> {
3996        let name_bytes = self.bytes_from_mem(name_ptr, name_size)?;
3997        let name = String::from_utf8_lossy(&name_bytes);
3998
3999        let arg = match self.context.args().get(&name) {
4000            Some(arg) => arg,
4001            None => return Ok(Err(ApiError::MissingArgument)),
4002        };
4003
4004        if arg.inner_bytes().len() > output_size {
4005            return Ok(Err(ApiError::OutOfMemory));
4006        }
4007
4008        if let Err(error) = self
4009            .try_get_memory()?
4010            .set(output_ptr, &arg.inner_bytes()[..output_size])
4011        {
4012            return Err(ExecError::Interpreter(error.into()).into());
4013        }
4014
4015        Ok(Ok(()))
4016    }
4017
4018    /// Enforce group access restrictions (if any) on attempts to call an `EntryPoint`.
4019    fn validate_entry_point_access(
4020        &self,
4021        package: &Package,
4022        name: &str,
4023        access: &EntryPointAccess,
4024    ) -> Result<(), ExecError> {
4025        match access {
4026            EntryPointAccess::Public => Ok(()),
4027            EntryPointAccess::Groups(group_names) => {
4028                if group_names.is_empty() {
4029                    // Exits early in a special case of empty list of groups regardless of the group
4030                    // checking logic below it.
4031                    return Err(ExecError::InvalidContext);
4032                }
4033
4034                let find_result = group_names.iter().find(|&group_name| {
4035                    package
4036                        .groups()
4037                        .get(group_name)
4038                        .and_then(|urefs| {
4039                            urefs
4040                                .iter()
4041                                .find(|&uref| self.context.validate_uref(uref).is_ok())
4042                        })
4043                        .is_some()
4044                });
4045
4046                if find_result.is_none() {
4047                    return Err(ExecError::InvalidContext);
4048                }
4049
4050                Ok(())
4051            }
4052            EntryPointAccess::Template => Err(ExecError::TemplateMethod(name.to_string())),
4053        }
4054    }
4055
4056    /// Remove a user group from access to a contract
4057    fn remove_contract_user_group(
4058        &mut self,
4059        package_key: PackageHash,
4060        label: Group,
4061    ) -> Result<Result<(), ApiError>, ExecError> {
4062        if self.context.engine_config().enable_entity {
4063            let mut package: Package = self.context.get_validated_package(package_key)?;
4064            let group_to_remove = Group::new(label);
4065
4066            // Ensure group exists in groups
4067            if !package.groups().contains(&group_to_remove) {
4068                return Ok(Err(addressable_entity::Error::GroupDoesNotExist.into()));
4069            }
4070
4071            // Remove group if it is not referenced by at least one entry_point in active versions.
4072            let versions = package.versions();
4073            for entity_hash in versions.contract_hashes() {
4074                let entry_points = {
4075                    self.context
4076                        .get_casper_vm_v1_entry_point(Key::AddressableEntity(*entity_hash))?
4077                };
4078                for entry_point in entry_points.take_entry_points() {
4079                    match entry_point.access() {
4080                        EntryPointAccess::Public | EntryPointAccess::Template => {
4081                            continue;
4082                        }
4083                        EntryPointAccess::Groups(groups) => {
4084                            if groups.contains(&group_to_remove) {
4085                                return Ok(Err(addressable_entity::Error::GroupInUse.into()));
4086                            }
4087                        }
4088                    }
4089                }
4090            }
4091
4092            if !package.remove_group(&group_to_remove) {
4093                return Ok(Err(addressable_entity::Error::GroupInUse.into()));
4094            }
4095
4096            // Write updated package to the global state
4097            self.context.metered_write_gs_unsafe(package_key, package)?;
4098        } else {
4099            let mut contract_package = self
4100                .context
4101                .get_validated_contract_package(package_key.value())?;
4102            let group_to_remove = Group::new(label);
4103
4104            // Ensure group exists in groups
4105            if !contract_package.groups().contains(&group_to_remove) {
4106                return Ok(Err(addressable_entity::Error::GroupDoesNotExist.into()));
4107            }
4108
4109            // Remove group if it is not referenced by at least one entry_point in active versions.
4110            for (_version, contract_hash) in contract_package.versions().iter() {
4111                let entry_points = {
4112                    self.context
4113                        .get_casper_vm_v1_entry_point(Key::contract_entity_key(
4114                            AddressableEntityHash::new(contract_hash.value()),
4115                        ))?
4116                };
4117                for entry_point in entry_points.take_entry_points() {
4118                    match entry_point.access() {
4119                        EntryPointAccess::Public | EntryPointAccess::Template => {
4120                            continue;
4121                        }
4122                        EntryPointAccess::Groups(groups) => {
4123                            if groups.contains(&group_to_remove) {
4124                                return Ok(Err(addressable_entity::Error::GroupInUse.into()));
4125                            }
4126                        }
4127                    }
4128                }
4129            }
4130
4131            if !contract_package.remove_group(&group_to_remove) {
4132                return Ok(Err(addressable_entity::Error::GroupInUse.into()));
4133            }
4134
4135            // Write updated package to the global state
4136            self.context.metered_write_gs_unsafe(
4137                ContractPackageHash::new(package_key.value()),
4138                contract_package,
4139            )?;
4140        }
4141        Ok(Ok(()))
4142    }
4143
4144    #[allow(clippy::too_many_arguments)]
4145    fn provision_contract_user_group_uref(
4146        &mut self,
4147        package_ptr: u32,
4148        package_size: u32,
4149        label_ptr: u32,
4150        label_size: u32,
4151        output_size_ptr: u32,
4152    ) -> Result<Result<(), ApiError>, ExecError> {
4153        let contract_package_hash = self.t_from_mem(package_ptr, package_size)?;
4154        let label: String = self.t_from_mem(label_ptr, label_size)?;
4155        let new_uref = if self.context.engine_config().enable_entity {
4156            let mut contract_package = self.context.get_validated_package(contract_package_hash)?;
4157            let groups = contract_package.groups_mut();
4158
4159            let group_label = Group::new(label);
4160
4161            // Ensure there are not too many urefs
4162            if groups.total_urefs() + 1 > addressable_entity::MAX_TOTAL_UREFS {
4163                return Ok(Err(addressable_entity::Error::MaxTotalURefsExceeded.into()));
4164            }
4165
4166            // Ensure given group exists and does not exceed limits
4167            let group = match groups.get_mut(&group_label) {
4168                Some(group) if group.len() + 1 > addressable_entity::MAX_GROUPS as usize => {
4169                    // Ensures there are not too many groups to fit in amount of new urefs
4170                    return Ok(Err(addressable_entity::Error::MaxTotalURefsExceeded.into()));
4171                }
4172                Some(group) => group,
4173                None => return Ok(Err(addressable_entity::Error::GroupDoesNotExist.into())),
4174            };
4175
4176            // Proceed with creating new URefs
4177            let new_uref = self.context.new_unit_uref()?;
4178            if !group.insert(new_uref) {
4179                return Ok(Err(addressable_entity::Error::URefAlreadyExists.into()));
4180            }
4181
4182            // Write updated package to the global state
4183            self.context
4184                .metered_write_gs_unsafe(contract_package_hash, contract_package)?;
4185            new_uref
4186        } else {
4187            let mut contract_package = self
4188                .context
4189                .get_validated_contract_package(contract_package_hash.value())?;
4190            let groups = contract_package.groups_mut();
4191
4192            let group_label = Group::new(label);
4193
4194            // Ensure there are not too many urefs
4195            if groups.total_urefs() + 1 > addressable_entity::MAX_TOTAL_UREFS {
4196                return Ok(Err(addressable_entity::Error::MaxTotalURefsExceeded.into()));
4197            }
4198
4199            // Ensure given group exists and does not exceed limits
4200            let group = match groups.get_mut(&group_label) {
4201                Some(group) if group.len() + 1 > addressable_entity::MAX_GROUPS as usize => {
4202                    // Ensures there are not too many groups to fit in amount of new urefs
4203                    return Ok(Err(addressable_entity::Error::MaxTotalURefsExceeded.into()));
4204                }
4205                Some(group) => group,
4206                None => return Ok(Err(addressable_entity::Error::GroupDoesNotExist.into())),
4207            };
4208
4209            // Proceed with creating new URefs
4210            let new_uref = self.context.new_unit_uref()?;
4211            if !group.insert(new_uref) {
4212                return Ok(Err(addressable_entity::Error::URefAlreadyExists.into()));
4213            }
4214
4215            // Write updated package to the global state
4216            self.context.metered_write_gs_unsafe(
4217                ContractPackageHash::new(contract_package_hash.value()),
4218                contract_package,
4219            )?;
4220            new_uref
4221        };
4222
4223        // check we can write to the host buffer
4224        if let Err(err) = self.check_host_buffer() {
4225            return Ok(Err(err));
4226        }
4227        // create CLValue for return value
4228        let new_uref_value = CLValue::from_t(new_uref)?;
4229        let value_size = new_uref_value.inner_bytes().len();
4230        // write return value to buffer
4231        if let Err(err) = self.write_host_buffer(new_uref_value) {
4232            return Ok(Err(err));
4233        }
4234        // Write return value size to output location
4235        let output_size_bytes = value_size.to_le_bytes(); // Wasm is little-endian
4236        if let Err(error) = self
4237            .try_get_memory()?
4238            .set(output_size_ptr, &output_size_bytes)
4239        {
4240            return Err(ExecError::Interpreter(error.into()));
4241        }
4242
4243        Ok(Ok(()))
4244    }
4245
4246    #[allow(clippy::too_many_arguments)]
4247    fn remove_contract_user_group_urefs(
4248        &mut self,
4249        package_ptr: u32,
4250        package_size: u32,
4251        label_ptr: u32,
4252        label_size: u32,
4253        urefs_ptr: u32,
4254        urefs_size: u32,
4255    ) -> Result<Result<(), ApiError>, ExecError> {
4256        let contract_package_hash: PackageHash = self.t_from_mem(package_ptr, package_size)?;
4257        let label: String = self.t_from_mem(label_ptr, label_size)?;
4258        let urefs: BTreeSet<URef> = self.t_from_mem(urefs_ptr, urefs_size)?;
4259
4260        if self.context.engine_config().enable_entity {
4261            let mut contract_package = self.context.get_validated_package(contract_package_hash)?;
4262
4263            let groups = contract_package.groups_mut();
4264            let group_label = Group::new(label);
4265
4266            let group = match groups.get_mut(&group_label) {
4267                Some(group) => group,
4268                None => return Ok(Err(addressable_entity::Error::GroupDoesNotExist.into())),
4269            };
4270
4271            if urefs.is_empty() {
4272                return Ok(Ok(()));
4273            }
4274
4275            for uref in urefs {
4276                if !group.remove(&uref) {
4277                    return Ok(Err(addressable_entity::Error::UnableToRemoveURef.into()));
4278                }
4279            }
4280            // Write updated package to the global state
4281            self.context
4282                .metered_write_gs_unsafe(contract_package_hash, contract_package)?;
4283        } else {
4284            let contract_package_hash = ContractPackageHash::new(contract_package_hash.value());
4285            let mut contract_package = self
4286                .context
4287                .get_validated_contract_package(contract_package_hash.value())?;
4288
4289            let groups = contract_package.groups_mut();
4290            let group_label = Group::new(label);
4291
4292            let group = match groups.get_mut(&group_label) {
4293                Some(group) => group,
4294                None => return Ok(Err(addressable_entity::Error::GroupDoesNotExist.into())),
4295            };
4296
4297            if urefs.is_empty() {
4298                return Ok(Ok(()));
4299            }
4300
4301            for uref in urefs {
4302                if !group.remove(&uref) {
4303                    return Ok(Err(addressable_entity::Error::UnableToRemoveURef.into()));
4304                }
4305            }
4306            // Write updated package to the global state
4307            self.context
4308                .metered_write_gs_unsafe(contract_package_hash, contract_package)?;
4309        }
4310
4311        Ok(Ok(()))
4312    }
4313
4314    /// Calculate gas cost for a host function
4315    fn charge_host_function_call<T>(
4316        &mut self,
4317        host_function: &HostFunction<T>,
4318        weights: T,
4319    ) -> Result<(), Trap>
4320    where
4321        T: AsRef<[HostFunctionCost]> + Copy,
4322    {
4323        let cost = host_function
4324            .calculate_gas_cost(weights)
4325            .ok_or(ExecError::GasLimit)?; // Overflowing gas calculation means gas limit was exceeded
4326        self.gas(cost)?;
4327        Ok(())
4328    }
4329
4330    /// Creates a dictionary
4331    fn new_dictionary(&mut self, output_size_ptr: u32) -> Result<Result<(), ApiError>, ExecError> {
4332        // check we can write to the host buffer
4333        if let Err(err) = self.check_host_buffer() {
4334            return Ok(Err(err));
4335        }
4336
4337        // Create new URef
4338        let new_uref = self.context.new_unit_uref()?;
4339
4340        // create CLValue for return value
4341        let new_uref_value = CLValue::from_t(new_uref)?;
4342        let value_size = new_uref_value.inner_bytes().len();
4343        // write return value to buffer
4344        if let Err(err) = self.write_host_buffer(new_uref_value) {
4345            return Ok(Err(err));
4346        }
4347        // Write return value size to output location
4348        let output_size_bytes = value_size.to_le_bytes(); // Wasm is little-endian
4349        if let Err(error) = self
4350            .try_get_memory()?
4351            .set(output_size_ptr, &output_size_bytes)
4352        {
4353            return Err(ExecError::Interpreter(error.into()));
4354        }
4355
4356        Ok(Ok(()))
4357    }
4358
4359    /// Reads the `value` under a `key` in a dictionary
4360    fn dictionary_get(
4361        &mut self,
4362        uref_ptr: u32,
4363        uref_size: u32,
4364        dictionary_item_key_bytes_ptr: u32,
4365        dictionary_item_key_bytes_size: u32,
4366        output_size_ptr: u32,
4367    ) -> Result<Result<(), ApiError>, Trap> {
4368        // check we can write to the host buffer
4369        if let Err(err) = self.check_host_buffer() {
4370            return Ok(Err(err));
4371        }
4372
4373        let uref: URef = self.t_from_mem(uref_ptr, uref_size)?;
4374        let dictionary_item_key = self.checked_memory_slice(
4375            dictionary_item_key_bytes_ptr as usize,
4376            dictionary_item_key_bytes_size as usize,
4377            |utf8_bytes| std::str::from_utf8(utf8_bytes).map(ToOwned::to_owned),
4378        )?;
4379
4380        let dictionary_item_key = if let Ok(item_key) = dictionary_item_key {
4381            item_key
4382        } else {
4383            return Ok(Err(ApiError::InvalidDictionaryItemKey));
4384        };
4385
4386        let cl_value = match self.context.dictionary_get(uref, &dictionary_item_key)? {
4387            Some(cl_value) => cl_value,
4388            None => return Ok(Err(ApiError::ValueNotFound)),
4389        };
4390
4391        let value_size: u32 = match cl_value.inner_bytes().len().try_into() {
4392            Ok(value) => value,
4393            Err(_) => return Ok(Err(ApiError::BufferTooSmall)),
4394        };
4395
4396        if let Err(error) = self.write_host_buffer(cl_value) {
4397            return Ok(Err(error));
4398        }
4399
4400        let value_bytes = value_size.to_le_bytes(); // Wasm is little-endian
4401        if let Err(error) = self.try_get_memory()?.set(output_size_ptr, &value_bytes) {
4402            return Err(ExecError::Interpreter(error.into()).into());
4403        }
4404
4405        Ok(Ok(()))
4406    }
4407
4408    /// Reads the `value` under a `Key::Dictionary`.
4409    fn dictionary_read(
4410        &mut self,
4411        key_ptr: u32,
4412        key_size: u32,
4413        output_size_ptr: u32,
4414    ) -> Result<Result<(), ApiError>, Trap> {
4415        if !self.can_write_to_host_buffer() {
4416            // Exit early if the host buffer is already occupied
4417            return Ok(Err(ApiError::HostBufferFull));
4418        }
4419
4420        let dictionary_key = self.key_from_mem(key_ptr, key_size)?;
4421        let cl_value = match self.context.dictionary_read(dictionary_key)? {
4422            Some(cl_value) => cl_value,
4423            None => return Ok(Err(ApiError::ValueNotFound)),
4424        };
4425
4426        let value_size: u32 = match cl_value.inner_bytes().len().try_into() {
4427            Ok(value) => value,
4428            Err(_) => return Ok(Err(ApiError::BufferTooSmall)),
4429        };
4430
4431        if let Err(error) = self.write_host_buffer(cl_value) {
4432            return Ok(Err(error));
4433        }
4434
4435        let value_bytes = value_size.to_le_bytes(); // Wasm is little-endian
4436        if let Err(error) = self.try_get_memory()?.set(output_size_ptr, &value_bytes) {
4437            return Err(ExecError::Interpreter(error.into()).into());
4438        }
4439
4440        Ok(Ok(()))
4441    }
4442
4443    /// Writes a `key`, `value` pair in a dictionary
4444    fn dictionary_put(
4445        &mut self,
4446        uref_ptr: u32,
4447        uref_size: u32,
4448        key_ptr: u32,
4449        key_size: u32,
4450        value_ptr: u32,
4451        value_size: u32,
4452    ) -> Result<Result<(), ApiError>, Trap> {
4453        let uref: URef = self.t_from_mem(uref_ptr, uref_size)?;
4454        let dictionary_item_key_bytes = {
4455            if (key_size as usize) > DICTIONARY_ITEM_KEY_MAX_LENGTH {
4456                return Ok(Err(ApiError::DictionaryItemKeyExceedsLength));
4457            }
4458            self.checked_memory_slice(key_ptr as usize, key_size as usize, |data| {
4459                std::str::from_utf8(data).map(ToOwned::to_owned)
4460            })?
4461        };
4462
4463        let dictionary_item_key = if let Ok(item_key) = dictionary_item_key_bytes {
4464            item_key
4465        } else {
4466            return Ok(Err(ApiError::InvalidDictionaryItemKey));
4467        };
4468        let cl_value = self.cl_value_from_mem(value_ptr, value_size)?;
4469        if let Err(e) = self
4470            .context
4471            .dictionary_put(uref, &dictionary_item_key, cl_value)
4472        {
4473            return Err(Trap::from(e));
4474        }
4475        Ok(Ok(()))
4476    }
4477
4478    /// Checks if immediate caller is a system contract or account.
4479    ///
4480    /// For cases where call stack is only the session code, then this method returns `true` if the
4481    /// caller is system, or `false` otherwise.
4482    fn is_system_immediate_caller(&self) -> Result<bool, ExecError> {
4483        let immediate_caller = match self.get_immediate_caller() {
4484            Some(call_stack_element) => call_stack_element,
4485            None => {
4486                // Immediate caller is assumed to exist at a time this check is run.
4487                return Ok(false);
4488            }
4489        };
4490
4491        match immediate_caller {
4492            Caller::Initiator { account_hash } => {
4493                // This case can happen during genesis where we're setting up purses for accounts.
4494                Ok(account_hash == &PublicKey::System.to_account_hash())
4495            }
4496            Caller::SmartContract { contract_hash, .. } => Ok(self
4497                .context
4498                .is_system_addressable_entity(&contract_hash.value())?),
4499            Caller::Entity { entity_addr, .. } => Ok(self
4500                .context
4501                .is_system_addressable_entity(&entity_addr.value())?),
4502        }
4503    }
4504
4505    fn load_authorization_keys(
4506        &mut self,
4507        len_ptr: u32,
4508        result_size_ptr: u32,
4509    ) -> Result<Result<(), ApiError>, Trap> {
4510        if !self.can_write_to_host_buffer() {
4511            // Exit early if the host buffer is already occupied
4512            return Ok(Err(ApiError::HostBufferFull));
4513        }
4514
4515        // A set of keys is converted into a vector so it can be written to a host buffer
4516        let authorization_keys = Vec::from_iter(self.context.authorization_keys().clone());
4517
4518        let total_keys: u32 = match authorization_keys.len().try_into() {
4519            Ok(value) => value,
4520            Err(_) => return Ok(Err(ApiError::OutOfMemory)),
4521        };
4522        let total_keys_bytes = total_keys.to_le_bytes();
4523        if let Err(error) = self.try_get_memory()?.set(len_ptr, &total_keys_bytes) {
4524            return Err(ExecError::Interpreter(error.into()).into());
4525        }
4526
4527        if total_keys == 0 {
4528            // No need to do anything else, we leave host buffer empty.
4529            return Ok(Ok(()));
4530        }
4531
4532        let authorization_keys = CLValue::from_t(authorization_keys).map_err(ExecError::CLValue)?;
4533
4534        let length: u32 = match authorization_keys.inner_bytes().len().try_into() {
4535            Ok(value) => value,
4536            Err(_) => return Ok(Err(ApiError::OutOfMemory)),
4537        };
4538        if let Err(error) = self.write_host_buffer(authorization_keys) {
4539            return Ok(Err(error));
4540        }
4541
4542        let length_bytes = length.to_le_bytes();
4543        if let Err(error) = self.try_get_memory()?.set(result_size_ptr, &length_bytes) {
4544            return Err(ExecError::Interpreter(error.into()).into());
4545        }
4546
4547        Ok(Ok(()))
4548    }
4549
4550    fn prune(&mut self, key: Key) {
4551        self.context.prune_gs_unsafe(key);
4552    }
4553
4554    pub(crate) fn migrate_contract_and_contract_package(
4555        &mut self,
4556        hash_addr: HashAddr,
4557    ) -> Result<AddressableEntity, ExecError> {
4558        let protocol_version = self.context.protocol_version();
4559        let contract = self.context.get_contract(ContractHash::new(hash_addr))?;
4560        let package_hash = contract.contract_package_hash();
4561        self.context
4562            .migrate_package(package_hash, protocol_version)?;
4563        let entity_hash = AddressableEntityHash::new(hash_addr);
4564        let key = Key::contract_entity_key(entity_hash);
4565        self.context.read_gs_typed(&key)
4566    }
4567
4568    fn add_message_topic(&mut self, topic_name: &str) -> Result<Result<(), ApiError>, ExecError> {
4569        let topic_hash = cryptography::blake2b(topic_name).into();
4570
4571        self.context
4572            .add_message_topic(topic_name, topic_hash)
4573            .map(|ret| ret.map_err(ApiError::from))
4574    }
4575
4576    fn emit_message(
4577        &mut self,
4578        topic_name: &str,
4579        message: MessagePayload,
4580    ) -> Result<Result<(), ApiError>, Trap> {
4581        let entity_addr = self.context.context_key_to_entity_addr()?;
4582
4583        let topic_name_hash = cryptography::blake2b(topic_name).into();
4584        let topic_key = Key::Message(MessageAddr::new_topic_addr(entity_addr, topic_name_hash));
4585
4586        // Check if the topic exists and get the summary.
4587        let Some(StoredValue::MessageTopic(prev_topic_summary)) =
4588            self.context.read_gs(&topic_key)?
4589        else {
4590            return Ok(Err(ApiError::MessageTopicNotRegistered));
4591        };
4592
4593        let current_blocktime = self.context.get_block_info().block_time();
4594        let topic_message_index = if prev_topic_summary.blocktime() != current_blocktime {
4595            for index in 1..prev_topic_summary.message_count() {
4596                self.context
4597                    .prune_gs_unsafe(Key::message(entity_addr, topic_name_hash, index));
4598            }
4599            0
4600        } else {
4601            prev_topic_summary.message_count()
4602        };
4603
4604        let block_message_index: u64 = match self
4605            .context
4606            .read_gs(&Key::BlockGlobal(BlockGlobalAddr::MessageCount))?
4607        {
4608            Some(stored_value) => {
4609                let (prev_block_time, prev_count): (BlockTime, u64) = CLValue::into_t(
4610                    CLValue::try_from(stored_value).map_err(ExecError::TypeMismatch)?,
4611                )
4612                .map_err(ExecError::CLValue)?;
4613                if prev_block_time == current_blocktime {
4614                    prev_count
4615                } else {
4616                    0
4617                }
4618            }
4619            None => 0,
4620        };
4621
4622        let Some(topic_message_count) = topic_message_index.checked_add(1) else {
4623            return Ok(Err(ApiError::MessageTopicFull));
4624        };
4625
4626        let Some(block_message_count) = block_message_index.checked_add(1) else {
4627            return Ok(Err(ApiError::MaxMessagesPerBlockExceeded));
4628        };
4629
4630        self.context.metered_emit_message(
4631            topic_key,
4632            current_blocktime,
4633            block_message_count,
4634            topic_message_count,
4635            Message::new(
4636                entity_addr,
4637                message,
4638                topic_name.to_string(),
4639                topic_name_hash,
4640                topic_message_index,
4641                block_message_index,
4642            ),
4643        )?;
4644        Ok(Ok(()))
4645    }
4646}
4647
4648#[cfg(feature = "test-support")]
4649fn dump_runtime_stack_info(instance: casper_wasmi::ModuleRef, max_stack_height: u32) {
4650    let globals = instance.globals();
4651    let Some(current_runtime_call_stack_height) = globals.last() else {
4652        return;
4653    };
4654
4655    if let RuntimeValue::I32(current_runtime_call_stack_height) =
4656        current_runtime_call_stack_height.get()
4657    {
4658        if current_runtime_call_stack_height > max_stack_height as i32 {
4659            eprintln!("runtime stack overflow, current={current_runtime_call_stack_height}, max={max_stack_height}");
4660        }
4661    };
4662}