casper_execution_engine/runtime/
externals.rs

1use std::{
2    collections::{BTreeMap, BTreeSet},
3    convert::TryFrom,
4};
5
6use casper_wasmi::{Externals, RuntimeArgs, RuntimeValue, Trap};
7
8use casper_storage::global_state::{error::Error as GlobalStateError, state::StateReader};
9use casper_types::{
10    account::AccountHash,
11    addressable_entity::{EntityEntryPoint, EntryPoints},
12    api_error,
13    bytesrepr::{self, ToBytes},
14    contract_messages::MessageTopicOperation,
15    contracts::{ContractPackageHash, EntryPoints as ContractEntryPoints, NamedKeys},
16    AddressableEntityHash, ApiError, EntityVersion, Gas, Group, HashAlgorithm, HostFunction,
17    HostFunctionCost, Key, PackageHash, PackageStatus, PublicKey, Signature, StoredValue, URef,
18    U512, UREF_SERIALIZED_LENGTH,
19};
20
21use super::{args::Args, ExecError, Runtime};
22use crate::{resolvers::v1_function_index::FunctionIndex, runtime::cryptography};
23
24impl<R> Externals for Runtime<'_, R>
25where
26    R: StateReader<Key, StoredValue, Error = GlobalStateError>,
27{
28    fn invoke_index(
29        &mut self,
30        index: usize,
31        args: RuntimeArgs,
32    ) -> Result<Option<RuntimeValue>, Trap> {
33        let func = FunctionIndex::try_from(index).expect("unknown function index");
34
35        let host_function_costs =
36            (*self.context.engine_config().wasm_config().v1()).take_host_function_costs();
37
38        match func {
39            FunctionIndex::ReadFuncIndex => {
40                // args(0) = pointer to key in Wasm memory
41                // args(1) = size of key in Wasm memory
42                // args(2) = pointer to output size (output param)
43                let (key_ptr, key_size, output_size_ptr) = Args::parse(args)?;
44                self.charge_host_function_call(
45                    &host_function_costs.read_value,
46                    [key_ptr, key_size, output_size_ptr],
47                )?;
48                let ret = self.read(key_ptr, key_size, output_size_ptr)?;
49                Ok(Some(RuntimeValue::I32(api_error::i32_from(ret))))
50            }
51
52            FunctionIndex::LoadNamedKeysFuncIndex => {
53                // args(0) = pointer to amount of keys (output)
54                // args(1) = pointer to amount of serialized bytes (output)
55                let (total_keys_ptr, result_size_ptr) = Args::parse(args)?;
56                self.charge_host_function_call(
57                    &host_function_costs.load_named_keys,
58                    [total_keys_ptr, result_size_ptr],
59                )?;
60                let ret = self.load_named_keys(total_keys_ptr, result_size_ptr)?;
61                Ok(Some(RuntimeValue::I32(api_error::i32_from(ret))))
62            }
63
64            FunctionIndex::WriteFuncIndex => {
65                // args(0) = pointer to key in Wasm memory
66                // args(1) = size of key
67                // args(2) = pointer to value
68                // args(3) = size of value
69                let (key_ptr, key_size, value_ptr, value_size) = Args::parse(args)?;
70                self.charge_host_function_call(
71                    &host_function_costs.write,
72                    [key_ptr, key_size, value_ptr, value_size],
73                )?;
74                self.write(key_ptr, key_size, value_ptr, value_size)?;
75                Ok(None)
76            }
77
78            FunctionIndex::AddFuncIndex => {
79                // args(0) = pointer to key in Wasm memory
80                // args(1) = size of key
81                // args(2) = pointer to value
82                // args(3) = size of value
83                let (key_ptr, key_size, value_ptr, value_size) = Args::parse(args)?;
84                self.charge_host_function_call(
85                    &host_function_costs.add,
86                    [key_ptr, key_size, value_ptr, value_size],
87                )?;
88                self.add(key_ptr, key_size, value_ptr, value_size)?;
89                Ok(None)
90            }
91
92            FunctionIndex::NewFuncIndex => {
93                // args(0) = pointer to uref destination in Wasm memory
94                // args(1) = pointer to initial value
95                // args(2) = size of initial value
96                let (uref_ptr, value_ptr, value_size) = Args::parse(args)?;
97                self.charge_host_function_call(
98                    &host_function_costs.new_uref,
99                    [uref_ptr, value_ptr, value_size],
100                )?;
101                self.new_uref(uref_ptr, value_ptr, value_size)?;
102                Ok(None)
103            }
104
105            FunctionIndex::RetFuncIndex => {
106                // args(0) = pointer to value
107                // args(1) = size of value
108                let (value_ptr, value_size) = Args::parse(args)?;
109                self.charge_host_function_call(&host_function_costs.ret, [value_ptr, value_size])?;
110                Err(self.ret(value_ptr, value_size as usize))
111            }
112
113            FunctionIndex::GetKeyFuncIndex => {
114                // args(0) = pointer to key name in Wasm memory
115                // args(1) = size of key name
116                // args(2) = pointer to output buffer for serialized key
117                // args(3) = size of output buffer
118                // args(4) = pointer to bytes written
119                let (name_ptr, name_size, output_ptr, output_size, bytes_written) =
120                    Args::parse(args)?;
121                self.charge_host_function_call(
122                    &host_function_costs.get_key,
123                    [name_ptr, name_size, output_ptr, output_size, bytes_written],
124                )?;
125                let ret = self.load_key(
126                    name_ptr,
127                    name_size,
128                    output_ptr,
129                    output_size as usize,
130                    bytes_written,
131                )?;
132                Ok(Some(RuntimeValue::I32(api_error::i32_from(ret))))
133            }
134
135            FunctionIndex::HasKeyFuncIndex => {
136                // args(0) = pointer to key name in Wasm memory
137                // args(1) = size of key name
138                let (name_ptr, name_size) = Args::parse(args)?;
139                self.charge_host_function_call(
140                    &host_function_costs.has_key,
141                    [name_ptr, name_size],
142                )?;
143                let result = self.has_key(name_ptr, name_size)?;
144                Ok(Some(RuntimeValue::I32(result)))
145            }
146
147            FunctionIndex::PutKeyFuncIndex => {
148                // args(0) = pointer to key name in Wasm memory
149                // args(1) = size of key name
150                // args(2) = pointer to key in Wasm memory
151                // args(3) = size of key
152                let (name_ptr, name_size, key_ptr, key_size) = Args::parse(args)?;
153                self.charge_host_function_call(
154                    &host_function_costs.put_key,
155                    [name_ptr, name_size, key_ptr, key_size],
156                )?;
157                self.put_key(name_ptr, name_size, key_ptr, key_size)?;
158                Ok(None)
159            }
160
161            FunctionIndex::RemoveKeyFuncIndex => {
162                // args(0) = pointer to key name in Wasm memory
163                // args(1) = size of key name
164                let (name_ptr, name_size) = Args::parse(args)?;
165                self.charge_host_function_call(
166                    &host_function_costs.remove_key,
167                    [name_ptr, name_size],
168                )?;
169                self.remove_key(name_ptr, name_size)?;
170                Ok(None)
171            }
172
173            FunctionIndex::GetCallerIndex => {
174                // args(0) = pointer where a size of serialized bytes will be stored
175                let (output_size_ptr,) = Args::parse(args)?;
176                self.charge_host_function_call(&host_function_costs.get_caller, [output_size_ptr])?;
177                let ret = self.get_caller(output_size_ptr)?;
178                Ok(Some(RuntimeValue::I32(api_error::i32_from(ret))))
179            }
180
181            FunctionIndex::GetBlocktimeIndex => {
182                // args(0) = pointer to Wasm memory where to write.
183                let (dest_ptr,) = Args::parse(args)?;
184                self.charge_host_function_call(&host_function_costs.get_blocktime, [dest_ptr])?;
185                self.get_blocktime(dest_ptr)?;
186                Ok(None)
187            }
188
189            FunctionIndex::GasFuncIndex => {
190                let (gas_arg,): (u32,) = Args::parse(args)?;
191                // Gas is special cased internal host function and for accounting purposes it isn't
192                // represented in protocol data.
193                self.gas(Gas::new(gas_arg))?;
194                Ok(None)
195            }
196
197            FunctionIndex::IsValidURefFnIndex => {
198                // args(0) = pointer to value to validate
199                // args(1) = size of value
200                let (uref_ptr, uref_size) = Args::parse(args)?;
201                self.charge_host_function_call(
202                    &host_function_costs.is_valid_uref,
203                    [uref_ptr, uref_size],
204                )?;
205                Ok(Some(RuntimeValue::I32(i32::from(
206                    self.is_valid_uref(uref_ptr, uref_size)?,
207                ))))
208            }
209
210            FunctionIndex::RevertFuncIndex => {
211                // args(0) = status u32
212                let (status,) = Args::parse(args)?;
213                self.charge_host_function_call(&host_function_costs.revert, [status])?;
214                Err(self.revert(status))
215            }
216
217            FunctionIndex::AddAssociatedKeyFuncIndex => {
218                // args(0) = pointer to array of bytes of an account hash
219                // args(1) = size of an account hash
220                // args(2) = weight of the key
221                let (account_hash_ptr, account_hash_size, weight_value) = Args::parse(args)?;
222                self.charge_host_function_call(
223                    &host_function_costs.add_associated_key,
224                    [
225                        account_hash_ptr,
226                        account_hash_size,
227                        weight_value as HostFunctionCost,
228                    ],
229                )?;
230                let value = self.add_associated_key(
231                    account_hash_ptr,
232                    account_hash_size as usize,
233                    weight_value,
234                )?;
235                Ok(Some(RuntimeValue::I32(value)))
236            }
237
238            FunctionIndex::RemoveAssociatedKeyFuncIndex => {
239                // args(0) = pointer to array of bytes of an account hash
240                // args(1) = size of an account hash
241                let (account_hash_ptr, account_hash_size) = Args::parse(args)?;
242                self.charge_host_function_call(
243                    &host_function_costs.remove_associated_key,
244                    [account_hash_ptr, account_hash_size],
245                )?;
246                let value =
247                    self.remove_associated_key(account_hash_ptr, account_hash_size as usize)?;
248                Ok(Some(RuntimeValue::I32(value)))
249            }
250
251            FunctionIndex::UpdateAssociatedKeyFuncIndex => {
252                // args(0) = pointer to array of bytes of an account hash
253                // args(1) = size of an account hash
254                // args(2) = weight of the key
255                let (account_hash_ptr, account_hash_size, weight_value) = Args::parse(args)?;
256                self.charge_host_function_call(
257                    &host_function_costs.update_associated_key,
258                    [
259                        account_hash_ptr,
260                        account_hash_size,
261                        weight_value as HostFunctionCost,
262                    ],
263                )?;
264                let value = self.update_associated_key(
265                    account_hash_ptr,
266                    account_hash_size as usize,
267                    weight_value,
268                )?;
269                Ok(Some(RuntimeValue::I32(value)))
270            }
271
272            FunctionIndex::SetActionThresholdFuncIndex => {
273                // args(0) = action type
274                // args(1) = new threshold
275                let (action_type_value, threshold_value) = Args::parse(args)?;
276                self.charge_host_function_call(
277                    &host_function_costs.set_action_threshold,
278                    [action_type_value, threshold_value as HostFunctionCost],
279                )?;
280                let value = self.set_action_threshold(action_type_value, threshold_value)?;
281                Ok(Some(RuntimeValue::I32(value)))
282            }
283
284            FunctionIndex::CreatePurseIndex => {
285                // args(0) = pointer to array for return value
286                // args(1) = length of array for return value
287                let (dest_ptr, dest_size) = Args::parse(args)?;
288
289                self.charge_host_function_call(
290                    &host_function_costs.create_purse,
291                    [dest_ptr, dest_size],
292                )?;
293
294                let result = if (dest_size as usize) < UREF_SERIALIZED_LENGTH {
295                    Err(ApiError::PurseNotCreated)
296                } else {
297                    let purse = self.create_purse()?;
298                    let purse_bytes = purse.into_bytes().map_err(ExecError::BytesRepr)?;
299                    self.try_get_memory()?
300                        .set(dest_ptr, &purse_bytes)
301                        .map_err(|e| ExecError::Interpreter(e.into()))?;
302                    Ok(())
303                };
304
305                Ok(Some(RuntimeValue::I32(api_error::i32_from(result))))
306            }
307
308            FunctionIndex::TransferToAccountIndex => {
309                // args(0) = pointer to array of bytes of an account hash
310                // args(1) = length of array of bytes of an account hash
311                // args(2) = pointer to array of bytes of an amount
312                // args(3) = length of array of bytes of an amount
313                // args(4) = pointer to array of bytes of an id
314                // args(5) = length of array of bytes of an id
315                // args(6) = pointer to a value where new value will be set
316                let (key_ptr, key_size, amount_ptr, amount_size, id_ptr, id_size, result_ptr) =
317                    Args::parse(args)?;
318                self.charge_host_function_call(
319                    &host_function_costs.transfer_to_account,
320                    [
321                        key_ptr,
322                        key_size,
323                        amount_ptr,
324                        amount_size,
325                        id_ptr,
326                        id_size,
327                        result_ptr,
328                    ],
329                )?;
330                let account_hash: AccountHash = {
331                    let bytes = self.bytes_from_mem(key_ptr, key_size as usize)?;
332                    bytesrepr::deserialize_from_slice(bytes).map_err(ExecError::BytesRepr)?
333                };
334                let amount: U512 = {
335                    let bytes = self.bytes_from_mem(amount_ptr, amount_size as usize)?;
336                    bytesrepr::deserialize_from_slice(bytes).map_err(ExecError::BytesRepr)?
337                };
338                let id: Option<u64> = {
339                    let bytes = self.bytes_from_mem(id_ptr, id_size as usize)?;
340                    bytesrepr::deserialize_from_slice(bytes).map_err(ExecError::BytesRepr)?
341                };
342
343                let ret = match self.transfer_to_account(account_hash, amount, id)? {
344                    Ok(transferred_to) => {
345                        let result_value: u32 = transferred_to as u32;
346                        let result_value_bytes = result_value.to_le_bytes();
347                        self.try_get_memory()?
348                            .set(result_ptr, &result_value_bytes)
349                            .map_err(|error| ExecError::Interpreter(error.into()))?;
350                        Ok(())
351                    }
352                    Err(api_error) => Err(api_error),
353                };
354                Ok(Some(RuntimeValue::I32(api_error::i32_from(ret))))
355            }
356
357            FunctionIndex::TransferFromPurseToAccountIndex => {
358                // args(0) = pointer to array of bytes in Wasm memory of a source purse
359                // args(1) = length of array of bytes in Wasm memory of a source purse
360                // args(2) = pointer to array of bytes in Wasm memory of an account hash
361                // args(3) = length of array of bytes in Wasm memory of an account hash
362                // args(4) = pointer to array of bytes in Wasm memory of an amount
363                // args(5) = length of array of bytes in Wasm memory of an amount
364                // args(6) = pointer to array of bytes in Wasm memory of an id
365                // args(7) = length of array of bytes in Wasm memory of an id
366                // args(8) = pointer to a value where value of `TransferredTo` enum will be set
367                let (
368                    source_ptr,
369                    source_size,
370                    key_ptr,
371                    key_size,
372                    amount_ptr,
373                    amount_size,
374                    id_ptr,
375                    id_size,
376                    result_ptr,
377                ) = Args::parse(args)?;
378                self.charge_host_function_call(
379                    &host_function_costs.transfer_from_purse_to_account,
380                    [
381                        source_ptr,
382                        source_size,
383                        key_ptr,
384                        key_size,
385                        amount_ptr,
386                        amount_size,
387                        id_ptr,
388                        id_size,
389                        result_ptr,
390                    ],
391                )?;
392                let source_purse = {
393                    let bytes = self.bytes_from_mem(source_ptr, source_size as usize)?;
394                    bytesrepr::deserialize_from_slice(bytes).map_err(ExecError::BytesRepr)?
395                };
396                let account_hash: AccountHash = {
397                    let bytes = self.bytes_from_mem(key_ptr, key_size as usize)?;
398                    bytesrepr::deserialize_from_slice(bytes).map_err(ExecError::BytesRepr)?
399                };
400                let amount: U512 = {
401                    let bytes = self.bytes_from_mem(amount_ptr, amount_size as usize)?;
402                    bytesrepr::deserialize_from_slice(bytes).map_err(ExecError::BytesRepr)?
403                };
404                let id: Option<u64> = {
405                    let bytes = self.bytes_from_mem(id_ptr, id_size as usize)?;
406                    bytesrepr::deserialize_from_slice(bytes).map_err(ExecError::BytesRepr)?
407                };
408                let ret = match self.transfer_from_purse_to_account_hash(
409                    source_purse,
410                    account_hash,
411                    amount,
412                    id,
413                )? {
414                    Ok(transferred_to) => {
415                        let result_value: u32 = transferred_to as u32;
416                        let result_value_bytes = result_value.to_le_bytes();
417                        self.try_get_memory()?
418                            .set(result_ptr, &result_value_bytes)
419                            .map_err(|error| ExecError::Interpreter(error.into()))?;
420                        Ok(())
421                    }
422                    Err(api_error) => Err(api_error),
423                };
424                Ok(Some(RuntimeValue::I32(api_error::i32_from(ret))))
425            }
426
427            FunctionIndex::TransferFromPurseToPurseIndex => {
428                // args(0) = pointer to array of bytes in Wasm memory of a source purse
429                // args(1) = length of array of bytes in Wasm memory of a source purse
430                // args(2) = pointer to array of bytes in Wasm memory of a target purse
431                // args(3) = length of array of bytes in Wasm memory of a target purse
432                // args(4) = pointer to array of bytes in Wasm memory of an amount
433                // args(5) = length of array of bytes in Wasm memory of an amount
434                // args(6) = pointer to array of bytes in Wasm memory of an id
435                // args(7) = length of array of bytes in Wasm memory of an id
436                let (
437                    source_ptr,
438                    source_size,
439                    target_ptr,
440                    target_size,
441                    amount_ptr,
442                    amount_size,
443                    id_ptr,
444                    id_size,
445                ) = Args::parse(args)?;
446                self.charge_host_function_call(
447                    &host_function_costs.transfer_from_purse_to_purse,
448                    [
449                        source_ptr,
450                        source_size,
451                        target_ptr,
452                        target_size,
453                        amount_ptr,
454                        amount_size,
455                        id_ptr,
456                        id_size,
457                    ],
458                )?;
459
460                let source: URef = {
461                    let bytes = self.bytes_from_mem(source_ptr, source_size as usize)?;
462                    bytesrepr::deserialize_from_slice(bytes).map_err(ExecError::BytesRepr)?
463                };
464
465                let target: URef = {
466                    let bytes = self.bytes_from_mem(target_ptr, target_size as usize)?;
467                    bytesrepr::deserialize_from_slice(bytes).map_err(ExecError::BytesRepr)?
468                };
469
470                let amount: U512 = {
471                    let bytes = self.bytes_from_mem(amount_ptr, amount_size as usize)?;
472                    bytesrepr::deserialize_from_slice(bytes).map_err(ExecError::BytesRepr)?
473                };
474
475                let id: Option<u64> = {
476                    let bytes = self.bytes_from_mem(id_ptr, id_size as usize)?;
477                    bytesrepr::deserialize_from_slice(bytes).map_err(ExecError::BytesRepr)?
478                };
479
480                let ret = self.transfer_from_purse_to_purse(source, target, amount, id)?;
481                Ok(Some(RuntimeValue::I32(api_error::i32_from(ret))))
482            }
483
484            FunctionIndex::GetBalanceIndex => {
485                // args(0) = pointer to purse input
486                // args(1) = length of purse
487                // args(2) = pointer to output size (output)
488                let (ptr, ptr_size, output_size_ptr) = Args::parse(args)?;
489                self.charge_host_function_call(
490                    &host_function_costs.get_balance,
491                    [ptr, ptr_size, output_size_ptr],
492                )?;
493                let ret = self.get_balance_host_buffer(ptr, ptr_size as usize, output_size_ptr)?;
494                Ok(Some(RuntimeValue::I32(api_error::i32_from(ret))))
495            }
496
497            FunctionIndex::GetPhaseIndex => {
498                // args(0) = pointer to Wasm memory where to write.
499                let (dest_ptr,) = Args::parse(args)?;
500                self.charge_host_function_call(&host_function_costs.get_phase, [dest_ptr])?;
501                self.get_phase(dest_ptr)?;
502                Ok(None)
503            }
504
505            FunctionIndex::GetSystemContractIndex => {
506                // args(0) = system contract index
507                // args(1) = dest pointer for storing serialized result
508                // args(2) = dest pointer size
509                let (system_contract_index, dest_ptr, dest_size) = Args::parse(args)?;
510                self.charge_host_function_call(
511                    &host_function_costs.get_system_contract,
512                    [system_contract_index, dest_ptr, dest_size],
513                )?;
514                let ret = self.get_system_contract(system_contract_index, dest_ptr, dest_size)?;
515                Ok(Some(RuntimeValue::I32(api_error::i32_from(ret))))
516            }
517
518            FunctionIndex::GetMainPurseIndex => {
519                // args(0) = pointer to Wasm memory where to write.
520                let (dest_ptr,) = Args::parse(args)?;
521                self.charge_host_function_call(&host_function_costs.get_main_purse, [dest_ptr])?;
522                self.get_main_purse(dest_ptr)?;
523                Ok(None)
524            }
525
526            FunctionIndex::ReadHostBufferIndex => {
527                // args(0) = pointer to Wasm memory where to write size.
528                let (dest_ptr, dest_size, bytes_written_ptr) = Args::parse(args)?;
529                self.charge_host_function_call(
530                    &host_function_costs.read_host_buffer,
531                    [dest_ptr, dest_size, bytes_written_ptr],
532                )?;
533                let ret = self.read_host_buffer(dest_ptr, dest_size as usize, bytes_written_ptr)?;
534                Ok(Some(RuntimeValue::I32(api_error::i32_from(ret))))
535            }
536
537            FunctionIndex::CreateContractPackageAtHash => {
538                // args(0) = pointer to wasm memory where to write 32-byte Hash address
539                // args(1) = pointer to wasm memory where to write 32-byte access key address
540                // args(2) = boolean flag to determine if the contract can be versioned
541                let (hash_dest_ptr, access_dest_ptr, is_locked) = Args::parse(args)?;
542                self.charge_host_function_call(
543                    &host_function_costs.create_contract_package_at_hash,
544                    [hash_dest_ptr, access_dest_ptr],
545                )?;
546                let package_status = PackageStatus::new(is_locked);
547                let (hash_addr, access_addr) =
548                    self.create_contract_package_at_hash(package_status)?;
549
550                self.function_address(hash_addr, hash_dest_ptr)?;
551                self.function_address(access_addr, access_dest_ptr)?;
552                Ok(None)
553            }
554
555            FunctionIndex::CreateContractUserGroup => {
556                // args(0) = pointer to package key in wasm memory
557                // args(1) = size of package key in wasm memory
558                // args(2) = pointer to group label in wasm memory
559                // args(3) = size of group label in wasm memory
560                // args(4) = number of new urefs to generate for the group
561                // args(5) = pointer to existing_urefs in wasm memory
562                // args(6) = size of existing_urefs in wasm memory
563                // args(7) = pointer to location to write size of output (written to host buffer)
564                let (
565                    package_key_ptr,
566                    package_key_size,
567                    label_ptr,
568                    label_size,
569                    num_new_urefs,
570                    existing_urefs_ptr,
571                    existing_urefs_size,
572                    output_size_ptr,
573                ) = Args::parse(args)?;
574
575                self.charge_host_function_call(
576                    &host_function_costs.create_contract_user_group,
577                    [
578                        package_key_ptr,
579                        package_key_size,
580                        label_ptr,
581                        label_size,
582                        num_new_urefs,
583                        existing_urefs_ptr,
584                        existing_urefs_size,
585                        output_size_ptr,
586                    ],
587                )?;
588
589                let contract_package_hash: PackageHash =
590                    self.t_from_mem(package_key_ptr, package_key_size)?;
591                let label: String = self.t_from_mem(label_ptr, label_size)?;
592                let existing_urefs: BTreeSet<URef> =
593                    self.t_from_mem(existing_urefs_ptr, existing_urefs_size)?;
594
595                let ret = self.create_contract_user_group(
596                    contract_package_hash,
597                    label,
598                    num_new_urefs,
599                    existing_urefs,
600                    output_size_ptr,
601                )?;
602                Ok(Some(RuntimeValue::I32(api_error::i32_from(ret))))
603            }
604
605            FunctionIndex::AddContractVersion => {
606                // args(0) = pointer to package key in wasm memory
607                // args(1) = size of package key in wasm memory
608                // args(2) = pointer to entrypoints in wasm memory
609                // args(3) = size of entrypoints in wasm memory
610                // args(4) = pointer to named keys in wasm memory
611                // args(5) = size of named keys in wasm memory
612                // args(6) = pointer to output buffer for serialized key
613                // args(7) = size of output buffer
614                // args(8) = pointer to bytes written
615                let (
616                    contract_package_hash_ptr,
617                    contract_package_hash_size,
618                    version_ptr,
619                    entry_points_ptr,
620                    entry_points_size,
621                    named_keys_ptr,
622                    named_keys_size,
623                    output_ptr,
624                    output_size,
625                    bytes_written_ptr,
626                ) = Args::parse(args)?;
627                self.charge_host_function_call(
628                    &host_function_costs.add_contract_version,
629                    [
630                        contract_package_hash_ptr,
631                        contract_package_hash_size,
632                        version_ptr,
633                        entry_points_ptr,
634                        entry_points_size,
635                        named_keys_ptr,
636                        named_keys_size,
637                        output_ptr,
638                        output_size,
639                        bytes_written_ptr,
640                    ],
641                )?;
642
643                let contract_package_hash: ContractPackageHash =
644                    self.t_from_mem(contract_package_hash_ptr, contract_package_hash_size)?;
645                let package_hash = PackageHash::new(contract_package_hash.value());
646                let entry_points: EntryPoints = {
647                    let contract_entry_points: ContractEntryPoints =
648                        self.t_from_mem(entry_points_ptr, entry_points_size)?;
649
650                    let points: Vec<EntityEntryPoint> = contract_entry_points
651                        .take_entry_points()
652                        .into_iter()
653                        .map(EntityEntryPoint::from)
654                        .collect();
655
656                    points.into()
657                };
658                let named_keys: NamedKeys = self.t_from_mem(named_keys_ptr, named_keys_size)?;
659                let ret = self.add_contract_version(
660                    package_hash,
661                    version_ptr,
662                    entry_points,
663                    named_keys,
664                    BTreeMap::new(),
665                    output_ptr,
666                )?;
667                Ok(Some(RuntimeValue::I32(api_error::i32_from(ret))))
668            }
669            FunctionIndex::AddContractVersionWithMessageTopics => {
670                // args(0)  = pointer to package hash in wasm memory
671                // args(1)  = size of package hash in wasm memory
672                // args(2)  = pointer to entity version in wasm memory
673                // args(3)  = pointer to entrypoints in wasm memory
674                // args(4)  = size of entrypoints in wasm memory
675                // args(5)  = pointer to named keys in wasm memory
676                // args(6)  = size of named keys in wasm memory
677                // args(7)  = pointer to the new topic names in wasm memory
678                // args(8)  = size of the new topic names in wasm memory
679                // args(9)  = pointer to output buffer for serialized key
680                // args(10) = size of output buffer
681                let (
682                    contract_package_hash_ptr,
683                    contract_package_hash_size,
684                    version_ptr,
685                    entry_points_ptr,
686                    entry_points_size,
687                    named_keys_ptr,
688                    named_keys_size,
689                    message_topics_ptr,
690                    message_topics_size,
691                    output_ptr,
692                    output_size,
693                ) = Args::parse(args)?;
694                self.charge_host_function_call(
695                    &host_function_costs.add_contract_version_with_message_topics,
696                    [
697                        contract_package_hash_ptr,
698                        contract_package_hash_size,
699                        version_ptr,
700                        entry_points_ptr,
701                        entry_points_size,
702                        named_keys_ptr,
703                        named_keys_size,
704                        message_topics_ptr,
705                        message_topics_size,
706                        output_ptr,
707                        output_size,
708                    ],
709                )?;
710
711                // Exit if unable to return output.
712                if output_size < 32 {
713                    // `output_size` must be >= actual length of serialized hash bytes
714                    return Ok(Some(RuntimeValue::I32(api_error::i32_from(Err(
715                        ApiError::BufferTooSmall,
716                    )))));
717                }
718
719                let package_hash: PackageHash =
720                    self.t_from_mem(contract_package_hash_ptr, contract_package_hash_size)?;
721                let entry_points: EntryPoints =
722                    self.t_from_mem(entry_points_ptr, entry_points_size)?;
723                let named_keys: NamedKeys = self.t_from_mem(named_keys_ptr, named_keys_size)?;
724                let message_topics: BTreeMap<String, MessageTopicOperation> =
725                    self.t_from_mem(message_topics_ptr, message_topics_size)?;
726
727                // Check that the names of the topics that are added are within the configured
728                // limits.
729                let message_limits = self.context.engine_config().wasm_config().messages_limits();
730                for (topic_name, _) in
731                    message_topics
732                        .iter()
733                        .filter(|(_, operation)| match operation {
734                            MessageTopicOperation::Add => true,
735                        })
736                {
737                    if topic_name.len() > message_limits.max_topic_name_size() as usize {
738                        return Ok(Some(RuntimeValue::I32(api_error::i32_from(Err(
739                            ApiError::MaxTopicNameSizeExceeded,
740                        )))));
741                    }
742                }
743
744                let ret = self.add_contract_version(
745                    package_hash,
746                    version_ptr,
747                    entry_points,
748                    named_keys,
749                    message_topics,
750                    output_ptr,
751                )?;
752                Ok(Some(RuntimeValue::I32(api_error::i32_from(ret))))
753            }
754
755            FunctionIndex::AddPackageVersionWithMessageTopics => {
756                // args(0)  = pointer to package hash in wasm memory
757                // args(1)  = size of package hash in wasm memory
758                // args(2)  = pointer to entity version in wasm memory
759                // args(3)  = pointer to entrypoints in wasm memory
760                // args(4)  = size of entrypoints in wasm memory
761                // args(5)  = pointer to named keys in wasm memory
762                // args(6)  = size of named keys in wasm memory
763                // args(7)  = pointer to the new topic names in wasm memory
764                // args(8)  = size of the new topic names in wasm memory
765                // args(9)  = pointer to output buffer for serialized key
766                // args(10) = size of output buffer
767                let (
768                    contract_package_hash_ptr,
769                    contract_package_hash_size,
770                    version_ptr,
771                    entry_points_ptr,
772                    entry_points_size,
773                    named_keys_ptr,
774                    named_keys_size,
775                    message_topics,
776                    message_topics_size,
777                    output_ptr,
778                    output_size,
779                ) = Args::parse(args)?;
780
781                self.charge_host_function_call(
782                    &host_function_costs.add_package_version_with_message_topics,
783                    [
784                        contract_package_hash_ptr,
785                        contract_package_hash_size,
786                        version_ptr,
787                        entry_points_ptr,
788                        entry_points_size,
789                        named_keys_ptr,
790                        named_keys_size,
791                        message_topics,
792                        message_topics_size,
793                        output_ptr,
794                        output_size,
795                    ],
796                )?;
797
798                // Exit if unable to return output.
799                if output_size < 32 {
800                    // `output_size` must be >= actual length of serialized hash bytes
801                    return Ok(Some(RuntimeValue::I32(api_error::i32_from(Err(
802                        ApiError::BufferTooSmall,
803                    )))));
804                }
805
806                let package_hash: PackageHash =
807                    self.t_from_mem(contract_package_hash_ptr, contract_package_hash_size)?;
808                let entry_points: EntryPoints =
809                    self.t_from_mem(entry_points_ptr, entry_points_size)?;
810                let named_keys: NamedKeys = self.t_from_mem(named_keys_ptr, named_keys_size)?;
811                let message_topics: BTreeMap<String, MessageTopicOperation> =
812                    self.t_from_mem(message_topics, message_topics_size)?;
813
814                // Check that the names of the topics that are added are within the configured
815                // limits.
816                let message_limits = self.context.engine_config().wasm_config().messages_limits();
817                for (topic_name, _) in
818                    message_topics
819                        .iter()
820                        .filter(|(_, operation)| match operation {
821                            MessageTopicOperation::Add => true,
822                        })
823                {
824                    if topic_name.len() > message_limits.max_topic_name_size() as usize {
825                        return Ok(Some(RuntimeValue::I32(api_error::i32_from(Err(
826                            ApiError::MaxTopicNameSizeExceeded,
827                        )))));
828                    }
829                }
830
831                let ret = self.add_contract_version(
832                    package_hash,
833                    version_ptr,
834                    entry_points,
835                    named_keys,
836                    message_topics,
837                    output_ptr,
838                )?;
839                Ok(Some(RuntimeValue::I32(api_error::i32_from(ret))))
840            }
841
842            FunctionIndex::DisableContractVersion => {
843                // args(0) = pointer to package hash in wasm memory
844                // args(1) = size of package hash in wasm memory
845                // args(2) = pointer to contract hash in wasm memory
846                // args(3) = size of contract hash in wasm memory
847                let (package_key_ptr, package_key_size, contract_hash_ptr, contract_hash_size) =
848                    Args::parse(args)?;
849                self.charge_host_function_call(
850                    &host_function_costs.disable_contract_version,
851                    [
852                        package_key_ptr,
853                        package_key_size,
854                        contract_hash_ptr,
855                        contract_hash_size,
856                    ],
857                )?;
858                let contract_package_hash = self.t_from_mem(package_key_ptr, package_key_size)?;
859                let contract_hash = self.t_from_mem(contract_hash_ptr, contract_hash_size)?;
860
861                let result = self.disable_contract_version(contract_package_hash, contract_hash)?;
862
863                Ok(Some(RuntimeValue::I32(api_error::i32_from(result))))
864            }
865
866            FunctionIndex::CallContractFuncIndex => {
867                // args(0) = pointer to contract hash where contract is at in global state
868                // args(1) = size of contract hash
869                // args(2) = pointer to entry point
870                // args(3) = size of entry point
871                // args(4) = pointer to function arguments in Wasm memory
872                // args(5) = size of arguments
873                // args(6) = pointer to result size (output)
874                let (
875                    contract_hash_ptr,
876                    contract_hash_size,
877                    entry_point_name_ptr,
878                    entry_point_name_size,
879                    args_ptr,
880                    args_size,
881                    result_size_ptr,
882                ) = Args::parse(args)?;
883                self.charge_host_function_call(
884                    &host_function_costs.call_contract,
885                    [
886                        contract_hash_ptr,
887                        contract_hash_size,
888                        entry_point_name_ptr,
889                        entry_point_name_size,
890                        args_ptr,
891                        args_size,
892                        result_size_ptr,
893                    ],
894                )?;
895
896                let contract_hash: AddressableEntityHash =
897                    self.t_from_mem(contract_hash_ptr, contract_hash_size)?;
898                let entry_point_name: String =
899                    self.t_from_mem(entry_point_name_ptr, entry_point_name_size)?;
900                let args_bytes: Vec<u8> = {
901                    let args_size: u32 = args_size;
902                    self.bytes_from_mem(args_ptr, args_size as usize)?.to_vec()
903                };
904
905                let ret = self.call_contract_host_buffer(
906                    contract_hash,
907                    &entry_point_name,
908                    &args_bytes,
909                    result_size_ptr,
910                )?;
911                Ok(Some(RuntimeValue::I32(api_error::i32_from(ret))))
912            }
913
914            FunctionIndex::CallVersionedContract => {
915                // args(0) = pointer to contract_package_hash where contract is at in global state
916                // args(1) = size of contract_package_hash
917                // args(2) = pointer to contract version in wasm memory
918                // args(3) = size of contract version in wasm memory
919                // args(4) = pointer to method name in wasm memory
920                // args(5) = size of method name in wasm memory
921                // args(6) = pointer to function arguments in Wasm memory
922                // args(7) = size of arguments
923                // args(8) = pointer to result size (output)
924                let (
925                    contract_package_hash_ptr,
926                    contract_package_hash_size,
927                    contract_version_ptr,
928                    contract_package_size,
929                    entry_point_name_ptr,
930                    entry_point_name_size,
931                    args_ptr,
932                    args_size,
933                    result_size_ptr,
934                ) = Args::parse(args)?;
935                self.charge_host_function_call(
936                    &host_function_costs.call_versioned_contract,
937                    [
938                        contract_package_hash_ptr,
939                        contract_package_hash_size,
940                        contract_version_ptr,
941                        contract_package_size,
942                        entry_point_name_ptr,
943                        entry_point_name_size,
944                        args_ptr,
945                        args_size,
946                        result_size_ptr,
947                    ],
948                )?;
949
950                let contract_package_hash: PackageHash =
951                    self.t_from_mem(contract_package_hash_ptr, contract_package_hash_size)?;
952                let contract_version: Option<EntityVersion> =
953                    self.t_from_mem(contract_version_ptr, contract_package_size)?;
954                let entry_point_name: String =
955                    self.t_from_mem(entry_point_name_ptr, entry_point_name_size)?;
956                let args_bytes: Vec<u8> = {
957                    let args_size: u32 = args_size;
958                    self.bytes_from_mem(args_ptr, args_size as usize)?.to_vec()
959                };
960
961                let ret = self.call_versioned_contract_host_buffer(
962                    contract_package_hash,
963                    contract_version,
964                    entry_point_name,
965                    &args_bytes,
966                    result_size_ptr,
967                )?;
968                Ok(Some(RuntimeValue::I32(api_error::i32_from(ret))))
969            }
970
971            #[cfg(feature = "test-support")]
972            FunctionIndex::PrintIndex => {
973                let (text_ptr, text_size) = Args::parse(args)?;
974                self.charge_host_function_call(&host_function_costs.print, [text_ptr, text_size])?;
975                self.print(text_ptr, text_size)?;
976                Ok(None)
977            }
978
979            FunctionIndex::GetRuntimeArgsizeIndex => {
980                // args(0) = pointer to name of host runtime arg to load
981                // args(1) = size of name of the host runtime arg
982                // args(2) = pointer to a argument size (output)
983                let (name_ptr, name_size, size_ptr) = Args::parse(args)?;
984                self.charge_host_function_call(
985                    &host_function_costs.get_named_arg_size,
986                    [name_ptr, name_size, size_ptr],
987                )?;
988                let ret = self.get_named_arg_size(name_ptr, name_size as usize, size_ptr)?;
989                Ok(Some(RuntimeValue::I32(api_error::i32_from(ret))))
990            }
991
992            FunctionIndex::GetRuntimeArgIndex => {
993                // args(0) = pointer to serialized argument name
994                // args(1) = size of serialized argument name
995                // args(2) = pointer to output pointer where host will write argument bytes
996                // args(3) = size of available data under output pointer
997                let (name_ptr, name_size, dest_ptr, dest_size) = Args::parse(args)?;
998                self.charge_host_function_call(
999                    &host_function_costs.get_named_arg,
1000                    [name_ptr, name_size, dest_ptr, dest_size],
1001                )?;
1002                let ret =
1003                    self.get_named_arg(name_ptr, name_size as usize, dest_ptr, dest_size as usize)?;
1004                Ok(Some(RuntimeValue::I32(api_error::i32_from(ret))))
1005            }
1006
1007            FunctionIndex::RemoveContractUserGroupIndex => {
1008                // args(0) = pointer to package key in wasm memory
1009                // args(1) = size of package key in wasm memory
1010                // args(2) = pointer to serialized group label
1011                // args(3) = size of serialized group label
1012                let (package_key_ptr, package_key_size, label_ptr, label_size) = Args::parse(args)?;
1013                self.charge_host_function_call(
1014                    &host_function_costs.remove_contract_user_group,
1015                    [package_key_ptr, package_key_size, label_ptr, label_size],
1016                )?;
1017                let package_key = self.t_from_mem(package_key_ptr, package_key_size)?;
1018                let label: Group = self.t_from_mem(label_ptr, label_size)?;
1019
1020                let ret = self.remove_contract_user_group(package_key, label)?;
1021                Ok(Some(RuntimeValue::I32(api_error::i32_from(ret))))
1022            }
1023
1024            FunctionIndex::ExtendContractUserGroupURefsIndex => {
1025                // args(0) = pointer to package key in wasm memory
1026                // args(1) = size of package key in wasm memory
1027                // args(2) = pointer to label name
1028                // args(3) = label size bytes
1029                // args(4) = output of size value of host bytes data
1030                let (package_ptr, package_size, label_ptr, label_size, value_size_ptr) =
1031                    Args::parse(args)?;
1032
1033                self.charge_host_function_call(
1034                    &host_function_costs.provision_contract_user_group_uref,
1035                    [
1036                        package_ptr,
1037                        package_size,
1038                        label_ptr,
1039                        label_size,
1040                        value_size_ptr,
1041                    ],
1042                )?;
1043                let ret = self.provision_contract_user_group_uref(
1044                    package_ptr,
1045                    package_size,
1046                    label_ptr,
1047                    label_size,
1048                    value_size_ptr,
1049                )?;
1050                Ok(Some(RuntimeValue::I32(api_error::i32_from(ret))))
1051            }
1052
1053            FunctionIndex::RemoveContractUserGroupURefsIndex => {
1054                // args(0) = pointer to package key in wasm memory
1055                // args(1) = size of package key in wasm memory
1056                // args(2) = pointer to label name
1057                // args(3) = label size bytes
1058                // args(4) = pointer to urefs
1059                // args(5) = size of urefs pointer
1060                let (package_ptr, package_size, label_ptr, label_size, urefs_ptr, urefs_size) =
1061                    Args::parse(args)?;
1062                self.charge_host_function_call(
1063                    &host_function_costs.remove_contract_user_group_urefs,
1064                    [
1065                        package_ptr,
1066                        package_size,
1067                        label_ptr,
1068                        label_size,
1069                        urefs_ptr,
1070                        urefs_size,
1071                    ],
1072                )?;
1073                let ret = self.remove_contract_user_group_urefs(
1074                    package_ptr,
1075                    package_size,
1076                    label_ptr,
1077                    label_size,
1078                    urefs_ptr,
1079                    urefs_size,
1080                )?;
1081                Ok(Some(RuntimeValue::I32(api_error::i32_from(ret))))
1082            }
1083
1084            FunctionIndex::Blake2b => {
1085                let (in_ptr, in_size, out_ptr, out_size) = Args::parse(args)?;
1086                self.charge_host_function_call(
1087                    &host_function_costs.blake2b,
1088                    [in_ptr, in_size, out_ptr, out_size],
1089                )?;
1090                let digest =
1091                    self.checked_memory_slice(in_ptr as usize, in_size as usize, |input| {
1092                        cryptography::blake2b(input)
1093                    })?;
1094
1095                let result = if digest.len() != out_size as usize {
1096                    Err(ApiError::BufferTooSmall)
1097                } else {
1098                    Ok(())
1099                };
1100                if result.is_err() {
1101                    return Ok(Some(RuntimeValue::I32(api_error::i32_from(result))));
1102                }
1103
1104                self.try_get_memory()?
1105                    .set(out_ptr, &digest)
1106                    .map_err(|error| ExecError::Interpreter(error.into()))?;
1107                Ok(Some(RuntimeValue::I32(0)))
1108            }
1109
1110            FunctionIndex::NewDictionaryFuncIndex => {
1111                // args(0) = pointer to output size (output param)
1112                let (output_size_ptr,): (u32,) = Args::parse(args)?;
1113                const UREF_LEN: u32 = 33u32;
1114                self.charge_host_function_call(&host_function_costs.new_uref, [0, 0, UREF_LEN])?;
1115                let ret = self.new_dictionary(output_size_ptr)?;
1116                Ok(Some(RuntimeValue::I32(api_error::i32_from(ret))))
1117            }
1118
1119            FunctionIndex::DictionaryGetFuncIndex => {
1120                // args(0) = pointer to uref in Wasm memory
1121                // args(1) = size of uref in Wasm memory
1122                // args(2) = pointer to key bytes pointer in Wasm memory
1123                // args(3) = pointer to key bytes size in Wasm memory
1124                // args(4) = pointer to output size (output param)
1125                let (uref_ptr, uref_size, key_bytes_ptr, key_bytes_size, output_size_ptr): (
1126                    _,
1127                    u32,
1128                    _,
1129                    u32,
1130                    _,
1131                ) = Args::parse(args)?;
1132                self.charge_host_function_call(
1133                    &host_function_costs.dictionary_get,
1134                    [key_bytes_ptr, key_bytes_size, output_size_ptr],
1135                )?;
1136                let ret = self.dictionary_get(
1137                    uref_ptr,
1138                    uref_size,
1139                    key_bytes_ptr,
1140                    key_bytes_size,
1141                    output_size_ptr,
1142                )?;
1143                Ok(Some(RuntimeValue::I32(api_error::i32_from(ret))))
1144            }
1145
1146            FunctionIndex::DictionaryPutFuncIndex => {
1147                // args(0) = pointer to uref in Wasm memory
1148                // args(1) = size of uref in Wasm memory
1149                // args(2) = pointer to key bytes pointer in Wasm memory
1150                // args(3) = pointer to key bytes size in Wasm memory
1151                // args(4) = pointer to value bytes pointer in Wasm memory
1152                // args(5) = pointer to value bytes size in Wasm memory
1153                let (uref_ptr, uref_size, key_bytes_ptr, key_bytes_size, value_ptr, value_ptr_size): (_, u32, _, u32, _, u32) = Args::parse(args)?;
1154                self.charge_host_function_call(
1155                    &host_function_costs.dictionary_put,
1156                    [key_bytes_ptr, key_bytes_size, value_ptr, value_ptr_size],
1157                )?;
1158                let ret = self.dictionary_put(
1159                    uref_ptr,
1160                    uref_size,
1161                    key_bytes_ptr,
1162                    key_bytes_size,
1163                    value_ptr,
1164                    value_ptr_size,
1165                )?;
1166                Ok(Some(RuntimeValue::I32(api_error::i32_from(ret))))
1167            }
1168
1169            FunctionIndex::DictionaryReadFuncIndex => {
1170                // args(0) = pointer to key in Wasm memory
1171                // args(1) = size of key in Wasm memory
1172                // args(2) = pointer to output size (output param)
1173                let (key_ptr, key_size, output_size_ptr) = Args::parse(args)?;
1174                self.charge_host_function_call(
1175                    &host_function_costs.read_value,
1176                    [key_ptr, key_size, output_size_ptr],
1177                )?;
1178                let ret = self.dictionary_read(key_ptr, key_size, output_size_ptr)?;
1179                Ok(Some(RuntimeValue::I32(api_error::i32_from(ret))))
1180            }
1181
1182            FunctionIndex::LoadCallStack => {
1183                // args(0) (Output) Pointer to number of elements in the call stack.
1184                // args(1) (Output) Pointer to size in bytes of the serialized call stack.
1185                let (call_stack_len_ptr, result_size_ptr) = Args::parse(args)?;
1186
1187                self.charge_host_function_call(
1188                    &HostFunction::fixed(10_000),
1189                    [call_stack_len_ptr, result_size_ptr],
1190                )?;
1191                let ret = self.load_call_stack(call_stack_len_ptr, result_size_ptr)?;
1192                Ok(Some(RuntimeValue::I32(api_error::i32_from(ret))))
1193            }
1194
1195            FunctionIndex::LoadCallerInformation => {
1196                // args(0) (Input) Type of action
1197                // args(1) (Output) Pointer to number of elements in the call stack.
1198                // args(2) (Output) Pointer to size in bytes of the serialized call stack.
1199                let (action, call_stack_len_ptr, result_size_ptr) = Args::parse(args)?;
1200                self.charge_host_function_call(
1201                    &HostFunction::fixed(10_000),
1202                    [0, call_stack_len_ptr, result_size_ptr],
1203                )?;
1204                let ret =
1205                    self.load_caller_information(action, call_stack_len_ptr, result_size_ptr)?;
1206                Ok(Some(RuntimeValue::I32(api_error::i32_from(ret))))
1207            }
1208
1209            FunctionIndex::LoadAuthorizationKeys => {
1210                // args(0) (Output) Pointer to number of authorization keys.
1211                // args(1) (Output) Pointer to size in bytes of the total bytes.
1212                let (len_ptr, result_size_ptr) = Args::parse(args)?;
1213                self.charge_host_function_call(
1214                    &HostFunction::fixed(10_000),
1215                    [len_ptr, result_size_ptr],
1216                )?;
1217                let ret = self.load_authorization_keys(len_ptr, result_size_ptr)?;
1218                Ok(Some(RuntimeValue::I32(api_error::i32_from(ret))))
1219            }
1220
1221            FunctionIndex::RandomBytes => {
1222                let (out_ptr, out_size) = Args::parse(args)?;
1223                self.charge_host_function_call(
1224                    &host_function_costs.random_bytes,
1225                    [out_ptr, out_size],
1226                )?;
1227
1228                let random_bytes = self.context.random_bytes()?;
1229
1230                let result = if random_bytes.len() != out_size as usize {
1231                    Err(ApiError::BufferTooSmall)
1232                } else {
1233                    Ok(())
1234                };
1235                if result.is_err() {
1236                    return Ok(Some(RuntimeValue::I32(api_error::i32_from(result))));
1237                }
1238
1239                self.try_get_memory()?
1240                    .set(out_ptr, &random_bytes)
1241                    .map_err(|error| ExecError::Interpreter(error.into()))?;
1242
1243                Ok(Some(RuntimeValue::I32(0)))
1244            }
1245
1246            FunctionIndex::EnableContractVersion => {
1247                // args(0) = pointer to package hash in wasm memory
1248                // args(1) = size of package hash in wasm memory
1249                // args(2) = pointer to contract hash in wasm memory
1250                // args(3) = size of contract hash in wasm memory
1251                let (package_key_ptr, package_key_size, contract_hash_ptr, contract_hash_size) =
1252                    Args::parse(args)?;
1253                self.charge_host_function_call(
1254                    &host_function_costs.enable_contract_version,
1255                    [
1256                        package_key_ptr,
1257                        package_key_size,
1258                        contract_hash_ptr,
1259                        contract_hash_size,
1260                    ],
1261                )?;
1262                let contract_package_hash = self.t_from_mem(package_key_ptr, package_key_size)?;
1263                let contract_hash = self.t_from_mem(contract_hash_ptr, contract_hash_size)?;
1264
1265                let result = self.enable_contract_version(contract_package_hash, contract_hash)?;
1266
1267                Ok(Some(RuntimeValue::I32(api_error::i32_from(result))))
1268            }
1269
1270            FunctionIndex::ManageMessageTopic => {
1271                // args(0) = pointer to the serialized topic name string in wasm memory
1272                // args(1) = size of the serialized topic name string in wasm memory
1273                // args(2) = pointer to the operation to be performed for the specified topic
1274                // args(3) = size of the operation
1275                let (topic_name_ptr, topic_name_size, operation_ptr, operation_size) =
1276                    Args::parse(args)?;
1277                self.charge_host_function_call(
1278                    &host_function_costs.manage_message_topic,
1279                    [
1280                        topic_name_ptr,
1281                        topic_name_size,
1282                        operation_ptr,
1283                        operation_size,
1284                    ],
1285                )?;
1286
1287                let limits = self.context.engine_config().wasm_config().messages_limits();
1288
1289                if topic_name_size > limits.max_topic_name_size() {
1290                    return Ok(Some(RuntimeValue::I32(api_error::i32_from(Err(
1291                        ApiError::MaxTopicNameSizeExceeded,
1292                    )))));
1293                }
1294
1295                let topic_name_bytes =
1296                    self.bytes_from_mem(topic_name_ptr, topic_name_size as usize)?;
1297                let topic_name = std::str::from_utf8(&topic_name_bytes)
1298                    .map_err(|e| Trap::from(ExecError::InvalidUtf8Encoding(e)))?;
1299
1300                if operation_size as usize > MessageTopicOperation::max_serialized_len() {
1301                    return Err(Trap::from(ExecError::InvalidImputedOperation));
1302                }
1303                let topic_operation = self
1304                    .t_from_mem(operation_ptr, operation_size)
1305                    .map_err(|_e| Trap::from(ExecError::InvalidImputedOperation))?;
1306
1307                // only allow managing messages from stored contracts
1308                if !self.context.get_context_key().is_smart_contract_key() {
1309                    return Err(Trap::from(ExecError::InvalidContext));
1310                }
1311
1312                let result = match topic_operation {
1313                    MessageTopicOperation::Add => {
1314                        self.add_message_topic(topic_name).map_err(Trap::from)?
1315                    }
1316                };
1317
1318                Ok(Some(RuntimeValue::I32(api_error::i32_from(result))))
1319            }
1320
1321            FunctionIndex::EmitMessage => {
1322                // args(0) = pointer to the serialized topic name string in wasm memory
1323                // args(1) = size of the serialized name string in wasm memory
1324                // args(2) = pointer to the serialized message payload in wasm memory
1325                // args(3) = size of the serialized message payload in wasm memory
1326                let (topic_name_ptr, topic_name_size, message_ptr, message_size) =
1327                    Args::parse(args)?;
1328
1329                // Charge for the call to emit message. This increases for every message emitted
1330                // within an execution so we're not using the static value from the wasm config.
1331                self.context
1332                    .charge_gas(Gas::new(self.context.emit_message_cost()))?;
1333                // Charge for parameter weights.
1334                self.charge_host_function_call(
1335                    &HostFunction::new(0, host_function_costs.emit_message.arguments()),
1336                    &[topic_name_ptr, topic_name_size, message_ptr, message_size],
1337                )?;
1338
1339                let limits = self.context.engine_config().wasm_config().messages_limits();
1340
1341                if topic_name_size > limits.max_topic_name_size() {
1342                    return Ok(Some(RuntimeValue::I32(api_error::i32_from(Err(
1343                        ApiError::MaxTopicNameSizeExceeded,
1344                    )))));
1345                }
1346
1347                if message_size > limits.max_message_size() {
1348                    return Ok(Some(RuntimeValue::I32(api_error::i32_from(Err(
1349                        ApiError::MessageTooLarge,
1350                    )))));
1351                }
1352
1353                let topic_name_bytes =
1354                    self.bytes_from_mem(topic_name_ptr, topic_name_size as usize)?;
1355                let topic_name = std::str::from_utf8(&topic_name_bytes)
1356                    .map_err(|e| Trap::from(ExecError::InvalidUtf8Encoding(e)))?;
1357
1358                let message = self.t_from_mem(message_ptr, message_size)?;
1359
1360                let result = self.emit_message(topic_name, message)?;
1361                if result.is_ok() {
1362                    // Increase the cost for the next call to emit a message.
1363                    let new_cost = self
1364                        .context
1365                        .emit_message_cost()
1366                        .checked_add(host_function_costs.cost_increase_per_message.into())
1367                        .ok_or(ExecError::GasLimit)?;
1368                    self.context.set_emit_message_cost(new_cost);
1369                }
1370                Ok(Some(RuntimeValue::I32(api_error::i32_from(result))))
1371            }
1372
1373            FunctionIndex::GetBlockInfoIndex => {
1374                // args(0) = field selector
1375                // args(1) = pointer to output pointer where host will write argument bytes
1376                let (field_idx, dest_ptr): (u8, u32) = Args::parse(args)?;
1377
1378                self.charge_host_function_call(&host_function_costs.get_block_info, [0u32, 0u32])?;
1379                self.get_block_info(field_idx, dest_ptr)?;
1380                Ok(None)
1381            }
1382
1383            FunctionIndex::GenericHash => {
1384                // args(0) = pointer to input in Wasm memory
1385                // args(1) = size of input in Wasm memory
1386                // args(2) = integer representation of HashAlgorithm enum variant
1387                // args(3) = pointer to output pointer in Wasm memory
1388                // args(4) = size of output
1389                let (in_ptr, in_size, hash_algo_type, out_ptr, out_size) = Args::parse(args)?;
1390                self.charge_host_function_call(
1391                    &host_function_costs.generic_hash,
1392                    [in_ptr, in_size, hash_algo_type, out_ptr, out_size],
1393                )?;
1394                let hash_algo_type = match HashAlgorithm::try_from(hash_algo_type as u8) {
1395                    Ok(v) => v,
1396                    Err(_e) => {
1397                        return Ok(Some(RuntimeValue::I32(api_error::i32_from(Err(
1398                            ApiError::InvalidArgument,
1399                        )))))
1400                    }
1401                };
1402
1403                let digest =
1404                    self.checked_memory_slice(in_ptr as usize, in_size as usize, |input| {
1405                        match hash_algo_type {
1406                            HashAlgorithm::Blake2b => cryptography::blake2b(input),
1407                            HashAlgorithm::Blake3 => cryptography::blake3(input),
1408                            HashAlgorithm::Sha256 => cryptography::sha256(input),
1409                        }
1410                    })?;
1411
1412                let result = if digest.len() > out_size as usize {
1413                    Err(ApiError::BufferTooSmall)
1414                } else {
1415                    Ok(())
1416                };
1417
1418                if result.is_err() {
1419                    return Ok(Some(RuntimeValue::I32(api_error::i32_from(result))));
1420                }
1421
1422                if self.try_get_memory()?.set(out_ptr, &digest).is_err() {
1423                    return Ok(Some(RuntimeValue::I32(
1424                        u32::from(ApiError::HostBufferEmpty) as i32,
1425                    )));
1426                }
1427
1428                Ok(Some(RuntimeValue::I32(0)))
1429            }
1430
1431            FunctionIndex::RecoverSecp256k1 => {
1432                // args(0) = pointer to input bytes in memory
1433                // args(1) = length of input bytes in memory
1434                // args(2) = pointer to signature bytes in memory
1435                // args(3) = length of signature bytes in memory
1436                // args(4) = pointer to public key buffer in memory (size is fixed)
1437                // args(5) = the recovery id
1438
1439                let (
1440                    data_ptr,
1441                    data_size,
1442                    signature_ptr,
1443                    signature_size,
1444                    public_key_ptr,
1445                    recovery_id,
1446                ) = Args::parse(args)?;
1447
1448                self.charge_host_function_call(
1449                    &host_function_costs.recover_secp256k1,
1450                    [
1451                        data_ptr,
1452                        data_size,
1453                        signature_ptr,
1454                        signature_size,
1455                        public_key_ptr,
1456                        recovery_id,
1457                    ],
1458                )?;
1459
1460                if recovery_id >= 4 {
1461                    return Ok(Some(RuntimeValue::I32(
1462                        u32::from(ApiError::InvalidArgument) as i32,
1463                    )));
1464                }
1465
1466                let data = self.bytes_from_mem(data_ptr, data_size as usize)?;
1467                let signature: Signature = self.t_from_mem(signature_ptr, signature_size)?;
1468
1469                let Ok(public_key) =
1470                    casper_types::crypto::recover_secp256k1(data, &signature, recovery_id as u8)
1471                else {
1472                    return Ok(Some(RuntimeValue::I32(
1473                        u32::from(ApiError::InvalidArgument) as i32,
1474                    )));
1475                };
1476
1477                let Ok(key_bytes) = public_key.to_bytes() else {
1478                    return Ok(Some(RuntimeValue::I32(
1479                        u32::from(ApiError::OutOfMemory) as i32
1480                    )));
1481                };
1482
1483                if self
1484                    .try_get_memory()?
1485                    .set(public_key_ptr, &key_bytes)
1486                    .is_err()
1487                {
1488                    return Ok(Some(RuntimeValue::I32(
1489                        u32::from(ApiError::HostBufferEmpty) as i32,
1490                    )));
1491                }
1492
1493                Ok(Some(RuntimeValue::I32(0)))
1494            }
1495
1496            FunctionIndex::VerifySignature => {
1497                // args(0) = pointer to message bytes in memory
1498                // args(1) = length of message bytes
1499                // args(2) = pointer to signature bytes in memory
1500                // args(3) = length of signature bytes
1501                // args(4) = pointer to public key bytes in memory
1502                // args(5) = length of public key bytes
1503                let (
1504                    message_ptr,
1505                    message_size,
1506                    signature_ptr,
1507                    signature_size,
1508                    public_key_ptr,
1509                    public_key_size,
1510                ) = Args::parse(args)?;
1511
1512                self.charge_host_function_call(
1513                    &host_function_costs.verify_signature,
1514                    [
1515                        message_ptr,
1516                        message_size,
1517                        signature_ptr,
1518                        signature_size,
1519                        public_key_ptr,
1520                        public_key_size,
1521                    ],
1522                )?;
1523
1524                let message = self.bytes_from_mem(message_ptr, message_size as usize)?;
1525                let signature: Signature = self.t_from_mem(signature_ptr, signature_size)?;
1526                let public_key: PublicKey = self.t_from_mem(public_key_ptr, public_key_size)?;
1527
1528                if casper_types::crypto::verify(message, &signature, &public_key).is_err() {
1529                    return Ok(Some(RuntimeValue::I32(
1530                        u32::from(ApiError::InvalidArgument) as i32,
1531                    )));
1532                }
1533
1534                Ok(Some(RuntimeValue::I32(0)))
1535            }
1536            FunctionIndex::CallPackageVersion => {
1537                // args(0) = pointer to contract_package_hash where contract is at in global state
1538                // args(1) = size of contract_package_hash
1539                // args(2) = pointer to major version in wasm memory
1540                // args(3) = size of major version in wasm memory
1541                // args(3) = pointer to contract version in wasm memory
1542                // args(4) = size of contract version in wasm memory
1543                // args(5) = pointer to method name in wasm memory
1544                // args(6) = size of method name in wasm memory
1545                // args(7) = pointer to function arguments in Wasm memory
1546                // args(8) = size of arguments
1547                // args(9) = pointer to result size (output)
1548                let (
1549                    contract_package_hash_ptr,
1550                    contract_package_hash_size,
1551                    major_version_ptr,
1552                    major_version_size,
1553                    contract_version_ptr,
1554                    contract_version_size,
1555                    entry_point_name_ptr,
1556                    entry_point_name_size,
1557                    args_ptr,
1558                    args_size,
1559                    result_size_ptr,
1560                ) = Args::parse(args)?;
1561                self.charge_host_function_call(
1562                    &host_function_costs.call_package_version,
1563                    [
1564                        contract_package_hash_ptr,
1565                        contract_package_hash_size,
1566                        major_version_ptr,
1567                        major_version_size,
1568                        contract_version_ptr,
1569                        contract_version_size,
1570                        entry_point_name_ptr,
1571                        entry_point_name_size,
1572                        args_ptr,
1573                        args_size,
1574                        result_size_ptr,
1575                    ],
1576                )?;
1577
1578                let contract_package_hash: PackageHash =
1579                    self.t_from_mem(contract_package_hash_ptr, contract_package_hash_size)?;
1580                let major_version: u32 = self.t_from_mem(major_version_ptr, major_version_size)?;
1581                let contract_version: EntityVersion =
1582                    self.t_from_mem(contract_version_ptr, contract_version_size)?;
1583                let entry_point_name: String =
1584                    self.t_from_mem(entry_point_name_ptr, entry_point_name_size)?;
1585                let args_bytes: Vec<u8> = {
1586                    let args_size: u32 = args_size;
1587                    self.bytes_from_mem(args_ptr, args_size as usize)?.to_vec()
1588                };
1589
1590                let ret = self.call_package_version_host_buffer(
1591                    contract_package_hash,
1592                    major_version,
1593                    contract_version,
1594                    entry_point_name,
1595                    &args_bytes,
1596                    result_size_ptr,
1597                )?;
1598                Ok(Some(RuntimeValue::I32(api_error::i32_from(ret))))
1599            }
1600        }
1601    }
1602}