concordium_smart_contract_engine/v1/
mod.rs

1//! Implementation of execution of V1 contracts.
2//!
3//! This contains only the execution of the Wasm parts and does not include the
4//! handling of invoked operations (e.g., calling another contract, sending
5//! transfers). That is handled by a separate scheduler component.
6//!
7//! The main entrypoints in this module are
8//! - [`invoke_init`] for invoking an init function to create a new instance
9//! - [`invoke_receive`] for invoking an entrypoint of an existing instance
10//! - [`resume_receive`] for resuming execution of an interrupted entrypoint
11//!
12//! These methods are intended to be used on [`Artifact`]'s obtained using
13//! [`instantiate_with_metering`](utils::instantiate_with_metering) using
14//! [`ConcordiumAllowedImports`] for handling imports.
15//!
16//! In addition to the above methods there are auxiliary helpers
17//! - [`invoke_init_from_artifact`] and [`invoke_receive_from_artifact`] which
18//!   first parse an [`Artifact`] and then run the corresponding `invoke_*`
19//!   function.
20//! - [`invoke_init_from_source`] and [`invoke_receive_from_source`] which first
21//!   parse and validate a Wasm module, then convert it to an [`Artifact`], and
22//!   then run it using the appropriate `invoke_*` function.
23//! - [`invoke_init_with_metering_from_source`] and
24//!   [`invoke_receive_with_metering_from_source`] which first parse and
25//!   validate the Wasm module, then inject cost metering instructions, and then
26//!   convert it to an [`Artifact`] and run it using the appropriate `invoke_*`
27//!   function.
28#[cfg(test)]
29mod crypto_primitives_tests;
30#[cfg(test)]
31mod tests;
32
33#[cfg(feature = "enable-ffi")]
34mod ffi;
35pub mod trie;
36mod types;
37
38use crate::{constants, v0, DebugInfo, ExecResult, InterpreterEnergy, OutOfEnergy};
39use anyhow::{bail, ensure};
40use concordium_contracts_common::{
41    AccountAddress, Address, Amount, ChainMetadata, ContractAddress, EntrypointName,
42    ModuleReference, OwnedEntrypointName, ReceiveName,
43};
44use concordium_wasm::{
45    artifact::{Artifact, CompiledFunction, CompiledFunctionBytes, RunnableCode},
46    machine::{self, ExecutionOutcome, NoInterrupt},
47    utils,
48    validate::ValidationConfig,
49    CostConfiguration,
50};
51use machine::Value;
52use sha3::Digest;
53use std::{borrow::Borrow, collections::BTreeMap, io::Write, sync::Arc};
54use trie::BackingStoreLoad;
55pub use types::*;
56
57#[derive(thiserror::Error, Debug)]
58/// An invalid return value was returned by the call.
59/// Allowed return values are either 0 for success, or negative for signalling
60/// errors.
61#[error("Unexpected return value from the invocation: {value:?}")]
62pub struct InvalidReturnCodeError<Debug> {
63    pub value:       Option<i32>,
64    pub debug_trace: Debug,
65}
66
67impl<R, Debug: DebugInfo, Ctx> From<InvalidReturnCodeError<Debug>>
68    for types::ReceiveResult<R, Debug, Ctx>
69{
70    fn from(value: InvalidReturnCodeError<Debug>) -> Self {
71        Self::Trap {
72            error:            anyhow::anyhow!("Invalid return code: {:?}", value.value),
73            remaining_energy: 0.into(), // We consume all energy in case of protocol violation.
74            trace:            value.debug_trace,
75        }
76    }
77}
78
79/// An alias for the return type of the `invoke_*` family of functions.
80pub type InvokeResult<A, Debug> = Result<A, InvalidReturnCodeError<Debug>>;
81
82/// Interrupt triggered by the smart contract to execute an instruction on the
83/// host, either an account transfer, a smart contract call or an upgrade
84/// instruction.
85#[derive(Debug)]
86pub enum Interrupt {
87    /// Transfer an amount of tokens to the **account**.
88    Transfer {
89        to:     AccountAddress,
90        amount: Amount,
91    },
92    /// Invoke an entrypoint on the given contract.
93    Call {
94        address:   ContractAddress,
95        parameter: ParameterVec,
96        name:      OwnedEntrypointName,
97        amount:    Amount,
98    },
99    /// Upgrade the smart contract code to the provided module.
100    Upgrade {
101        module_ref: ModuleReference,
102    },
103    /// Query the balance and staked balance of an account.
104    QueryAccountBalance {
105        address: AccountAddress,
106    },
107    /// Query the balance of a contract.
108    QueryContractBalance {
109        address: ContractAddress,
110    },
111    /// Query the CCD/EUR and EUR/NRG exchange rates.
112    QueryExchangeRates,
113    /// Check signatures on the provided data.
114    CheckAccountSignature {
115        address: AccountAddress,
116        payload: Vec<u8>,
117    },
118    /// Query account keys.
119    QueryAccountKeys {
120        address: AccountAddress,
121    },
122    /// Query the module reference of a contract.
123    QueryContractModuleReference {
124        address: ContractAddress,
125    },
126    /// Query the constructor name of a contract.
127    QueryContractName {
128        address: ContractAddress,
129    },
130}
131
132impl Interrupt {
133    /// Whether the logs should be cleared for handling this interrupt or not.
134    /// This is somewhat hacky, but it is needed because there are two kinds of
135    /// interrupts. The queries which do not affect the state, and the state
136    /// affecting ones. The latter ones produce "Interrupt" events in the
137    /// scheduler, which record the log trace up to that point in execution.
138    /// The query ones do not.
139    ///
140    /// This is admittedly rather hairy and could be done better. But that is
141    /// the semantics we have now, and changing it is a bigger reorganization.
142    pub(crate) fn should_clear_logs(&self) -> bool {
143        match self {
144            Interrupt::Transfer {
145                ..
146            } => true,
147            Interrupt::Call {
148                ..
149            } => true,
150            Interrupt::Upgrade {
151                ..
152            } => true,
153            Interrupt::QueryAccountBalance {
154                ..
155            } => false,
156            Interrupt::QueryContractBalance {
157                ..
158            } => false,
159            Interrupt::QueryExchangeRates => false,
160            Interrupt::CheckAccountSignature {
161                ..
162            } => false,
163            Interrupt::QueryAccountKeys {
164                ..
165            } => false,
166            Interrupt::QueryContractModuleReference {
167                ..
168            } => false,
169            Interrupt::QueryContractName {
170                ..
171            } => false,
172        }
173    }
174}
175
176impl Interrupt {
177    pub fn to_bytes(&self, out: &mut Vec<u8>) -> anyhow::Result<()> {
178        match self {
179            Interrupt::Transfer {
180                to,
181                amount,
182            } => {
183                out.push(0u8);
184                out.write_all(to.as_ref())?;
185                out.write_all(&amount.micro_ccd.to_be_bytes())?;
186                Ok(())
187            }
188            Interrupt::Call {
189                address,
190                parameter,
191                name,
192                amount,
193            } => {
194                out.push(1u8);
195                out.write_all(&address.index.to_be_bytes())?;
196                out.write_all(&address.subindex.to_be_bytes())?;
197                out.write_all(&(parameter.len() as u16).to_be_bytes())?;
198                out.write_all(parameter)?;
199                let name_str: &str = name.as_entrypoint_name().into();
200                out.write_all(&(name_str.as_bytes().len() as u16).to_be_bytes())?;
201                out.write_all(name_str.as_bytes())?;
202                out.write_all(&amount.micro_ccd.to_be_bytes())?;
203                Ok(())
204            }
205            Interrupt::Upgrade {
206                module_ref,
207            } => {
208                out.push(2u8);
209                out.write_all(module_ref.as_ref())?;
210                Ok(())
211            }
212            Interrupt::QueryAccountBalance {
213                address,
214            } => {
215                out.push(3u8);
216                out.write_all(address.as_ref())?;
217                Ok(())
218            }
219            Interrupt::QueryContractBalance {
220                address,
221            } => {
222                out.push(4u8);
223                out.write_all(&address.index.to_be_bytes())?;
224                out.write_all(&address.subindex.to_be_bytes())?;
225                Ok(())
226            }
227            Interrupt::QueryExchangeRates => {
228                out.push(5u8);
229                Ok(())
230            }
231            Interrupt::CheckAccountSignature {
232                address,
233                payload,
234            } => {
235                out.push(6u8);
236                out.write_all(address.as_ref())?;
237                out.write_all(&(payload.len() as u64).to_be_bytes())?;
238                out.write_all(payload)?;
239                Ok(())
240            }
241            Interrupt::QueryAccountKeys {
242                address,
243            } => {
244                out.push(7u8);
245                out.write_all(address.as_ref())?;
246                Ok(())
247            }
248            Interrupt::QueryContractModuleReference {
249                address,
250            } => {
251                out.push(8u8);
252                out.write_all(&address.index.to_be_bytes())?;
253                out.write_all(&address.subindex.to_be_bytes())?;
254                Ok(())
255            }
256            Interrupt::QueryContractName {
257                address,
258            } => {
259                out.push(9u8);
260                out.write_all(&address.index.to_be_bytes())?;
261                out.write_all(&address.subindex.to_be_bytes())?;
262                Ok(())
263            }
264        }
265    }
266}
267
268#[derive(Debug)]
269/// A host implementation that provides access to host information needed for
270/// execution of contract initialization functions. The "host" in this context
271/// refers to the Wasm concept of a host.
272/// This keeps track of the current state and logs, gives access to the context,
273/// and makes sure that execution stays within resource bounds dictated by
274/// allocated energy.
275pub(crate) struct InitHost<'a, BackingStore, ParamType, Ctx, A: DebugInfo> {
276    /// Remaining energy for execution.
277    pub energy:                   InterpreterEnergy,
278    /// Remaining amount of activation frames.
279    /// In other words, how many more functions can we call in a nested way.
280    pub activation_frames:        u32,
281    /// Logs produced during execution.
282    pub logs:                     v0::Logs,
283    /// The contract's state.
284    pub state:                    InstanceState<'a, BackingStore>,
285    /// The response from the call.
286    pub return_value:             ReturnValue,
287    /// The parameter to the init method.
288    pub parameter:                ParamType,
289    /// The init context for this invocation.
290    pub init_ctx:                 Ctx,
291    /// Whether there is a limit on the number of logs and sizes of return
292    /// values. Limit removed in P5.
293    limit_logs_and_return_values: bool,
294    pub trace:                    A,
295}
296
297impl<'a, 'b, BackingStore, Ctx2, Ctx1: Into<Ctx2>, A: DebugInfo>
298    From<InitHost<'b, BackingStore, ParameterRef<'a>, Ctx1, A>>
299    for InitHost<'b, BackingStore, ParameterVec, Ctx2, A>
300{
301    fn from(host: InitHost<'b, BackingStore, ParameterRef<'a>, Ctx1, A>) -> Self {
302        Self {
303            energy: host.energy,
304            activation_frames: host.activation_frames,
305            logs: host.logs,
306            state: host.state,
307            return_value: host.return_value,
308            parameter: host.parameter.into(),
309            init_ctx: host.init_ctx.into(),
310            limit_logs_and_return_values: host.limit_logs_and_return_values,
311            trace: host.trace,
312        }
313    }
314}
315
316#[derive(Copy, Clone, PartialOrd, Ord, Eq, PartialEq, Debug)]
317/// Host functions supported by V1 contracts.
318pub enum HostFunctionV1 {
319    /// Functions allowed both in `init` and `receive` functions.
320    Common(CommonFunc),
321    /// Functions allowed only in `init` methods.
322    Init(InitOnlyFunc),
323    /// Functions allowed only in `receive` methods.
324    Receive(ReceiveOnlyFunc),
325}
326
327/// The [`Display`](std::fmt::Display) implementation renders the function in
328/// the same way that it is expected to be named in the imports.
329impl std::fmt::Display for HostFunctionV1 {
330    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
331        match self {
332            HostFunctionV1::Common(c) => c.fmt(f),
333            HostFunctionV1::Init(io) => io.fmt(f),
334            HostFunctionV1::Receive(ro) => ro.fmt(f),
335        }
336    }
337}
338
339#[derive(Debug, Copy, Clone)]
340/// A record of a host call in the [`DebugTracker`].
341pub struct HostCall {
342    /// The host function that was called.
343    pub host_function: HostFunctionV1,
344    /// The amount of energy consumed by the call.
345    pub energy_used:   InterpreterEnergy,
346}
347
348#[derive(Default, Debug)]
349/// A type that implements [`DebugInfo`] and can be used for collecting
350/// execution information during execution.
351pub struct DebugTracker {
352    /// The amount of interpreter energy used by pure Wasm instruction
353    /// execution.
354    pub operation:       InterpreterEnergy,
355    /// The amount of interpreter energy charged due to additional memory
356    /// allocation in Wasm linear memory.
357    pub memory_alloc:    InterpreterEnergy,
358    /// The list of host calls in the order they appeared. The first component
359    /// is the event index which is shared between the host trace calls and
360    /// the `emitted_events` field below so that it is possible to reconstruct
361    /// one global order of events.
362    pub host_call_trace: Vec<(usize, HostCall)>,
363    /// Events emitted by calls to `debug_print` host function. The first
364    /// component is the event index shared with the `host_call_trace` value.
365    pub emitted_events:  Vec<(usize, EmittedDebugStatement)>,
366    /// Internal tracker to assign event indices.
367    next_index:          usize,
368}
369
370/// The [`Display`](std::fmt::Display) implementation renders all public fields
371/// of the type in **multiple lines**. The host calls and emitted events are
372/// interleaved so that they appear in the order that they occurred.
373impl std::fmt::Display for DebugTracker {
374    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
375        let DebugTracker {
376            operation,
377            memory_alloc,
378            host_call_trace,
379            emitted_events,
380            next_index: _,
381        } = self;
382        writeln!(f, "Wasm instruction cost: {operation}")?;
383        writeln!(f, "Memory alocation cost: {memory_alloc}")?;
384        let mut iter1 = host_call_trace.iter().peekable();
385        let mut iter2 = emitted_events.iter().peekable();
386        while let (Some((i1, call)), Some((i2, event))) = (iter1.peek(), iter2.peek()) {
387            if i1 < i2 {
388                iter1.next();
389                writeln!(f, "{} used {} interpreter energy", call.host_function, call.energy_used)?;
390            } else {
391                iter2.next();
392                writeln!(f, "{event}")?;
393            }
394        }
395        for (
396            _,
397            HostCall {
398                host_function,
399                energy_used,
400            },
401        ) in iter1
402        {
403            writeln!(f, "{host_function} used {energy_used} interpreter energy")?;
404        }
405        for (_, event) in iter2 {
406            writeln!(f, "{event}")?;
407        }
408        Ok(())
409    }
410}
411
412impl DebugTracker {
413    /// Summarize all the host calls, grouping them by the host function. The
414    /// value at each host function is the pair of the number of times the
415    /// host function was called, and the sum of interpreter energy those
416    /// calls consumed.
417    pub fn host_call_summary(&self) -> BTreeMap<HostFunctionV1, (usize, InterpreterEnergy)> {
418        let mut out = BTreeMap::new();
419        for (
420            _,
421            HostCall {
422                host_function,
423                energy_used,
424            },
425        ) in self.host_call_trace.iter()
426        {
427            let summary = out.entry(*host_function).or_insert((0, InterpreterEnergy {
428                energy: 0,
429            }));
430            summary.0 += 1;
431            summary.1.energy += energy_used.energy;
432        }
433        out
434    }
435}
436
437impl crate::DebugInfo for DebugTracker {
438    const ENABLE_DEBUG: bool = true;
439
440    fn empty_trace() -> Self { Self::default() }
441
442    fn trace_host_call(&mut self, f: self::ImportFunc, energy_used: InterpreterEnergy) {
443        let next_idx = self.next_index;
444        match f {
445            ImportFunc::ChargeMemoryAlloc => self.memory_alloc.add(energy_used),
446            ImportFunc::Common(c) => {
447                self.next_index += 1;
448                self.host_call_trace.push((next_idx, HostCall {
449                    host_function: HostFunctionV1::Common(c),
450                    energy_used,
451                }));
452            }
453            ImportFunc::InitOnly(io) => {
454                self.next_index += 1;
455                self.host_call_trace.push((next_idx, HostCall {
456                    host_function: HostFunctionV1::Init(io),
457                    energy_used,
458                }));
459            }
460            ImportFunc::ReceiveOnly(ro) => {
461                self.next_index += 1;
462                self.host_call_trace.push((next_idx, HostCall {
463                    host_function: HostFunctionV1::Receive(ro),
464                    energy_used,
465                }));
466            }
467        }
468    }
469
470    fn emit_debug_event(&mut self, event: EmittedDebugStatement) {
471        let next_idx = self.next_index;
472        self.next_index += 1;
473        self.emitted_events.push((next_idx, event));
474    }
475}
476
477#[derive(Debug)]
478/// A host implementation that provides access to host information needed for
479/// execution of contract receive methods. The "host" in this context
480/// refers to the Wasm concept of a host.
481/// This keeps track of the current state and logs, gives access to the context,
482/// and makes sure that execution stays within resource bounds dictated by
483/// allocated energy.
484#[doc(hidden)] // Needed in benchmarks, but generally should not be used by
485               // users of the library.
486pub struct ReceiveHost<'a, BackingStore, ParamType, Ctx, A: DebugInfo> {
487    pub energy:    InterpreterEnergy,
488    pub stateless: StateLessReceiveHost<ParamType, Ctx>,
489    pub state:     InstanceState<'a, BackingStore>,
490    pub trace:     A,
491}
492
493#[derive(Debug)]
494/// Part of the receive host that is stored to handle the interrupt.
495/// This part is not changed during the handling of the interrupt, however
496/// before execution resumes, after returning from handling of the interrupt,
497/// the logs and parameters are set appropriately.
498#[doc(hidden)] // Needed in benchmarks, but generally should not be used by
499               // users of the library.
500pub struct StateLessReceiveHost<ParamType, Ctx> {
501    /// Remaining amount of activation frames.
502    /// In other words, how many more functions can we call in a nested way.
503    pub activation_frames: u32,
504    /// Logs produced during execution.
505    pub logs:              v0::Logs,
506    /// Return value from execution.
507    pub return_value:      ReturnValue,
508    /// The parameter to the receive method, as well as any responses from
509    /// calls to other contracts during execution.
510    pub parameters:        Vec<ParamType>,
511    /// The receive context for this call.
512    pub receive_ctx:       Ctx,
513    /// Configuration determining which options are allowed at runtime.
514    pub params:            ReceiveParams,
515}
516
517impl<'a, Ctx2, Ctx1: Into<Ctx2>> From<StateLessReceiveHost<ParameterRef<'a>, Ctx1>>
518    for StateLessReceiveHost<ParameterVec, Ctx2>
519{
520    fn from(host: StateLessReceiveHost<ParameterRef<'a>, Ctx1>) -> Self {
521        Self {
522            activation_frames: host.activation_frames,
523            logs:              host.logs,
524            return_value:      host.return_value,
525            parameters:        host.parameters.into_iter().map(|x| x.to_vec()).collect(),
526            receive_ctx:       host.receive_ctx.into(),
527            params:            host.params,
528        }
529    }
530}
531
532/// An event emitted by the `debug_print` host function in debug mode.
533#[derive(Debug)]
534pub struct EmittedDebugStatement {
535    /// File in which the debug macro was used.
536    pub filename:         String,
537    /// The line inside the file.
538    pub line:             u32,
539    /// An the column.
540    pub column:           u32,
541    /// The message that was emitted.
542    pub msg:              String,
543    /// Remaining **interpreter energy** energy left for execution.
544    pub remaining_energy: InterpreterEnergy,
545}
546
547impl std::fmt::Display for EmittedDebugStatement {
548    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
549        write!(
550            f,
551            "{}:{}:{}:@{}:{}",
552            self.filename, self.line, self.column, self.remaining_energy, self.msg
553        )
554    }
555}
556
557pub(crate) mod host {
558    //! v1 host function implementations. Functions in this inner module are
559    //! mostly just wrappers. They parse relevant arguments from the
560    //! machine, e.g., read values from the stack or memory, and push values to
561    //! the stack and update the memory, and account for some energy use.
562    //! The main logic (e.g., updating state) is usually handed over to the
563    //! relevant component (e.g., the state), except when the logic is very
564    //! simple. For this reason the functions generally don't have much
565    //! documentation on their own, and one should look at underlying
566    //! function to determine detailed behaviour.
567    //!
568    //! These functions are safety-critical, and must withstand malicious use.
569    //! Thus they are written in a very defensive way to make sure no out of
570    //! bounds accesses occur.
571    use std::convert::TryFrom;
572
573    use super::*;
574    use concordium_contracts_common::{
575        Cursor, EntrypointName, Get, ParseError, ParseResult, ACCOUNT_ADDRESS_SIZE,
576    };
577
578    const TRANSFER_TAG: u32 = 0;
579    const CALL_TAG: u32 = 1;
580    const QUERY_ACCOUNT_BALANCE_TAG: u32 = 2;
581    const QUERY_CONTRACT_BALANCE_TAG: u32 = 3;
582    const QUERY_EXCHANGE_RATE_TAG: u32 = 4;
583    const CHECK_ACCOUNT_SIGNATURE_TAG: u32 = 5;
584    const QUERY_ACCOUNT_KEYS_TAG: u32 = 6;
585    const QUERY_CONTRACT_MODULE_REFERENCE_TAG: u32 = 7;
586    const QUERY_CONTRACT_NAME_TAG: u32 = 8;
587
588    /// Parse the call arguments. This is using the serialization as defined in
589    /// the smart contracts code since the arguments will be written by a
590    /// smart contract. Returns `Ok(Err(OutOfEnergy))` if there is
591    /// insufficient energy.
592    fn parse_call_args(
593        energy: &mut InterpreterEnergy,
594        cursor: &mut Cursor<&[u8]>,
595        max_parameter_size: usize,
596    ) -> ParseResult<Result<Interrupt, OutOfEnergy>> {
597        let address = cursor.get()?;
598        let parameter_len: u16 = cursor.get()?;
599        if usize::from(parameter_len) > max_parameter_size {
600            return Err(ParseError {});
601        }
602        if energy.tick_energy(constants::copy_parameter_cost(parameter_len.into())).is_err() {
603            return Ok(Err(OutOfEnergy));
604        }
605        let start = cursor.offset;
606        let end = cursor.offset + parameter_len as usize;
607        if end > cursor.data.len() {
608            return Err(ParseError {});
609        }
610        let parameter: ParameterVec = cursor.data[start..end].to_vec();
611        cursor.offset = end;
612        let name = cursor.get()?;
613        let amount = cursor.get()?;
614        Ok(Ok(Interrupt::Call {
615            address,
616            parameter,
617            name,
618            amount,
619        }))
620    }
621
622    /// Write to the return value.
623    fn write_return_value_helper(
624        rv: &mut ReturnValue,
625        energy: &mut InterpreterEnergy,
626        offset: u32,
627        bytes: &[u8],
628        limit_return_value_size: bool,
629    ) -> ExecResult<u32> {
630        let length = bytes.len();
631        let offset = offset as usize;
632        ensure!(offset <= rv.len(), "Cannot write past the offset.");
633        let end = offset
634            .checked_add(length)
635            .ok_or_else(|| anyhow::anyhow!("Writing past the end of memory."))?;
636        let end = if limit_return_value_size {
637            std::cmp::min(end, constants::MAX_CONTRACT_STATE as usize)
638        } else {
639            end
640        };
641        if rv.len() < end {
642            energy.tick_energy(constants::additional_output_size_cost(
643                end as u64 - rv.len() as u64,
644            ))?;
645            rv.resize(end, 0u8);
646        }
647        let written = (&mut rv[offset..end]).write(bytes)?;
648        Ok(written as u32)
649    }
650
651    #[cfg_attr(not(feature = "fuzz-coverage"), inline)]
652    pub(crate) fn write_return_value(
653        memory: &mut [u8],
654        stack: &mut machine::RuntimeStack,
655        energy: &mut InterpreterEnergy,
656        rv: &mut ReturnValue,
657        limit_return_value_size: bool,
658    ) -> machine::RunResult<()> {
659        let offset = unsafe { stack.pop_u32() };
660        let length = unsafe { stack.pop_u32() };
661        let start = unsafe { stack.pop_u32() } as usize;
662        // charge energy linearly in the amount of data written.
663        energy.tick_energy(constants::write_output_cost(length))?;
664        let end = start + length as usize; // this cannot overflow on 64-bit machines.
665        ensure!(end <= memory.len(), "Illegal memory access.");
666        let res = write_return_value_helper(
667            rv,
668            energy,
669            offset,
670            &memory[start..end],
671            limit_return_value_size,
672        )?;
673        stack.push_value(res);
674        Ok(())
675    }
676
677    #[cfg_attr(not(feature = "fuzz-coverage"), inline)]
678    /// Handle the `invoke` host function.
679    pub(crate) fn invoke(
680        params: ReceiveParams,
681        memory: &mut [u8],
682        stack: &mut machine::RuntimeStack,
683        energy: &mut InterpreterEnergy,
684    ) -> machine::RunResult<Option<Interrupt>> {
685        energy.tick_energy(constants::INVOKE_BASE_COST)?;
686        let length_u32 = unsafe { stack.pop_u32() }; // length of the instruction payload in memory
687        let length = length_u32 as usize;
688        let start = unsafe { stack.pop_u32() } as usize; // start of the instruction payload in memory
689        let tag = unsafe { stack.pop_u32() }; // tag of the instruction
690        match tag {
691            TRANSFER_TAG => {
692                ensure!(
693                    length == ACCOUNT_ADDRESS_SIZE + 8,
694                    "Transfers must have exactly 40 bytes of payload, but was {}",
695                    length
696                );
697                // Overflow is not possible in the next line on 64-bit machines.
698                ensure!(start + length <= memory.len(), "Illegal memory access.");
699                let mut addr_bytes = [0u8; ACCOUNT_ADDRESS_SIZE];
700                addr_bytes.copy_from_slice(&memory[start..start + ACCOUNT_ADDRESS_SIZE]);
701                let to = AccountAddress(addr_bytes);
702                let mut amount_bytes = [0; 8];
703                amount_bytes.copy_from_slice(
704                    &memory[start + ACCOUNT_ADDRESS_SIZE..start + ACCOUNT_ADDRESS_SIZE + 8],
705                );
706                let amount = Amount {
707                    micro_ccd: u64::from_le_bytes(amount_bytes),
708                };
709                Ok(Interrupt::Transfer {
710                    to,
711                    amount,
712                }
713                .into())
714            }
715            CALL_TAG => {
716                ensure!(start + length <= memory.len(), "Illegal memory access.");
717                let mut cursor = Cursor::new(&memory[start..start + length]);
718                match parse_call_args(energy, &mut cursor, params.max_parameter_size) {
719                    Ok(Ok(i)) => Ok(Some(i)),
720                    Ok(Err(OutOfEnergy)) => bail!(OutOfEnergy),
721                    Err(e) => bail!("Illegal call, cannot parse arguments: {:?}", e),
722                }
723            }
724            QUERY_ACCOUNT_BALANCE_TAG if params.support_queries => {
725                ensure!(
726                    length == ACCOUNT_ADDRESS_SIZE,
727                    "Account balance queries must have exactly 32 bytes of payload, but was {}",
728                    length
729                );
730                // Overflow is not possible in the next line on 64-bit machines.
731                ensure!(start + length <= memory.len(), "Illegal memory access.");
732                let mut addr_bytes = [0u8; ACCOUNT_ADDRESS_SIZE];
733                addr_bytes.copy_from_slice(&memory[start..start + ACCOUNT_ADDRESS_SIZE]);
734                let address = AccountAddress(addr_bytes);
735                Ok(Interrupt::QueryAccountBalance {
736                    address,
737                }
738                .into())
739            }
740            QUERY_CONTRACT_BALANCE_TAG if params.support_queries => {
741                ensure!(
742                    length == 8 + 8,
743                    "Contract balance queries must have exactly 16 bytes of payload, but was {}",
744                    length
745                );
746                // Overflow is not possible in the next line on 64-bit machines.
747                ensure!(start + length <= memory.len(), "Illegal memory access.");
748                let mut buf = [0u8; 8];
749                buf.copy_from_slice(&memory[start..start + 8]);
750                let index = u64::from_le_bytes(buf);
751                buf.copy_from_slice(&memory[start + 8..start + 16]);
752                let subindex = u64::from_le_bytes(buf);
753                let address = ContractAddress {
754                    index,
755                    subindex,
756                };
757                Ok(Interrupt::QueryContractBalance {
758                    address,
759                }
760                .into())
761            }
762            QUERY_EXCHANGE_RATE_TAG if params.support_queries => {
763                ensure!(
764                    length == 0,
765                    "Exchange rate query must have no payload, but was {}",
766                    length
767                );
768                Ok(Interrupt::QueryExchangeRates.into())
769            }
770            CHECK_ACCOUNT_SIGNATURE_TAG if params.support_account_signature_checks => {
771                ensure!(
772                    length >= ACCOUNT_ADDRESS_SIZE,
773                    "Account signature check queries must have at least the 32 bytes for an \
774                     account address, but was {}",
775                    length
776                );
777                // Overflow is not possible in the next line on 64-bit machines.
778                ensure!(start + length <= memory.len(), "Illegal memory access.");
779                if energy.tick_energy(constants::copy_to_host_cost(length_u32)).is_err() {
780                    bail!(OutOfEnergy);
781                }
782                let mut addr_bytes = [0u8; ACCOUNT_ADDRESS_SIZE];
783                addr_bytes.copy_from_slice(&memory[start..start + ACCOUNT_ADDRESS_SIZE]);
784                let address = AccountAddress(addr_bytes);
785                let payload = memory[start + ACCOUNT_ADDRESS_SIZE..start + length].to_vec();
786                Ok(Interrupt::CheckAccountSignature {
787                    address,
788                    payload,
789                }
790                .into())
791            }
792            QUERY_ACCOUNT_KEYS_TAG if params.support_account_signature_checks => {
793                ensure!(
794                    length == ACCOUNT_ADDRESS_SIZE,
795                    "Account keys queries must have exactly 32 bytes of payload, but was {}",
796                    length
797                );
798                // Overflow is not possible in the next line on 64-bit machines.
799                ensure!(start + length <= memory.len(), "Illegal memory access.");
800                let mut addr_bytes = [0u8; ACCOUNT_ADDRESS_SIZE];
801                addr_bytes.copy_from_slice(&memory[start..start + ACCOUNT_ADDRESS_SIZE]);
802                let address = AccountAddress(addr_bytes);
803                Ok(Interrupt::QueryAccountKeys {
804                    address,
805                }
806                .into())
807            }
808            QUERY_CONTRACT_MODULE_REFERENCE_TAG if params.support_contract_inspection_queries => {
809                ensure!(
810                    length == 8 + 8,
811                    "Contract module reference queries must have exactly 16 bytes of payload, but \
812                     was {}",
813                    length
814                );
815                // Overflow is not possible in the next line on 64-bit machines.
816                ensure!(start + length <= memory.len(), "Illegal memory access.");
817                let mut buf = [0u8; 8];
818                buf.copy_from_slice(&memory[start..start + 8]);
819                let index = u64::from_le_bytes(buf);
820                buf.copy_from_slice(&memory[start + 8..start + 16]);
821                let subindex = u64::from_le_bytes(buf);
822                let address = ContractAddress {
823                    index,
824                    subindex,
825                };
826                Ok(Interrupt::QueryContractModuleReference {
827                    address,
828                }
829                .into())
830            }
831            QUERY_CONTRACT_NAME_TAG if params.support_contract_inspection_queries => {
832                ensure!(
833                    length == 8 + 8,
834                    "Contract name queries must have exactly 16 bytes of payload, but was {}",
835                    length
836                );
837                // Overflow is not possible in the next line on 64-bit machines.
838                ensure!(start + length <= memory.len(), "Illegal memory access.");
839                let mut buf = [0u8; 8];
840                buf.copy_from_slice(&memory[start..start + 8]);
841                let index = u64::from_le_bytes(buf);
842                buf.copy_from_slice(&memory[start + 8..start + 16]);
843                let subindex = u64::from_le_bytes(buf);
844                let address = ContractAddress {
845                    index,
846                    subindex,
847                };
848                Ok(Interrupt::QueryContractName {
849                    address,
850                }
851                .into())
852            }
853            c => bail!("Illegal instruction code {}.", c),
854        }
855    }
856
857    #[cfg_attr(not(feature = "fuzz-coverage"), inline)]
858    /// Get the parameter size. This differs from the v0 version in that it
859    /// expects an argument on the stack to indicate which parameter to use.
860    pub(crate) fn get_parameter_size(
861        stack: &mut machine::RuntimeStack,
862        parameters: &[impl AsRef<[u8]>],
863    ) -> machine::RunResult<()> {
864        // the cost of this function is adequately reflected by the base cost of a
865        // function call so we do not charge extra.
866        let param_num = unsafe { stack.pop_u32() } as usize;
867        if let Some(param) = parameters.get(param_num) {
868            stack.push_value(param.as_ref().len() as u32);
869        } else {
870            stack.push_value(-1i32);
871        }
872        Ok(())
873    }
874
875    #[cfg_attr(not(feature = "fuzz-coverage"), inline)]
876    /// Get the parameter section. This differs from the v0 version in that it
877    /// expects an argument on the stack to indicate which parameter to use.
878    pub(crate) fn get_parameter_section(
879        memory: &mut [u8],
880        stack: &mut machine::RuntimeStack,
881        energy: &mut InterpreterEnergy,
882        parameters: &[impl AsRef<[u8]>],
883    ) -> machine::RunResult<()> {
884        let offset = unsafe { stack.pop_u32() } as usize;
885        let length = unsafe { stack.pop_u32() };
886        let start = unsafe { stack.pop_u32() } as usize;
887        let param_num = unsafe { stack.pop_u32() } as usize;
888        // charge energy linearly in the amount of data written.
889        energy.tick_energy(constants::copy_parameter_cost(length))?;
890        if let Some(param) = parameters.get(param_num) {
891            let write_end = start + length as usize; // this cannot overflow on 64-bit machines.
892            ensure!(write_end <= memory.len(), "Illegal memory access.");
893            let end = std::cmp::min(offset + length as usize, param.as_ref().len());
894            ensure!(offset <= end, "Attempting to read non-existent parameter.");
895            let amt = (&mut memory[start..write_end]).write(&param.as_ref()[offset..end])?;
896            stack.push_value(amt as u32);
897        } else {
898            stack.push_value(-1i32);
899        }
900        Ok(())
901    }
902
903    #[cfg_attr(not(feature = "fuzz-coverage"), inline)]
904    /// Handle the `state_lookup_entry` host function. See
905    /// [InstanceState::lookup_entry] for detailed documentation.
906    pub(crate) fn state_lookup_entry<BackingStore: BackingStoreLoad>(
907        memory: &mut [u8],
908        stack: &mut machine::RuntimeStack,
909        energy: &mut InterpreterEnergy,
910        state: &mut InstanceState<BackingStore>,
911    ) -> machine::RunResult<()> {
912        let key_len = unsafe { stack.pop_u32() };
913        let key_start = unsafe { stack.pop_u32() } as usize;
914        let key_end = key_start + key_len as usize;
915        energy.tick_energy(constants::lookup_entry_cost(key_len))?;
916        ensure!(key_end <= memory.len(), "Illegal memory access.");
917        let key = &memory[key_start..key_end];
918        let result = state.lookup_entry(key);
919        stack.push_value(u64::from(result));
920        Ok(())
921    }
922
923    #[cfg_attr(not(feature = "fuzz-coverage"), inline)]
924    /// Handle the `state_create_entry` host function. See
925    /// [InstanceState::create_entry] for detailed documentation.
926    pub(crate) fn state_create_entry<BackingStore: BackingStoreLoad>(
927        memory: &mut [u8],
928        stack: &mut machine::RuntimeStack,
929        energy: &mut InterpreterEnergy,
930        state: &mut InstanceState<BackingStore>,
931    ) -> machine::RunResult<()> {
932        let key_len = unsafe { stack.pop_u32() };
933        let key_start = unsafe { stack.pop_u32() } as usize;
934        let key_end = key_start + key_len as usize;
935        energy.tick_energy(constants::create_entry_cost(key_len))?;
936        ensure!(key_end <= memory.len(), "Illegal memory access.");
937        let key = &memory[key_start..key_end];
938        let entry_index = state.create_entry(key)?;
939        stack.push_value(u64::from(entry_index));
940        Ok(())
941    }
942
943    #[cfg_attr(not(feature = "fuzz-coverage"), inline)]
944    /// Handle the `state_delete_entry` host function. See
945    /// [InstanceState::delete_entry] for detailed documentation.
946    pub(crate) fn state_delete_entry<BackingStore: BackingStoreLoad>(
947        memory: &mut [u8],
948        stack: &mut machine::RuntimeStack,
949        energy: &mut InterpreterEnergy,
950        state: &mut InstanceState<BackingStore>,
951    ) -> machine::RunResult<()> {
952        let key_len = unsafe { stack.pop_u32() };
953        let key_start = unsafe { stack.pop_u32() } as usize;
954        let key_end = key_start + key_len as usize;
955        energy.tick_energy(constants::delete_entry_cost(key_len))?;
956        ensure!(key_end <= memory.len(), "Illegal memory access.");
957        let key = &memory[key_start..key_end];
958        let result = state.delete_entry(key)?;
959        stack.push_value(result);
960        Ok(())
961    }
962
963    #[cfg_attr(not(feature = "fuzz-coverage"), inline)]
964    /// Handle the `state_delete_prefix` host function. See
965    /// [InstanceState::delete_prefix] for detailed documentation.
966    pub(crate) fn state_delete_prefix<BackingStore: BackingStoreLoad>(
967        memory: &mut [u8],
968        stack: &mut machine::RuntimeStack,
969        energy: &mut InterpreterEnergy,
970        state: &mut InstanceState<BackingStore>,
971    ) -> machine::RunResult<()> {
972        let key_len = unsafe { stack.pop_u32() };
973        let key_start = unsafe { stack.pop_u32() } as usize;
974        let key_end = key_start + key_len as usize;
975        // this cannot overflow on 64-bit platforms, so it is safe to just add
976        ensure!(key_end <= memory.len(), "Illegal memory access.");
977        let key = &memory[key_start..key_end];
978        energy.tick_energy(constants::delete_prefix_find_cost(key_len))?;
979        let result = state.delete_prefix(energy, key)?;
980        stack.push_value(result);
981        Ok(())
982    }
983
984    #[cfg_attr(not(feature = "fuzz-coverage"), inline)]
985    /// Handle the `state_iterator` host function. See
986    /// [InstanceState::iterator] for detailed documentation.
987    pub(crate) fn state_iterator<BackingStore: BackingStoreLoad>(
988        memory: &mut [u8],
989        stack: &mut machine::RuntimeStack,
990        energy: &mut InterpreterEnergy,
991        state: &mut InstanceState<BackingStore>,
992    ) -> machine::RunResult<()> {
993        let prefix_len = unsafe { stack.pop_u32() };
994        let prefix_start = unsafe { stack.pop_u32() } as usize;
995        let prefix_end = prefix_start + prefix_len as usize;
996        ensure!(prefix_end <= memory.len(), "Illegal memory access.");
997        energy.tick_energy(constants::new_iterator_cost(prefix_len))?;
998        let prefix = &memory[prefix_start..prefix_end];
999        let iterator_index = state.iterator(prefix);
1000        stack.push_value(u64::from(iterator_index));
1001        Ok(())
1002    }
1003
1004    #[cfg_attr(not(feature = "fuzz-coverage"), inline)]
1005    /// Handle the `state_iterator_next` host function. See
1006    /// [InstanceState::iterator_next] for detailed documentation.
1007    pub(crate) fn state_iterator_next<BackingStore: BackingStoreLoad>(
1008        stack: &mut machine::RuntimeStack,
1009        energy: &mut InterpreterEnergy,
1010        state: &mut InstanceState<BackingStore>,
1011    ) -> machine::RunResult<()> {
1012        let iter_index = unsafe { stack.pop_u64() };
1013        let entry_option = state.iterator_next(energy, InstanceStateIterator::from(iter_index))?;
1014        stack.push_value(u64::from(entry_option));
1015        Ok(())
1016    }
1017
1018    /// Handle the `state_iterator_delete` host function. See
1019    /// [InstanceState::iterator_delete] for detailed documentation.
1020    pub(crate) fn state_iterator_delete<BackingStore: BackingStoreLoad>(
1021        stack: &mut machine::RuntimeStack,
1022        energy: &mut InterpreterEnergy,
1023        state: &mut InstanceState<BackingStore>,
1024    ) -> machine::RunResult<()> {
1025        let iter = unsafe { stack.pop_u64() };
1026        let result = state.iterator_delete(energy, InstanceStateIterator::from(iter))?;
1027        stack.push_value(result);
1028        Ok(())
1029    }
1030
1031    /// Handle the `state_iterator_key_size` host function. See
1032    /// [InstanceState::iterator_key_size] for detailed documentation.
1033    #[cfg_attr(not(feature = "fuzz-coverage"), inline)]
1034    pub(crate) fn state_iterator_key_size<BackingStore: BackingStoreLoad>(
1035        stack: &mut machine::RuntimeStack,
1036        energy: &mut InterpreterEnergy,
1037        state: &mut InstanceState<BackingStore>,
1038    ) -> machine::RunResult<()> {
1039        energy.tick_energy(constants::ITERATOR_KEY_SIZE_COST)?;
1040        // the cost of this function is adequately reflected by the base cost of a
1041        // function call so we do not charge extra.
1042        let iter = unsafe { stack.pop_u64() };
1043        let result = state.iterator_key_size(InstanceStateIterator::from(iter));
1044        stack.push_value(result);
1045        Ok(())
1046    }
1047
1048    /// Handle the `state_iterator_key_read` host function. See
1049    /// [InstanceState::iterator_key_read] for detailed documentation.
1050    pub(crate) fn state_iterator_key_read<BackingStore: BackingStoreLoad>(
1051        memory: &mut [u8],
1052        stack: &mut machine::RuntimeStack,
1053        energy: &mut InterpreterEnergy,
1054        state: &mut InstanceState<BackingStore>,
1055    ) -> machine::RunResult<()> {
1056        let offset = unsafe { stack.pop_u32() };
1057        let length = unsafe { stack.pop_u32() };
1058        let start = unsafe { stack.pop_u32() } as usize;
1059        let iter = unsafe { stack.pop_u64() };
1060        energy.tick_energy(constants::copy_from_host_cost(length))?;
1061        let dest_end = start + length as usize;
1062        ensure!(dest_end <= memory.len(), "Illegal memory access.");
1063        let dest = &mut memory[start..dest_end];
1064        let result = state.iterator_key_read(InstanceStateIterator::from(iter), dest, offset);
1065        stack.push_value(result);
1066        Ok(())
1067    }
1068
1069    /// Handle the `state_entry_read` host function. See
1070    /// [InstanceState::entry_read] for detailed documentation.
1071    pub(crate) fn state_entry_read<BackingStore: BackingStoreLoad>(
1072        memory: &mut [u8],
1073        stack: &mut machine::RuntimeStack,
1074        energy: &mut InterpreterEnergy,
1075        state: &mut InstanceState<BackingStore>,
1076    ) -> machine::RunResult<()> {
1077        let offset = unsafe { stack.pop_u32() };
1078        let length = unsafe { stack.pop_u32() };
1079        let dest_start = unsafe { stack.pop_u32() } as usize;
1080        let entry_index = unsafe { stack.pop_u64() };
1081        energy.tick_energy(constants::read_entry_cost(length))?;
1082        let dest_end = dest_start + length as usize;
1083        ensure!(dest_end <= memory.len(), "Illegal memory access.");
1084        let dest = &mut memory[dest_start..dest_end];
1085        let result = state.entry_read(InstanceStateEntry::from(entry_index), dest, offset);
1086        stack.push_value(result);
1087        Ok(())
1088    }
1089
1090    /// Handle the `state_entry_write` host function. See
1091    /// [InstanceState::entry_write] for detailed documentation.
1092    pub(crate) fn state_entry_write<BackingStore: BackingStoreLoad>(
1093        memory: &mut [u8],
1094        stack: &mut machine::RuntimeStack,
1095        energy: &mut InterpreterEnergy,
1096        state: &mut InstanceState<BackingStore>,
1097    ) -> machine::RunResult<()> {
1098        let offset = unsafe { stack.pop_u32() };
1099        let length = unsafe { stack.pop_u32() };
1100        let source_start = unsafe { stack.pop_u32() } as usize;
1101        let entry_index = unsafe { stack.pop_u64() };
1102        energy.tick_energy(constants::write_entry_cost(length))?;
1103        let source_end = source_start + length as usize;
1104        ensure!(source_end <= memory.len(), "Illegal memory access.");
1105        let source = &memory[source_start..source_end];
1106        let result =
1107            state.entry_write(energy, InstanceStateEntry::from(entry_index), source, offset)?;
1108        stack.push_value(result);
1109        Ok(())
1110    }
1111
1112    #[cfg_attr(not(feature = "fuzz-coverage"), inline)]
1113    /// Handle the `state_entry_size` host function. See
1114    /// [InstanceState::entry_size] for detailed documentation.
1115    pub(crate) fn state_entry_size<BackingStore: BackingStoreLoad>(
1116        stack: &mut machine::RuntimeStack,
1117        energy: &mut InterpreterEnergy,
1118        state: &mut InstanceState<BackingStore>,
1119    ) -> machine::RunResult<()> {
1120        let entry_index = unsafe { stack.pop_u64() };
1121        energy.tick_energy(constants::ENTRY_SIZE_COST)?;
1122        let result = state.entry_size(InstanceStateEntry::from(entry_index));
1123        stack.push_value(result);
1124        Ok(())
1125    }
1126
1127    #[cfg_attr(not(feature = "fuzz-coverage"), inline)]
1128    /// Handle the `state_entry_resize` host function. See
1129    /// [InstanceState::entry_resize] for detailed documentation.
1130    pub(crate) fn state_entry_resize<BackingStore: BackingStoreLoad>(
1131        stack: &mut machine::RuntimeStack,
1132        energy: &mut InterpreterEnergy,
1133        state: &mut InstanceState<BackingStore>,
1134    ) -> machine::RunResult<()> {
1135        energy.tick_energy(constants::RESIZE_ENTRY_BASE_COST)?;
1136        let new_size = unsafe { stack.pop_u32() };
1137        let entry_index = unsafe { stack.pop_u64() };
1138        let result = state.entry_resize(energy, InstanceStateEntry::from(entry_index), new_size)?;
1139        stack.push_value(result);
1140        Ok(())
1141    }
1142
1143    #[cfg_attr(not(feature = "fuzz-coverage"), inline)]
1144    /// Handle the `get_receive_entrypoint_size` host function.
1145    pub(crate) fn get_receive_entrypoint_size(
1146        stack: &mut machine::RuntimeStack,
1147        entrypoint: EntrypointName,
1148    ) -> machine::RunResult<()> {
1149        let size: u32 = entrypoint.size();
1150        stack.push_value(size);
1151        Ok(())
1152    }
1153
1154    #[cfg_attr(not(feature = "fuzz-coverage"), inline)]
1155    /// Handle the `get_receive_entrypoint` host function.
1156    pub(crate) fn get_receive_entrypoint(
1157        memory: &mut [u8],
1158        stack: &mut machine::RuntimeStack,
1159        entrypoint: EntrypointName,
1160    ) -> machine::RunResult<()> {
1161        let start = unsafe { stack.pop_u32() };
1162        let size = entrypoint.size();
1163        // overflow here is not possible on 64-bit machines
1164        let end: usize = start as usize + size as usize;
1165        ensure!(end <= memory.len(), "Illegal memory access.");
1166        let entrypoint_str: &str = entrypoint.into();
1167        memory[start as usize..end].copy_from_slice(entrypoint_str.as_bytes());
1168        Ok(())
1169    }
1170
1171    #[cfg_attr(not(feature = "fuzz-coverage"), inline)]
1172    pub(crate) fn verify_ed25519_signature(
1173        memory: &mut [u8],
1174        stack: &mut machine::RuntimeStack,
1175        energy: &mut InterpreterEnergy,
1176    ) -> machine::RunResult<()> {
1177        let message_len = unsafe { stack.pop_u32() };
1178        let message_start = unsafe { stack.pop_u32() };
1179        let signature_start = unsafe { stack.pop_u32() };
1180        let public_key_start = unsafe { stack.pop_u32() };
1181        let message_end = message_start as usize + message_len as usize;
1182        ensure!(message_end <= memory.len(), "Illegal memory access.");
1183        let public_key_end = public_key_start as usize + 32;
1184        ensure!(public_key_end <= memory.len(), "Illegal memory access.");
1185        let signature_end = signature_start as usize + 64;
1186        ensure!(signature_end <= memory.len(), "Illegal memory access.");
1187        // expensive operations start now.
1188        energy.tick_energy(constants::verify_ed25519_cost(message_len))?;
1189        let signature =
1190            ed25519_zebra::Signature::try_from(&memory[signature_start as usize..signature_end]);
1191        let message = &memory[message_start as usize..message_end];
1192        let public_key = ed25519_zebra::VerificationKey::try_from(
1193            &memory[public_key_start as usize..public_key_end],
1194        );
1195        match (signature, public_key) {
1196            (Ok(ref signature), Ok(public_key)) => {
1197                if public_key.verify(signature, message).is_ok() {
1198                    stack.push_value(1u32);
1199                } else {
1200                    stack.push_value(0u32);
1201                }
1202            }
1203            _ => stack.push_value(0u32),
1204        }
1205        Ok(())
1206    }
1207
1208    pub(crate) fn debug_print<Debug: DebugInfo>(
1209        debug: &mut Debug,
1210        memory: &mut [u8],
1211        stack: &mut machine::RuntimeStack,
1212        energy: &mut InterpreterEnergy,
1213    ) -> machine::RunResult<()> {
1214        let (filename, line, column, msg) = crate::utils::extract_debug(memory, stack)?;
1215        debug.emit_debug_event(EmittedDebugStatement {
1216            filename,
1217            line,
1218            column,
1219            msg,
1220            remaining_energy: *energy,
1221        });
1222        Ok(())
1223    }
1224
1225    #[cfg_attr(not(feature = "fuzz-coverage"), inline)]
1226    pub(crate) fn verify_ecdsa_secp256k1_signature(
1227        memory: &mut [u8],
1228        stack: &mut machine::RuntimeStack,
1229        energy: &mut InterpreterEnergy,
1230    ) -> machine::RunResult<()> {
1231        let message_start = unsafe { stack.pop_u32() };
1232        let signature_start = unsafe { stack.pop_u32() };
1233        let public_key_start = unsafe { stack.pop_u32() };
1234        let message_end = message_start as usize + 32;
1235        ensure!(message_end <= memory.len(), "Illegal memory access.");
1236        let public_key_end = public_key_start as usize + 33;
1237        ensure!(public_key_end <= memory.len(), "Illegal memory access.");
1238        let signature_end = signature_start as usize + 64;
1239        ensure!(signature_end <= memory.len(), "Illegal memory access.");
1240        // expensive operations start now.
1241        energy.tick_energy(constants::VERIFY_ECDSA_SECP256K1_COST)?;
1242        let signature = secp256k1::ecdsa::Signature::from_compact(
1243            &memory[signature_start as usize..signature_end],
1244        );
1245        let message = secp256k1::Message::from_slice(&memory[message_start as usize..message_end]);
1246        let public_key =
1247            secp256k1::PublicKey::from_slice(&memory[public_key_start as usize..public_key_end]);
1248        match (signature, message, public_key) {
1249            (Ok(signature), Ok(message), Ok(public_key)) => {
1250                let verifier = secp256k1::Secp256k1::verification_only();
1251                if verifier.verify_ecdsa(&message, &signature, &public_key).is_ok() {
1252                    stack.push_value(1u32);
1253                } else {
1254                    stack.push_value(0u32);
1255                }
1256            }
1257            _ => stack.push_value(0u32),
1258        }
1259        Ok(())
1260    }
1261
1262    #[cfg_attr(not(feature = "fuzz-coverage"), inline)]
1263    pub(crate) fn hash_sha2_256(
1264        memory: &mut [u8],
1265        stack: &mut machine::RuntimeStack,
1266        energy: &mut InterpreterEnergy,
1267    ) -> machine::RunResult<()> {
1268        let output_start = unsafe { stack.pop_u32() };
1269        let data_len = unsafe { stack.pop_u32() };
1270        let data_start = unsafe { stack.pop_u32() };
1271        let data_end = data_start as usize + data_len as usize;
1272        ensure!(data_end <= memory.len(), "Illegal memory access.");
1273        let output_end = output_start as usize + 32;
1274        ensure!(output_end <= memory.len(), "Illegal memory access.");
1275        // expensive operations start here
1276        energy.tick_energy(constants::hash_sha2_256_cost(data_len))?;
1277        let hash = sha2::Sha256::digest(&memory[data_start as usize..data_end]);
1278        memory[output_start as usize..output_end].copy_from_slice(&hash);
1279        Ok(())
1280    }
1281
1282    #[cfg_attr(not(feature = "fuzz-coverage"), inline)]
1283    pub(crate) fn hash_sha3_256(
1284        memory: &mut [u8],
1285        stack: &mut machine::RuntimeStack,
1286        energy: &mut InterpreterEnergy,
1287    ) -> machine::RunResult<()> {
1288        let output_start = unsafe { stack.pop_u32() };
1289        let data_len = unsafe { stack.pop_u32() };
1290        let data_start = unsafe { stack.pop_u32() };
1291        let data_end = data_start as usize + data_len as usize;
1292        ensure!(data_end <= memory.len(), "Illegal memory access.");
1293        let output_end = output_start as usize + 32;
1294        ensure!(output_end <= memory.len(), "Illegal memory access.");
1295        // expensive operations start here
1296        energy.tick_energy(constants::hash_sha3_256_cost(data_len))?;
1297        let hash = sha3::Sha3_256::digest(&memory[data_start as usize..data_end]);
1298        memory[output_start as usize..output_end].copy_from_slice(&hash);
1299        Ok(())
1300    }
1301
1302    #[cfg_attr(not(feature = "fuzz-coverage"), inline)]
1303    pub(crate) fn hash_keccak_256(
1304        memory: &mut [u8],
1305        stack: &mut machine::RuntimeStack,
1306        energy: &mut InterpreterEnergy,
1307    ) -> machine::RunResult<()> {
1308        let output_start = unsafe { stack.pop_u32() };
1309        let data_len = unsafe { stack.pop_u32() };
1310        let data_start = unsafe { stack.pop_u32() };
1311        let data_end = data_start as usize + data_len as usize;
1312        ensure!(data_end <= memory.len(), "Illegal memory access.");
1313        let output_end = output_start as usize + 32;
1314        ensure!(output_end <= memory.len(), "Illegal memory access.");
1315        // expensive operations start here
1316        energy.tick_energy(constants::hash_keccak_256_cost(data_len))?;
1317        let hash = sha3::Keccak256::digest(&memory[data_start as usize..data_end]);
1318        memory[output_start as usize..output_end].copy_from_slice(&hash);
1319        Ok(())
1320    }
1321
1322    #[cfg_attr(not(feature = "fuzz-coverage"), inline)]
1323    /// Handle the `upgrade` host function.
1324    pub(crate) fn upgrade(
1325        memory: &mut [u8],
1326        stack: &mut machine::RuntimeStack,
1327        energy: &mut InterpreterEnergy,
1328    ) -> machine::RunResult<Option<Interrupt>> {
1329        let module_ref_start = unsafe { stack.pop_u32() } as usize;
1330        let module_ref_end = module_ref_start + 32;
1331        ensure!(module_ref_end <= memory.len(), "Illegal memory access.");
1332        let mut module_reference_bytes = [0u8; 32];
1333        module_reference_bytes.copy_from_slice(&memory[module_ref_start..module_ref_end]);
1334        let module_ref = ModuleReference::from(module_reference_bytes);
1335        // We tick a base action cost here and
1336        // tick the remaining cost in the 'Scheduler' as it knows the size
1337        // of the new module.
1338        energy.tick_energy(constants::INVOKE_BASE_COST)?;
1339        Ok(Some(Interrupt::Upgrade {
1340            module_ref,
1341        }))
1342    }
1343}
1344
1345// The use of Vec<u8> is ugly, and we really should have [u8] there, but FFI
1346// prevents us doing that without ugly hacks.
1347impl<
1348        'a,
1349        BackingStore: BackingStoreLoad,
1350        ParamType: AsRef<[u8]>,
1351        Ctx: v0::HasInitContext,
1352        A: DebugInfo,
1353    > machine::Host<ProcessedImports> for InitHost<'a, BackingStore, ParamType, Ctx, A>
1354{
1355    type Interrupt = NoInterrupt;
1356
1357    #[cfg_attr(not(feature = "fuzz-coverage"), inline(always))]
1358    fn tick_initial_memory(&mut self, num_pages: u32) -> machine::RunResult<()> {
1359        self.energy.charge_memory_alloc(num_pages)
1360    }
1361
1362    #[inline(always)]
1363    fn tick_energy(&mut self, energy: u64) -> machine::RunResult<()> {
1364        self.energy.tick_energy(energy)
1365    }
1366
1367    #[inline(always)]
1368    fn track_call(&mut self) -> machine::RunResult<()> {
1369        v0::host::track_call(&mut self.activation_frames)
1370    }
1371
1372    #[inline(always)]
1373    fn track_return(&mut self) { v0::host::track_return(&mut self.activation_frames) }
1374
1375    #[cfg_attr(not(feature = "fuzz-coverage"), inline)]
1376    fn call(
1377        &mut self,
1378        f: &ProcessedImports,
1379        memory: &mut [u8],
1380        stack: &mut machine::RuntimeStack,
1381    ) -> machine::RunResult<Option<Self::Interrupt>> {
1382        let energy_before = self.energy;
1383        match f.tag {
1384            ImportFunc::ChargeMemoryAlloc => {
1385                v0::host::charge_memory_alloc(stack, &mut self.energy)?
1386            }
1387            ImportFunc::Common(cf) => match cf {
1388                CommonFunc::WriteOutput => host::write_return_value(
1389                    memory,
1390                    stack,
1391                    &mut self.energy,
1392                    &mut self.return_value,
1393                    self.limit_logs_and_return_values,
1394                ),
1395                CommonFunc::GetParameterSize => host::get_parameter_size(stack, &[&self.parameter]),
1396                CommonFunc::GetParameterSection => {
1397                    host::get_parameter_section(memory, stack, &mut self.energy, &[&self.parameter])
1398                }
1399                CommonFunc::GetPolicySection => v0::host::get_policy_section(
1400                    memory,
1401                    stack,
1402                    &mut self.energy,
1403                    self.init_ctx.sender_policies(),
1404                ),
1405                CommonFunc::LogEvent => v0::host::log_event(
1406                    memory,
1407                    stack,
1408                    &mut self.energy,
1409                    &mut self.logs,
1410                    self.limit_logs_and_return_values,
1411                ),
1412                CommonFunc::GetSlotTime => v0::host::get_slot_time(stack, self.init_ctx.metadata()),
1413                CommonFunc::StateLookupEntry => {
1414                    host::state_lookup_entry(memory, stack, &mut self.energy, &mut self.state)
1415                }
1416                CommonFunc::StateCreateEntry => {
1417                    host::state_create_entry(memory, stack, &mut self.energy, &mut self.state)
1418                }
1419                CommonFunc::StateDeleteEntry => {
1420                    host::state_delete_entry(memory, stack, &mut self.energy, &mut self.state)
1421                }
1422                CommonFunc::StateDeletePrefix => {
1423                    host::state_delete_prefix(memory, stack, &mut self.energy, &mut self.state)
1424                }
1425                CommonFunc::StateIteratePrefix => {
1426                    host::state_iterator(memory, stack, &mut self.energy, &mut self.state)
1427                }
1428                CommonFunc::StateIteratorNext => {
1429                    host::state_iterator_next(stack, &mut self.energy, &mut self.state)
1430                }
1431                CommonFunc::StateIteratorDelete => {
1432                    host::state_iterator_delete(stack, &mut self.energy, &mut self.state)
1433                }
1434                CommonFunc::StateIteratorKeySize => {
1435                    host::state_iterator_key_size(stack, &mut self.energy, &mut self.state)
1436                }
1437                CommonFunc::StateIteratorKeyRead => {
1438                    host::state_iterator_key_read(memory, stack, &mut self.energy, &mut self.state)
1439                }
1440                CommonFunc::StateEntryRead => {
1441                    host::state_entry_read(memory, stack, &mut self.energy, &mut self.state)
1442                }
1443                CommonFunc::StateEntryWrite => {
1444                    host::state_entry_write(memory, stack, &mut self.energy, &mut self.state)
1445                }
1446                CommonFunc::StateEntrySize => {
1447                    host::state_entry_size(stack, &mut self.energy, &mut self.state)
1448                }
1449                CommonFunc::StateEntryResize => {
1450                    host::state_entry_resize(stack, &mut self.energy, &mut self.state)
1451                }
1452                CommonFunc::VerifyEd25519 => {
1453                    host::verify_ed25519_signature(memory, stack, &mut self.energy)
1454                }
1455                CommonFunc::VerifySecp256k1 => {
1456                    host::verify_ecdsa_secp256k1_signature(memory, stack, &mut self.energy)
1457                }
1458                CommonFunc::DebugPrint => {
1459                    host::debug_print(&mut self.trace, memory, stack, &mut self.energy)
1460                }
1461                CommonFunc::HashSHA2_256 => host::hash_sha2_256(memory, stack, &mut self.energy),
1462                CommonFunc::HashSHA3_256 => host::hash_sha3_256(memory, stack, &mut self.energy),
1463                CommonFunc::HashKeccak256 => host::hash_keccak_256(memory, stack, &mut self.energy),
1464            }?,
1465            ImportFunc::InitOnly(InitOnlyFunc::GetInitOrigin) => {
1466                v0::host::get_init_origin(memory, stack, self.init_ctx.init_origin())?
1467            }
1468            ImportFunc::ReceiveOnly(_) => {
1469                bail!("Not implemented for init {:#?}.", f);
1470            }
1471        }
1472        let energy_after: InterpreterEnergy = self.energy;
1473        self.trace.trace_host_call(f.tag, energy_before.saturating_sub(&energy_after));
1474        Ok(None)
1475    }
1476}
1477
1478/// A receive context for V1 contracts.
1479pub trait HasReceiveContext: v0::HasReceiveContext {
1480    /// Get the name of the entrypoint that was actually invoked.
1481    /// This may differ from the name of the entrypoint that is actually invoked
1482    /// in case the entrypoint that is invoked is the fallback one.
1483    fn entrypoint(&self) -> ExecResult<EntrypointName>;
1484}
1485
1486impl<X: AsRef<[u8]>> v0::HasReceiveContext for ReceiveContext<X> {
1487    type MetadataType = ChainMetadata;
1488
1489    fn metadata(&self) -> &Self::MetadataType { &self.common.metadata }
1490
1491    fn invoker(&self) -> ExecResult<&AccountAddress> { Ok(&self.common.invoker) }
1492
1493    fn self_address(&self) -> ExecResult<&ContractAddress> { Ok(&self.common.self_address) }
1494
1495    fn self_balance(&self) -> ExecResult<Amount> { Ok(self.common.self_balance) }
1496
1497    fn sender(&self) -> ExecResult<&Address> { Ok(&self.common.sender) }
1498
1499    fn owner(&self) -> ExecResult<&AccountAddress> { Ok(&self.common.owner) }
1500
1501    fn sender_policies(&self) -> ExecResult<&[u8]> { Ok(self.common.sender_policies.as_ref()) }
1502}
1503
1504impl<X: AsRef<[u8]>> HasReceiveContext for ReceiveContext<X> {
1505    #[inline(always)]
1506    fn entrypoint(&self) -> ExecResult<EntrypointName> { Ok(self.entrypoint.as_entrypoint_name()) }
1507}
1508
1509impl<'a, X: HasReceiveContext> HasReceiveContext for &'a X {
1510    #[inline(always)]
1511    fn entrypoint(&self) -> ExecResult<EntrypointName> { (*self).entrypoint() }
1512}
1513
1514impl<
1515        'a,
1516        BackingStore: BackingStoreLoad,
1517        ParamType: AsRef<[u8]>,
1518        Ctx: HasReceiveContext,
1519        A: DebugInfo,
1520    > machine::Host<ProcessedImports> for ReceiveHost<'a, BackingStore, ParamType, Ctx, A>
1521{
1522    type Interrupt = Interrupt;
1523
1524    #[cfg_attr(not(feature = "fuzz-coverage"), inline(always))]
1525    fn tick_initial_memory(&mut self, num_pages: u32) -> machine::RunResult<()> {
1526        self.energy.charge_memory_alloc(num_pages)
1527    }
1528
1529    #[inline(always)]
1530    fn tick_energy(&mut self, energy: u64) -> machine::RunResult<()> {
1531        self.energy.tick_energy(energy)
1532    }
1533
1534    #[inline(always)]
1535    fn track_call(&mut self) -> machine::RunResult<()> {
1536        v0::host::track_call(&mut self.stateless.activation_frames)
1537    }
1538
1539    #[inline(always)]
1540    fn track_return(&mut self) { v0::host::track_return(&mut self.stateless.activation_frames) }
1541
1542    #[cfg_attr(not(feature = "fuzz-coverage"), inline)]
1543    fn call(
1544        &mut self,
1545        f: &ProcessedImports,
1546        memory: &mut [u8],
1547        stack: &mut machine::RuntimeStack,
1548    ) -> machine::RunResult<Option<Self::Interrupt>> {
1549        let energy_before = self.energy;
1550        match f.tag {
1551            ImportFunc::ChargeMemoryAlloc => {
1552                v0::host::charge_memory_alloc(stack, &mut self.energy)?
1553            }
1554            ImportFunc::Common(cf) => match cf {
1555                CommonFunc::WriteOutput => host::write_return_value(
1556                    memory,
1557                    stack,
1558                    &mut self.energy,
1559                    &mut self.stateless.return_value,
1560                    self.stateless.params.limit_logs_and_return_values,
1561                ),
1562                CommonFunc::GetParameterSize => {
1563                    host::get_parameter_size(stack, &self.stateless.parameters)
1564                }
1565                CommonFunc::GetParameterSection => host::get_parameter_section(
1566                    memory,
1567                    stack,
1568                    &mut self.energy,
1569                    &self.stateless.parameters,
1570                ),
1571                CommonFunc::GetPolicySection => v0::host::get_policy_section(
1572                    memory,
1573                    stack,
1574                    &mut self.energy,
1575                    self.stateless.receive_ctx.sender_policies(),
1576                ),
1577                CommonFunc::LogEvent => v0::host::log_event(
1578                    memory,
1579                    stack,
1580                    &mut self.energy,
1581                    &mut self.stateless.logs,
1582                    self.stateless.params.limit_logs_and_return_values,
1583                ),
1584                CommonFunc::GetSlotTime => {
1585                    v0::host::get_slot_time(stack, self.stateless.receive_ctx.metadata())
1586                }
1587                CommonFunc::StateLookupEntry => {
1588                    host::state_lookup_entry(memory, stack, &mut self.energy, &mut self.state)
1589                }
1590                CommonFunc::StateCreateEntry => {
1591                    host::state_create_entry(memory, stack, &mut self.energy, &mut self.state)
1592                }
1593                CommonFunc::StateDeleteEntry => {
1594                    host::state_delete_entry(memory, stack, &mut self.energy, &mut self.state)
1595                }
1596                CommonFunc::StateDeletePrefix => {
1597                    host::state_delete_prefix(memory, stack, &mut self.energy, &mut self.state)
1598                }
1599                CommonFunc::StateIteratePrefix => {
1600                    host::state_iterator(memory, stack, &mut self.energy, &mut self.state)
1601                }
1602                CommonFunc::StateIteratorNext => {
1603                    host::state_iterator_next(stack, &mut self.energy, &mut self.state)
1604                }
1605                CommonFunc::StateIteratorDelete => {
1606                    host::state_iterator_delete(stack, &mut self.energy, &mut self.state)
1607                }
1608                CommonFunc::StateIteratorKeySize => {
1609                    host::state_iterator_key_size(stack, &mut self.energy, &mut self.state)
1610                }
1611                CommonFunc::StateIteratorKeyRead => {
1612                    host::state_iterator_key_read(memory, stack, &mut self.energy, &mut self.state)
1613                }
1614                CommonFunc::StateEntryRead => {
1615                    host::state_entry_read(memory, stack, &mut self.energy, &mut self.state)
1616                }
1617                CommonFunc::StateEntryWrite => {
1618                    host::state_entry_write(memory, stack, &mut self.energy, &mut self.state)
1619                }
1620                CommonFunc::StateEntrySize => {
1621                    host::state_entry_size(stack, &mut self.energy, &mut self.state)
1622                }
1623                CommonFunc::StateEntryResize => {
1624                    host::state_entry_resize(stack, &mut self.energy, &mut self.state)
1625                }
1626                CommonFunc::VerifyEd25519 => {
1627                    host::verify_ed25519_signature(memory, stack, &mut self.energy)
1628                }
1629                CommonFunc::VerifySecp256k1 => {
1630                    host::verify_ecdsa_secp256k1_signature(memory, stack, &mut self.energy)
1631                }
1632                CommonFunc::DebugPrint => {
1633                    host::debug_print(&mut self.trace, memory, stack, &mut self.energy)
1634                }
1635                CommonFunc::HashSHA2_256 => host::hash_sha2_256(memory, stack, &mut self.energy),
1636                CommonFunc::HashSHA3_256 => host::hash_sha3_256(memory, stack, &mut self.energy),
1637                CommonFunc::HashKeccak256 => host::hash_keccak_256(memory, stack, &mut self.energy),
1638            }?,
1639            ImportFunc::ReceiveOnly(rof) => match rof {
1640                ReceiveOnlyFunc::Invoke => {
1641                    let invoke =
1642                        host::invoke(self.stateless.params, memory, stack, &mut self.energy);
1643                    let energy_after: InterpreterEnergy = self.energy;
1644                    self.trace.trace_host_call(f.tag, energy_before.saturating_sub(&energy_after));
1645                    return invoke;
1646                }
1647                ReceiveOnlyFunc::GetReceiveInvoker => v0::host::get_receive_invoker(
1648                    memory,
1649                    stack,
1650                    self.stateless.receive_ctx.invoker(),
1651                ),
1652                ReceiveOnlyFunc::GetReceiveSelfAddress => v0::host::get_receive_self_address(
1653                    memory,
1654                    stack,
1655                    self.stateless.receive_ctx.self_address(),
1656                ),
1657                ReceiveOnlyFunc::GetReceiveSelfBalance => v0::host::get_receive_self_balance(
1658                    stack,
1659                    self.stateless.receive_ctx.self_balance(),
1660                ),
1661                ReceiveOnlyFunc::GetReceiveSender => {
1662                    v0::host::get_receive_sender(memory, stack, self.stateless.receive_ctx.sender())
1663                }
1664                ReceiveOnlyFunc::GetReceiveOwner => {
1665                    v0::host::get_receive_owner(memory, stack, self.stateless.receive_ctx.owner())
1666                }
1667                ReceiveOnlyFunc::GetReceiveEntrypointSize => host::get_receive_entrypoint_size(
1668                    stack,
1669                    self.stateless.receive_ctx.entrypoint()?,
1670                ),
1671                ReceiveOnlyFunc::GetReceiveEntryPoint => host::get_receive_entrypoint(
1672                    memory,
1673                    stack,
1674                    self.stateless.receive_ctx.entrypoint()?,
1675                ),
1676                ReceiveOnlyFunc::Upgrade => {
1677                    return host::upgrade(memory, stack, &mut self.energy);
1678                }
1679            }?,
1680            ImportFunc::InitOnly(InitOnlyFunc::GetInitOrigin) => {
1681                bail!("Not implemented for receive.");
1682            }
1683        }
1684        let energy_after: InterpreterEnergy = self.energy;
1685        self.trace.trace_host_call(f.tag, energy_before.saturating_sub(&energy_after));
1686        Ok(None)
1687    }
1688}
1689
1690/// Parameter whose ownership is tracked statically.
1691pub type ParameterRef<'a> = &'a [u8];
1692/// Parameter whose ownership is tracked dynamically.
1693/// This is needed, for example, when execution passes through Haskell and Rust.
1694/// Ideally this would be Arc<[u8]> but then this cannot be passed via the FFI
1695/// boundary directly since [u8] is not Sized. To avoid a third type we settle
1696/// on [`Vec<u8>`](Vec).
1697pub type ParameterVec = Vec<u8>;
1698
1699/// Collection of information relevant to invoke a init-function.
1700#[derive(Debug)]
1701pub struct InitInvocation<'a> {
1702    /// The amount included in the transaction.
1703    pub amount:    Amount,
1704    /// The name of the init function to invoke.
1705    pub init_name: &'a str,
1706    /// A parameter to provide the init function.
1707    pub parameter: ParameterRef<'a>,
1708    /// The limit on the energy to be used for execution.
1709    pub energy:    InterpreterEnergy,
1710}
1711
1712/// Invokes an init-function from a given artifact
1713pub fn invoke_init<BackingStore: BackingStoreLoad, R: RunnableCode, A: DebugInfo>(
1714    artifact: impl Borrow<Artifact<ProcessedImports, R>>,
1715    init_ctx: impl v0::HasInitContext,
1716    init_invocation: InitInvocation,
1717    limit_logs_and_return_values: bool,
1718    mut loader: BackingStore,
1719) -> InvokeResult<InitResult<A>, A> {
1720    let mut initial_state = trie::MutableState::initial_state();
1721    let inner = initial_state.get_inner(&mut loader);
1722    let state_ref = InstanceState::new(loader, inner);
1723    let mut host = InitHost::<_, _, _, A> {
1724        energy: init_invocation.energy,
1725        activation_frames: constants::MAX_ACTIVATION_FRAMES,
1726        logs: v0::Logs::new(),
1727        state: state_ref,
1728        return_value: Vec::new(),
1729        parameter: init_invocation.parameter,
1730        limit_logs_and_return_values,
1731        init_ctx,
1732        trace: A::empty_trace(),
1733    };
1734    let result = artifact.borrow().run(&mut host, init_invocation.init_name, &[Value::I64(
1735        init_invocation.amount.micro_ccd() as i64,
1736    )]);
1737    let return_value = std::mem::take(&mut host.return_value);
1738    let remaining_energy = host.energy.energy;
1739    let logs = std::mem::take(&mut host.logs);
1740    let trace = std::mem::replace(&mut host.trace, A::empty_trace());
1741    // release lock on the state
1742    drop(host);
1743    match result {
1744        Ok(ExecutionOutcome::Success {
1745            result,
1746            ..
1747        }) => {
1748            // process the return value.
1749            // - 0 indicates success
1750            // - positive values are a protocol violation, so they lead to a runtime error
1751            // - negative values lead to a rejection with a specific reject reason.
1752            if let Some(Value::I32(n)) = result {
1753                if n == 0 {
1754                    Ok(InitResult::Success {
1755                        logs,
1756                        return_value,
1757                        remaining_energy: remaining_energy.into(),
1758                        state: initial_state,
1759                        trace,
1760                    })
1761                } else {
1762                    let (reason, trace) = reason_from_wasm_error_code(n, trace)?;
1763                    Ok(InitResult::Reject {
1764                        reason,
1765                        return_value,
1766                        remaining_energy: remaining_energy.into(),
1767                        trace,
1768                    })
1769                }
1770            } else {
1771                Err(InvalidReturnCodeError {
1772                    value:       None,
1773                    debug_trace: trace,
1774                })
1775            }
1776        }
1777        Ok(ExecutionOutcome::Interrupted {
1778            reason,
1779            config: _,
1780        }) => match reason {},
1781        Err(error) => {
1782            if error.downcast_ref::<OutOfEnergy>().is_some() {
1783                Ok(InitResult::OutOfEnergy {
1784                    trace,
1785                })
1786            } else {
1787                Ok(InitResult::Trap {
1788                    error,
1789                    remaining_energy: remaining_energy.into(),
1790                    trace,
1791                })
1792            }
1793        }
1794    }
1795}
1796
1797#[derive(Debug, Clone, PartialEq, Eq)]
1798/// The kind of errors that may occur during handling of contract `invoke` or
1799/// `upgrade`.
1800pub enum InvokeFailure {
1801    /// The V1 contract rejected the call with the specific code. The code is
1802    /// always negative.
1803    ContractReject {
1804        code: i32,
1805        data: ParameterVec,
1806    },
1807    /// A transfer was attempted, but the sender did not have sufficient funds.
1808    InsufficientAmount,
1809    /// The receiving account of the transfer did not exist.
1810    NonExistentAccount,
1811    /// Contract to invoke did not exist (i.e., there is no contract on the
1812    /// supplied address).
1813    NonExistentContract,
1814    /// The contract existed, but the entrypoint did not.
1815    NonExistentEntrypoint,
1816    /// Sending a message to a V0 contact failed.
1817    SendingV0Failed,
1818    /// Invoking a contract failed with a runtime error.
1819    RuntimeError,
1820    /// The module to upgrade to does not exist.
1821    UpgradeInvalidModuleRef,
1822    /// The upgrade attempted to upgrade to a module which does not have the
1823    /// the required contract.
1824    UpgradeInvalidContractName,
1825    /// Attempt to upgrade a V1 contract to a V0 contract.
1826    UpgradeInvalidVersion,
1827    /// Could not parse the signature and message.
1828    SignatureDataMalformed,
1829    /// Invalid signature on the provided message.
1830    SignatureCheckFailed,
1831}
1832
1833impl InvokeFailure {
1834    /// Encode the failure kind in a format that is expected from a host
1835    /// function. If the return value is present it is pushed to the supplied
1836    /// vector of parameters.
1837    pub(crate) fn encode_as_u64<Debug>(
1838        self,
1839        parameters: &mut Vec<ParameterVec>,
1840    ) -> ResumeResult<u64, Debug> {
1841        Ok(match self {
1842            InvokeFailure::ContractReject {
1843                code,
1844                data,
1845            } => {
1846                let len = parameters.len();
1847                if len > 0b0111_1111_1111_1111_1111_1111 {
1848                    return Err(ResumeError::TooManyInterrupts);
1849                }
1850                parameters.push(data);
1851                (len as u64) << 40 | (code as u32 as u64)
1852            }
1853            InvokeFailure::InsufficientAmount => 0x01_0000_0000,
1854            InvokeFailure::NonExistentAccount => 0x02_0000_0000,
1855            InvokeFailure::NonExistentContract => 0x03_0000_0000,
1856            InvokeFailure::NonExistentEntrypoint => 0x04_0000_0000,
1857            InvokeFailure::SendingV0Failed => 0x05_0000_0000,
1858            InvokeFailure::RuntimeError => 0x06_0000_0000,
1859            InvokeFailure::UpgradeInvalidModuleRef => 0x07_0000_0000,
1860            InvokeFailure::UpgradeInvalidContractName => 0x08_0000_0000,
1861            InvokeFailure::UpgradeInvalidVersion => 0x09_0000_0000,
1862            InvokeFailure::SignatureDataMalformed => 0x0a_0000_0000,
1863            InvokeFailure::SignatureCheckFailed => 0x0b_0000_0000,
1864        })
1865    }
1866}
1867
1868/// Response from an invoke call.
1869#[derive(Debug)]
1870pub enum InvokeResponse {
1871    /// Execution was successful, and the state potentially changed.
1872    Success {
1873        /// Balance after the execution of the interrupt.
1874        new_balance: Amount,
1875        /// Some calls do not have any return values, such as transfers.
1876        data:        Option<ParameterVec>,
1877    },
1878    /// Execution was not successful. The state did not change
1879    /// and the contract or environment responded with the given error.
1880    Failure {
1881        kind: InvokeFailure,
1882    },
1883}
1884
1885#[cfg(feature = "enable-ffi")]
1886impl InvokeResponse {
1887    // NB: This must match the response encoding in V1.hs in consensus
1888    pub(crate) fn try_from_ffi_response(
1889        response_status: u64,
1890        new_balance: Amount,
1891        data: Option<ParameterVec>,
1892    ) -> anyhow::Result<Self> {
1893        // If the first 3 bytes are all set that indicates an error.
1894        let response = if response_status & 0xffff_ff00_0000_0000 == 0xffff_ff00_0000_0000 {
1895            let kind = match response_status & 0x0000_00ff_0000_0000 {
1896                0x0000_0000_0000_0000 => {
1897                    // The return value is present since this was a logic error.
1898                    if response_status & 0x0000_0000_ffff_ffff == 0 {
1899                        // Host violated precondition. There must be a non-zero error code.
1900                        bail!("Host violated precondition.")
1901                    }
1902                    let code = (response_status & 0x0000_0000_ffff_ffff) as u32 as i32;
1903                    if let Some(data) = data {
1904                        InvokeFailure::ContractReject {
1905                            code,
1906                            data,
1907                        }
1908                    } else {
1909                        bail!("Return value should be present in case of logic error.")
1910                    }
1911                }
1912                0x0000_0001_0000_0000 => InvokeFailure::InsufficientAmount,
1913                0x0000_0002_0000_0000 => InvokeFailure::NonExistentAccount,
1914                0x0000_0003_0000_0000 => InvokeFailure::NonExistentContract,
1915                0x0000_0004_0000_0000 => InvokeFailure::NonExistentEntrypoint,
1916                0x0000_0005_0000_0000 => InvokeFailure::SendingV0Failed,
1917                0x0000_0006_0000_0000 => InvokeFailure::RuntimeError,
1918                0x0000_0007_0000_0000 => InvokeFailure::UpgradeInvalidModuleRef,
1919                0x0000_0008_0000_0000 => InvokeFailure::UpgradeInvalidContractName,
1920                0x0000_0009_0000_0000 => InvokeFailure::UpgradeInvalidVersion,
1921                0x0000_000a_0000_0000 => InvokeFailure::SignatureDataMalformed,
1922                0x0000_000b_0000_0000 => InvokeFailure::SignatureCheckFailed,
1923                x => bail!("Unrecognized error code: {}", x),
1924            };
1925            InvokeResponse::Failure {
1926                kind,
1927            }
1928        } else {
1929            InvokeResponse::Success {
1930                new_balance,
1931                data,
1932            }
1933        };
1934        Ok(response)
1935    }
1936}
1937
1938#[derive(Copy, Clone, Debug)]
1939/// Common data used by the `invoke_*_from_artifact` family of functions.
1940pub struct InvokeFromArtifactCtx<'a> {
1941    /// The source of the artifact, serialized in the format specified by the
1942    /// `wasm_transform` crate.
1943    pub artifact:  &'a [u8],
1944    /// Amount to invoke with.
1945    pub amount:    Amount,
1946    /// Parameter to supply to the call.
1947    pub parameter: ParameterRef<'a>,
1948    /// Energy to allow for execution.
1949    pub energy:    InterpreterEnergy,
1950}
1951
1952/// Invokes an init-function from a given **serialized** artifact.
1953#[cfg_attr(not(feature = "fuzz-coverage"), inline)]
1954pub fn invoke_init_from_artifact<BackingStore: BackingStoreLoad, A: DebugInfo>(
1955    ctx: InvokeFromArtifactCtx,
1956    init_ctx: impl v0::HasInitContext,
1957    init_name: &str,
1958    loader: BackingStore,
1959    limit_logs_and_return_values: bool,
1960) -> ExecResult<InitResult<A>> {
1961    let artifact = utils::parse_artifact(ctx.artifact)?;
1962    let r = invoke_init(
1963        artifact,
1964        init_ctx,
1965        InitInvocation {
1966            amount: ctx.amount,
1967            init_name,
1968            parameter: ctx.parameter,
1969            energy: ctx.energy,
1970        },
1971        limit_logs_and_return_values,
1972        loader,
1973    )?;
1974    Ok(r)
1975}
1976
1977#[derive(Copy, Clone, Debug)]
1978/// Common data used by the `invoke_*_from_source` family of functions.
1979pub struct InvokeFromSourceCtx<'a> {
1980    /// The source Wasm module.
1981    pub source:          &'a [u8],
1982    /// Amount to invoke with.
1983    pub amount:          Amount,
1984    /// Parameter to supply to the call.
1985    pub parameter:       ParameterRef<'a>,
1986    /// Energy to allow for execution.
1987    pub energy:          InterpreterEnergy,
1988    /// Whether the module should be processed to allow upgrades or not.
1989    /// Upgrades are only allowed in protocol P5 and later. If this is set to
1990    /// `false` then parsing and validation will reject modules that use the
1991    /// `upgrade` function.
1992    pub support_upgrade: bool,
1993}
1994
1995/// Invokes an init-function from a **serialized** Wasm module.
1996#[cfg_attr(not(feature = "fuzz-coverage"), inline)]
1997pub fn invoke_init_from_source<BackingStore: BackingStoreLoad, A: DebugInfo>(
1998    ctx: InvokeFromSourceCtx,
1999    init_ctx: impl v0::HasInitContext,
2000    init_name: &str,
2001    loader: BackingStore,
2002    validation_config: ValidationConfig,
2003    limit_logs_and_return_values: bool,
2004) -> ExecResult<InitResult<A>> {
2005    let artifact = utils::instantiate(
2006        validation_config,
2007        &ConcordiumAllowedImports {
2008            support_upgrade: ctx.support_upgrade,
2009            enable_debug:    A::ENABLE_DEBUG,
2010        },
2011        ctx.source,
2012    )?
2013    .artifact;
2014    let r = invoke_init(
2015        artifact,
2016        init_ctx,
2017        InitInvocation {
2018            amount: ctx.amount,
2019            init_name,
2020            parameter: ctx.parameter,
2021            energy: ctx.energy,
2022        },
2023        limit_logs_and_return_values,
2024        loader,
2025    )?;
2026    Ok(r)
2027}
2028
2029/// Same as `invoke_init_from_source`, except that the module has cost
2030/// accounting instructions inserted before the init function is called.
2031#[cfg_attr(not(feature = "fuzz-coverage"), inline)]
2032pub fn invoke_init_with_metering_from_source<BackingStore: BackingStoreLoad, A: DebugInfo>(
2033    ctx: InvokeFromSourceCtx,
2034    init_ctx: impl v0::HasInitContext,
2035    init_name: &str,
2036    loader: BackingStore,
2037    validation_config: ValidationConfig,
2038    cost_config: impl CostConfiguration,
2039    limit_logs_and_return_values: bool,
2040) -> ExecResult<InitResult<A>> {
2041    let artifact = utils::instantiate_with_metering(
2042        validation_config,
2043        cost_config,
2044        &ConcordiumAllowedImports {
2045            support_upgrade: ctx.support_upgrade,
2046            enable_debug:    A::ENABLE_DEBUG,
2047        },
2048        ctx.source,
2049    )?
2050    .artifact;
2051    let r = invoke_init(
2052        artifact,
2053        init_ctx,
2054        InitInvocation {
2055            amount: ctx.amount,
2056            init_name,
2057            parameter: ctx.parameter,
2058            energy: ctx.energy,
2059        },
2060        limit_logs_and_return_values,
2061        loader,
2062    )?;
2063    Ok(r)
2064}
2065
2066fn process_receive_result<
2067    BackingStore,
2068    Param,
2069    R: RunnableCode,
2070    Art: Into<Arc<Artifact<ProcessedImports, R>>>,
2071    Ctx1,
2072    Ctx2,
2073    A: DebugInfo,
2074>(
2075    artifact: Art,
2076    host: ReceiveHost<'_, BackingStore, Param, Ctx1, A>,
2077    result: machine::RunResult<ExecutionOutcome<Interrupt>>,
2078) -> InvokeResult<ReceiveResult<R, A, Ctx2>, A>
2079where
2080    StateLessReceiveHost<ParameterVec, Ctx2>: From<StateLessReceiveHost<Param, Ctx1>>, {
2081    let mut stateless = host.stateless;
2082    match result {
2083        Ok(ExecutionOutcome::Success {
2084            result,
2085            ..
2086        }) => {
2087            let remaining_energy = host.energy;
2088            if let Some(Value::I32(n)) = result {
2089                if n >= 0 {
2090                    Ok(ReceiveResult::Success {
2091                        logs: stateless.logs,
2092                        state_changed: host.state.changed,
2093                        return_value: stateless.return_value,
2094                        remaining_energy,
2095                        trace: host.trace,
2096                    })
2097                } else {
2098                    let (reason, trace) = reason_from_wasm_error_code(n, host.trace)?;
2099                    Ok(ReceiveResult::Reject {
2100                        reason,
2101                        return_value: stateless.return_value,
2102                        remaining_energy,
2103                        trace,
2104                    })
2105                }
2106            } else {
2107                Err(InvalidReturnCodeError {
2108                    value:       None,
2109                    debug_trace: host.trace,
2110                })
2111            }
2112        }
2113        Ok(ExecutionOutcome::Interrupted {
2114            reason,
2115            config,
2116        }) => {
2117            let remaining_energy = host.energy;
2118            // Logs are returned per section that is executed.
2119            // So here we set the host logs to empty and return any
2120            // existing logs.
2121            let logs = if reason.should_clear_logs() {
2122                std::mem::take(&mut stateless.logs)
2123            } else {
2124                v0::Logs::new()
2125            };
2126            let state_changed = host.state.changed;
2127            let trace = host.trace;
2128            let host = SavedHost {
2129                stateless:          stateless.into(),
2130                current_generation: host.state.current_generation,
2131                entry_mapping:      host.state.entry_mapping,
2132                iterators:          host.state.iterators,
2133            };
2134            Ok(ReceiveResult::Interrupt {
2135                remaining_energy,
2136                state_changed,
2137                logs,
2138                config: Box::new(ReceiveInterruptedState {
2139                    host,
2140                    artifact: artifact.into(),
2141                    config,
2142                }),
2143                interrupt: reason,
2144                trace,
2145            })
2146        }
2147        Err(error) => {
2148            if error.downcast_ref::<OutOfEnergy>().is_some() {
2149                Ok(ReceiveResult::OutOfEnergy {
2150                    trace: host.trace,
2151                })
2152            } else {
2153                Ok(ReceiveResult::Trap {
2154                    error,
2155                    remaining_energy: host.energy,
2156                    trace: host.trace,
2157                })
2158            }
2159        }
2160    }
2161}
2162
2163/// Runtime parameters that affect the limits placed on the
2164/// entrypoint execution.
2165#[derive(Debug, Clone, Copy)]
2166pub struct ReceiveParams {
2167    /// Maximum size of a parameter that an `invoke` operation can have.
2168    pub max_parameter_size:                  usize,
2169    /// Whether the amount of logs a contract may produce, and the size of the
2170    /// logs, is limited.
2171    pub limit_logs_and_return_values:        bool,
2172    /// Whether queries should be supported or not. Queries were introduced in
2173    /// protocol 5.
2174    pub support_queries:                     bool,
2175    /// Whether querying account public keys and checking account signatures is
2176    /// supported.
2177    pub support_account_signature_checks:    bool,
2178    /// Whether queries for inspecting a smart contract's module reference and
2179    /// contract name should be supported or not. These queries were introduced
2180    /// in protocol 7.
2181    pub support_contract_inspection_queries: bool,
2182}
2183
2184impl ReceiveParams {
2185    /// Parameters that are in effect in protocol version 4.
2186    pub fn new_p4() -> Self {
2187        Self {
2188            max_parameter_size:                  1024,
2189            limit_logs_and_return_values:        true,
2190            support_queries:                     false,
2191            support_account_signature_checks:    false,
2192            support_contract_inspection_queries: false,
2193        }
2194    }
2195
2196    /// Parameters that are in effect in protocol version 5.
2197    pub fn new_p5() -> Self {
2198        Self {
2199            max_parameter_size:                  u16::MAX.into(),
2200            limit_logs_and_return_values:        false,
2201            support_queries:                     true,
2202            support_account_signature_checks:    false,
2203            support_contract_inspection_queries: false,
2204        }
2205    }
2206
2207    /// Parameters that are in effect in protocol version 6.
2208    pub fn new_p6() -> Self {
2209        Self {
2210            max_parameter_size:                  u16::MAX.into(),
2211            limit_logs_and_return_values:        false,
2212            support_queries:                     true,
2213            support_account_signature_checks:    true,
2214            support_contract_inspection_queries: false,
2215        }
2216    }
2217
2218    /// Parameters that are in effect in protocol version 7 and up.
2219    pub fn new_p7() -> Self {
2220        Self {
2221            max_parameter_size:                  u16::MAX.into(),
2222            limit_logs_and_return_values:        false,
2223            support_queries:                     true,
2224            support_account_signature_checks:    true,
2225            support_contract_inspection_queries: true,
2226        }
2227    }
2228}
2229
2230/// Collection of information relevant to invoke a receive-function.
2231#[derive(Debug)]
2232pub struct ReceiveInvocation<'a> {
2233    /// The amount included in the transaction.
2234    pub amount:       Amount,
2235    /// The name of the receive function to invoke.
2236    pub receive_name: ReceiveName<'a>,
2237    /// A parameter to provide the receive function.
2238    pub parameter:    ParameterRef<'a>,
2239    /// The limit on the energy to be used for execution.
2240    pub energy:       InterpreterEnergy,
2241}
2242
2243/// Invokes a receive-function from a given [artifact](Artifact).
2244pub fn invoke_receive<
2245    BackingStore: BackingStoreLoad,
2246    R1: RunnableCode,
2247    R2: RunnableCode,
2248    Art: Borrow<Artifact<ProcessedImports, R1>> + Into<Arc<Artifact<ProcessedImports, R2>>>,
2249    Ctx1: HasReceiveContext,
2250    Ctx2: From<Ctx1>,
2251    A: DebugInfo,
2252>(
2253    artifact: Art,
2254    receive_ctx: Ctx1,
2255    receive_invocation: ReceiveInvocation,
2256    instance_state: InstanceState<BackingStore>,
2257    params: ReceiveParams,
2258) -> InvokeResult<ReceiveResult<R2, A, Ctx2>, A> {
2259    let mut host = ReceiveHost {
2260        energy:    receive_invocation.energy,
2261        stateless: StateLessReceiveHost {
2262            activation_frames: constants::MAX_ACTIVATION_FRAMES,
2263            logs: v0::Logs::new(),
2264            return_value: Vec::new(),
2265            parameters: vec![receive_invocation.parameter],
2266            receive_ctx,
2267            params,
2268        },
2269        state:     instance_state,
2270        trace:     A::empty_trace(),
2271    };
2272
2273    let result =
2274        artifact.borrow().run(&mut host, receive_invocation.receive_name.get_chain_name(), &[
2275            Value::I64(receive_invocation.amount.micro_ccd() as i64),
2276        ]);
2277    process_receive_result(artifact, host, result)
2278}
2279
2280pub type ResumeResult<A, Debug> = Result<A, ResumeError<Debug>>;
2281
2282#[derive(Debug, thiserror::Error)]
2283pub enum ResumeError<Debug> {
2284    /// There have been too many interrupts during this contract execution.
2285    #[error("Too many interrupts in a contract call.")]
2286    TooManyInterrupts,
2287    #[error("Invalid return value from a contract call: {error:?}")]
2288    InvalidReturn {
2289        #[from]
2290        error: InvalidReturnCodeError<Debug>,
2291    },
2292}
2293
2294impl<R, Debug: DebugInfo, Ctx> From<ResumeError<Debug>> for types::ReceiveResult<R, Debug, Ctx> {
2295    fn from(value: ResumeError<Debug>) -> Self {
2296        match value {
2297            ResumeError::TooManyInterrupts => {
2298                Self::Trap {
2299                    error:            anyhow::anyhow!("Too many interrupts in a contract call."),
2300                    remaining_energy: 0.into(), /* Protocol violations lead to consuming all
2301                                                 * energy. */
2302                    trace:            Debug::empty_trace(), // nothing was executed, so no trace.
2303                }
2304            }
2305            ResumeError::InvalidReturn {
2306                error,
2307            } => error.into(),
2308        }
2309    }
2310}
2311
2312/// Resume execution of the receive method after handling the interrupt.
2313///
2314/// The arguments are as follows
2315///
2316/// - `interrupted_state` is the state of execution that is captured when we
2317///   started handling the interrupt
2318/// - `response` is the response from the operation that was invoked
2319/// - `energy` is the remaning energy left for execution
2320/// - `state_trie` is the current state of the contract instance, **after**
2321///   handling the interrupt
2322/// - `state_updated` indicates whether the state of the instance has changed
2323///   during handling of the operation. This can currently only happen if there
2324///   is re-entrancy, i.e., if during handling of the interrupt the instance
2325///   that invoked it is itself again invoked. Note that this indicates only
2326///   **state changes**. Amount changes are no reflected in this.
2327/// - `backing_store` gives access to any on-disk storage for the instance
2328///   state.
2329pub fn resume_receive<BackingStore: BackingStoreLoad, A: DebugInfo>(
2330    interrupted_state: Box<ReceiveInterruptedState<CompiledFunction>>,
2331    response: InvokeResponse,  // response from the call
2332    energy: InterpreterEnergy, // remaining energy for execution
2333    state_trie: &mut trie::MutableState,
2334    state_updated: bool,
2335    mut backing_store: BackingStore,
2336) -> ResumeResult<ReceiveResult<CompiledFunction, A>, A> {
2337    let inner = state_trie.get_inner(&mut backing_store);
2338    let state = InstanceState::migrate(
2339        state_updated,
2340        interrupted_state.host.current_generation,
2341        interrupted_state.host.entry_mapping,
2342        interrupted_state.host.iterators,
2343        backing_store,
2344        inner,
2345    );
2346    let mut host = ReceiveHost {
2347        stateless: interrupted_state.host.stateless,
2348        energy,
2349        state,
2350        trace: A::empty_trace(),
2351    };
2352    let response = match response {
2353        InvokeResponse::Success {
2354            new_balance,
2355            data,
2356        } => {
2357            host.stateless.receive_ctx.common.self_balance = new_balance;
2358            // the response value is constructed by setting the last 5 bytes to 0
2359            // for the first 3 bytes, the first bit is 1 if the state changed, and 0
2360            // otherwise the remaining bits are the index of the parameter.
2361            let tag = if state_updated {
2362                0b1000_0000_0000_0000_0000_0000u64
2363            } else {
2364                0
2365            };
2366            if let Some(data) = data {
2367                let len = host.stateless.parameters.len();
2368                if len > 0b0111_1111_1111_1111_1111_1111 {
2369                    return Err(ResumeError::TooManyInterrupts);
2370                }
2371                host.stateless.parameters.push(data);
2372                // return the index of the parameter to retrieve.
2373                (len as u64 | tag) << 40
2374            } else {
2375                // modulo the tag, 0 indicates that there is no new response. This works
2376                // because if there is a response
2377                // len must be at least 1 since every contract starts by being
2378                // called with a parameter
2379                tag << 40
2380            }
2381        }
2382        InvokeResponse::Failure {
2383            kind,
2384        } => kind.encode_as_u64(&mut host.stateless.parameters)?,
2385    };
2386    // push the response from the invoke
2387    let mut config = interrupted_state.config;
2388    config.push_value(response);
2389    let result = interrupted_state.artifact.run_config(&mut host, config);
2390    let r = process_receive_result(interrupted_state.artifact, host, result)?;
2391    Ok(r)
2392}
2393
2394/// Returns the passed Wasm error code if it is negative.
2395/// This function should only be called on negative numbers.
2396fn reason_from_wasm_error_code<A>(
2397    n: i32,
2398    debug_trace: A,
2399) -> Result<(i32, A), InvalidReturnCodeError<A>> {
2400    if n < 0 {
2401        Ok((n, debug_trace))
2402    } else {
2403        Err(InvalidReturnCodeError {
2404            value: Some(n),
2405            debug_trace,
2406        })
2407    }
2408}
2409
2410/// Invokes a receive-function from a given **serialized** artifact.
2411#[cfg_attr(not(feature = "fuzz-coverage"), inline)]
2412pub fn invoke_receive_from_artifact<
2413    'a,
2414    BackingStore: BackingStoreLoad,
2415    Ctx1: HasReceiveContext,
2416    Ctx2: From<Ctx1>,
2417    A: DebugInfo,
2418>(
2419    ctx: InvokeFromArtifactCtx<'a>,
2420    receive_ctx: Ctx1,
2421    receive_name: ReceiveName,
2422    instance_state: InstanceState<BackingStore>,
2423    params: ReceiveParams,
2424) -> ExecResult<ReceiveResult<CompiledFunctionBytes<'a>, A, Ctx2>> {
2425    let artifact = utils::parse_artifact(ctx.artifact)?;
2426    let r = invoke_receive(
2427        Arc::new(artifact),
2428        receive_ctx,
2429        ReceiveInvocation {
2430            energy: ctx.energy,
2431            parameter: ctx.parameter,
2432            receive_name,
2433            amount: ctx.amount,
2434        },
2435        instance_state,
2436        params,
2437    )?;
2438    Ok(r)
2439}
2440
2441/// Invokes a receive-function from a given **serialized** Wasm module.
2442#[cfg_attr(not(feature = "fuzz-coverage"), inline)]
2443pub fn invoke_receive_from_source<
2444    BackingStore: BackingStoreLoad,
2445    Ctx1: HasReceiveContext,
2446    Ctx2: From<Ctx1>,
2447    A: DebugInfo,
2448>(
2449    validation_config: ValidationConfig,
2450    ctx: InvokeFromSourceCtx,
2451    receive_ctx: Ctx1,
2452    receive_name: ReceiveName,
2453    instance_state: InstanceState<BackingStore>,
2454    params: ReceiveParams,
2455) -> ExecResult<ReceiveResult<CompiledFunction, A, Ctx2>> {
2456    let artifact = utils::instantiate(
2457        validation_config,
2458        &ConcordiumAllowedImports {
2459            support_upgrade: ctx.support_upgrade,
2460            enable_debug:    A::ENABLE_DEBUG,
2461        },
2462        ctx.source,
2463    )?
2464    .artifact;
2465    let r = invoke_receive(
2466        Arc::new(artifact),
2467        receive_ctx,
2468        ReceiveInvocation {
2469            amount: ctx.amount,
2470            receive_name,
2471            parameter: ctx.parameter,
2472            energy: ctx.energy,
2473        },
2474        instance_state,
2475        params,
2476    )?;
2477    Ok(r)
2478}
2479
2480/// Invokes a receive-function from a given **serialized** Wasm module. Before
2481/// execution the Wasm module is injected with cost metering.
2482#[cfg_attr(not(feature = "fuzz-coverage"), inline)]
2483pub fn invoke_receive_with_metering_from_source<
2484    BackingStore: BackingStoreLoad,
2485    Ctx1: HasReceiveContext,
2486    Ctx2: From<Ctx1>,
2487    A: DebugInfo,
2488>(
2489    validation_config: ValidationConfig,
2490    cost_config: impl CostConfiguration,
2491    ctx: InvokeFromSourceCtx,
2492    receive_ctx: Ctx1,
2493    receive_name: ReceiveName,
2494    instance_state: InstanceState<BackingStore>,
2495    params: ReceiveParams,
2496) -> ExecResult<ReceiveResult<CompiledFunction, A, Ctx2>> {
2497    let artifact = utils::instantiate_with_metering(
2498        validation_config,
2499        cost_config,
2500        &ConcordiumAllowedImports {
2501            support_upgrade: ctx.support_upgrade,
2502            enable_debug:    A::ENABLE_DEBUG,
2503        },
2504        ctx.source,
2505    )?
2506    .artifact;
2507    let r = invoke_receive(
2508        Arc::new(artifact),
2509        receive_ctx,
2510        ReceiveInvocation {
2511            amount: ctx.amount,
2512            receive_name,
2513            parameter: ctx.parameter,
2514            energy: ctx.energy,
2515        },
2516        instance_state,
2517        params,
2518    )?;
2519    Ok(r)
2520}