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::EntryPoints,
12    api_error,
13    bytesrepr::{self, ToBytes},
14    contract_messages::MessageTopicOperation,
15    contracts::{ContractPackageHash, 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                    self.t_from_mem(entry_points_ptr, entry_points_size)?;
648                let named_keys: NamedKeys = self.t_from_mem(named_keys_ptr, named_keys_size)?;
649                let ret = self.add_contract_version(
650                    package_hash,
651                    version_ptr,
652                    entry_points,
653                    named_keys,
654                    BTreeMap::new(),
655                    output_ptr,
656                )?;
657                Ok(Some(RuntimeValue::I32(api_error::i32_from(ret))))
658            }
659            FunctionIndex::AddContractVersionWithMessageTopics => {
660                // args(0)  = pointer to package hash in wasm memory
661                // args(1)  = size of package hash in wasm memory
662                // args(2)  = pointer to entity version in wasm memory
663                // args(3)  = pointer to entrypoints in wasm memory
664                // args(4)  = size of entrypoints in wasm memory
665                // args(5)  = pointer to named keys in wasm memory
666                // args(6)  = size of named keys in wasm memory
667                // args(7)  = pointer to the new topic names in wasm memory
668                // args(8)  = size of the new topic names in wasm memory
669                // args(9)  = pointer to output buffer for serialized key
670                // args(10) = size of output buffer
671                let (
672                    contract_package_hash_ptr,
673                    contract_package_hash_size,
674                    version_ptr,
675                    entry_points_ptr,
676                    entry_points_size,
677                    named_keys_ptr,
678                    named_keys_size,
679                    message_topics_ptr,
680                    message_topics_size,
681                    output_ptr,
682                    output_size,
683                ) = Args::parse(args)?;
684                self.charge_host_function_call(
685                    &host_function_costs.add_contract_version_with_message_topics,
686                    [
687                        contract_package_hash_ptr,
688                        contract_package_hash_size,
689                        version_ptr,
690                        entry_points_ptr,
691                        entry_points_size,
692                        named_keys_ptr,
693                        named_keys_size,
694                        message_topics_ptr,
695                        message_topics_size,
696                        output_ptr,
697                        output_size,
698                    ],
699                )?;
700
701                // Exit if unable to return output.
702                if output_size < 32 {
703                    // `output_size` must be >= actual length of serialized hash bytes
704                    return Ok(Some(RuntimeValue::I32(api_error::i32_from(Err(
705                        ApiError::BufferTooSmall,
706                    )))));
707                }
708
709                let package_hash: PackageHash =
710                    self.t_from_mem(contract_package_hash_ptr, contract_package_hash_size)?;
711                let entry_points: EntryPoints =
712                    self.t_from_mem(entry_points_ptr, entry_points_size)?;
713                let named_keys: NamedKeys = self.t_from_mem(named_keys_ptr, named_keys_size)?;
714                let message_topics: BTreeMap<String, MessageTopicOperation> =
715                    self.t_from_mem(message_topics_ptr, message_topics_size)?;
716
717                // Check that the names of the topics that are added are within the configured
718                // limits.
719                let message_limits = self.context.engine_config().wasm_config().messages_limits();
720                for (topic_name, _) in
721                    message_topics
722                        .iter()
723                        .filter(|(_, operation)| match operation {
724                            MessageTopicOperation::Add => true,
725                        })
726                {
727                    if topic_name.len() > message_limits.max_topic_name_size() as usize {
728                        return Ok(Some(RuntimeValue::I32(api_error::i32_from(Err(
729                            ApiError::MaxTopicNameSizeExceeded,
730                        )))));
731                    }
732                }
733
734                let ret = self.add_contract_version(
735                    package_hash,
736                    version_ptr,
737                    entry_points,
738                    named_keys,
739                    message_topics,
740                    output_ptr,
741                )?;
742                Ok(Some(RuntimeValue::I32(api_error::i32_from(ret))))
743            }
744
745            FunctionIndex::AddPackageVersionWithMessageTopics => {
746                // args(0)  = pointer to package hash in wasm memory
747                // args(1)  = size of package hash in wasm memory
748                // args(2)  = pointer to entity version in wasm memory
749                // args(3)  = pointer to entrypoints in wasm memory
750                // args(4)  = size of entrypoints in wasm memory
751                // args(5)  = pointer to named keys in wasm memory
752                // args(6)  = size of named keys in wasm memory
753                // args(7)  = pointer to the new topic names in wasm memory
754                // args(8)  = size of the new topic names in wasm memory
755                // args(9)  = pointer to output buffer for serialized key
756                // args(10) = size of output buffer
757                let (
758                    contract_package_hash_ptr,
759                    contract_package_hash_size,
760                    version_ptr,
761                    entry_points_ptr,
762                    entry_points_size,
763                    named_keys_ptr,
764                    named_keys_size,
765                    message_topics,
766                    message_topics_size,
767                    output_ptr,
768                    output_size,
769                ) = Args::parse(args)?;
770
771                self.charge_host_function_call(
772                    &host_function_costs.add_package_version_with_message_topics,
773                    [
774                        contract_package_hash_ptr,
775                        contract_package_hash_size,
776                        version_ptr,
777                        entry_points_ptr,
778                        entry_points_size,
779                        named_keys_ptr,
780                        named_keys_size,
781                        message_topics,
782                        message_topics_size,
783                        output_ptr,
784                        output_size,
785                    ],
786                )?;
787
788                // Exit if unable to return output.
789                if output_size < 32 {
790                    // `output_size` must be >= actual length of serialized hash bytes
791                    return Ok(Some(RuntimeValue::I32(api_error::i32_from(Err(
792                        ApiError::BufferTooSmall,
793                    )))));
794                }
795
796                let package_hash: PackageHash =
797                    self.t_from_mem(contract_package_hash_ptr, contract_package_hash_size)?;
798                let entry_points: EntryPoints =
799                    self.t_from_mem(entry_points_ptr, entry_points_size)?;
800                let named_keys: NamedKeys = self.t_from_mem(named_keys_ptr, named_keys_size)?;
801                let message_topics: BTreeMap<String, MessageTopicOperation> =
802                    self.t_from_mem(message_topics, message_topics_size)?;
803
804                // Check that the names of the topics that are added are within the configured
805                // limits.
806                let message_limits = self.context.engine_config().wasm_config().messages_limits();
807                for (topic_name, _) in
808                    message_topics
809                        .iter()
810                        .filter(|(_, operation)| match operation {
811                            MessageTopicOperation::Add => true,
812                        })
813                {
814                    if topic_name.len() > message_limits.max_topic_name_size() as usize {
815                        return Ok(Some(RuntimeValue::I32(api_error::i32_from(Err(
816                            ApiError::MaxTopicNameSizeExceeded,
817                        )))));
818                    }
819                }
820
821                let ret = self.add_contract_version(
822                    package_hash,
823                    version_ptr,
824                    entry_points,
825                    named_keys,
826                    message_topics,
827                    output_ptr,
828                )?;
829                Ok(Some(RuntimeValue::I32(api_error::i32_from(ret))))
830            }
831
832            FunctionIndex::DisableContractVersion => {
833                // args(0) = pointer to package hash in wasm memory
834                // args(1) = size of package hash in wasm memory
835                // args(2) = pointer to contract hash in wasm memory
836                // args(3) = size of contract hash in wasm memory
837                let (package_key_ptr, package_key_size, contract_hash_ptr, contract_hash_size) =
838                    Args::parse(args)?;
839                self.charge_host_function_call(
840                    &host_function_costs.disable_contract_version,
841                    [
842                        package_key_ptr,
843                        package_key_size,
844                        contract_hash_ptr,
845                        contract_hash_size,
846                    ],
847                )?;
848                let contract_package_hash = self.t_from_mem(package_key_ptr, package_key_size)?;
849                let contract_hash = self.t_from_mem(contract_hash_ptr, contract_hash_size)?;
850
851                let result = self.disable_contract_version(contract_package_hash, contract_hash)?;
852
853                Ok(Some(RuntimeValue::I32(api_error::i32_from(result))))
854            }
855
856            FunctionIndex::CallContractFuncIndex => {
857                // args(0) = pointer to contract hash where contract is at in global state
858                // args(1) = size of contract hash
859                // args(2) = pointer to entry point
860                // args(3) = size of entry point
861                // args(4) = pointer to function arguments in Wasm memory
862                // args(5) = size of arguments
863                // args(6) = pointer to result size (output)
864                let (
865                    contract_hash_ptr,
866                    contract_hash_size,
867                    entry_point_name_ptr,
868                    entry_point_name_size,
869                    args_ptr,
870                    args_size,
871                    result_size_ptr,
872                ) = Args::parse(args)?;
873                self.charge_host_function_call(
874                    &host_function_costs.call_contract,
875                    [
876                        contract_hash_ptr,
877                        contract_hash_size,
878                        entry_point_name_ptr,
879                        entry_point_name_size,
880                        args_ptr,
881                        args_size,
882                        result_size_ptr,
883                    ],
884                )?;
885
886                let contract_hash: AddressableEntityHash =
887                    self.t_from_mem(contract_hash_ptr, contract_hash_size)?;
888                let entry_point_name: String =
889                    self.t_from_mem(entry_point_name_ptr, entry_point_name_size)?;
890                let args_bytes: Vec<u8> = {
891                    let args_size: u32 = args_size;
892                    self.bytes_from_mem(args_ptr, args_size as usize)?.to_vec()
893                };
894
895                let ret = self.call_contract_host_buffer(
896                    contract_hash,
897                    &entry_point_name,
898                    &args_bytes,
899                    result_size_ptr,
900                )?;
901                Ok(Some(RuntimeValue::I32(api_error::i32_from(ret))))
902            }
903
904            FunctionIndex::CallVersionedContract => {
905                // args(0) = pointer to contract_package_hash where contract is at in global state
906                // args(1) = size of contract_package_hash
907                // args(2) = pointer to contract version in wasm memory
908                // args(3) = size of contract version in wasm memory
909                // args(4) = pointer to method name in wasm memory
910                // args(5) = size of method name in wasm memory
911                // args(6) = pointer to function arguments in Wasm memory
912                // args(7) = size of arguments
913                // args(8) = pointer to result size (output)
914                let (
915                    contract_package_hash_ptr,
916                    contract_package_hash_size,
917                    contract_version_ptr,
918                    contract_package_size,
919                    entry_point_name_ptr,
920                    entry_point_name_size,
921                    args_ptr,
922                    args_size,
923                    result_size_ptr,
924                ) = Args::parse(args)?;
925                self.charge_host_function_call(
926                    &host_function_costs.call_versioned_contract,
927                    [
928                        contract_package_hash_ptr,
929                        contract_package_hash_size,
930                        contract_version_ptr,
931                        contract_package_size,
932                        entry_point_name_ptr,
933                        entry_point_name_size,
934                        args_ptr,
935                        args_size,
936                        result_size_ptr,
937                    ],
938                )?;
939
940                let contract_package_hash: PackageHash =
941                    self.t_from_mem(contract_package_hash_ptr, contract_package_hash_size)?;
942                let contract_version: Option<EntityVersion> =
943                    self.t_from_mem(contract_version_ptr, contract_package_size)?;
944                let entry_point_name: String =
945                    self.t_from_mem(entry_point_name_ptr, entry_point_name_size)?;
946                let args_bytes: Vec<u8> = {
947                    let args_size: u32 = args_size;
948                    self.bytes_from_mem(args_ptr, args_size as usize)?.to_vec()
949                };
950
951                let ret = self.call_versioned_contract_host_buffer(
952                    contract_package_hash,
953                    contract_version,
954                    entry_point_name,
955                    &args_bytes,
956                    result_size_ptr,
957                )?;
958                Ok(Some(RuntimeValue::I32(api_error::i32_from(ret))))
959            }
960
961            #[cfg(feature = "test-support")]
962            FunctionIndex::PrintIndex => {
963                let (text_ptr, text_size) = Args::parse(args)?;
964                self.charge_host_function_call(&host_function_costs.print, [text_ptr, text_size])?;
965                self.print(text_ptr, text_size)?;
966                Ok(None)
967            }
968
969            FunctionIndex::GetRuntimeArgsizeIndex => {
970                // args(0) = pointer to name of host runtime arg to load
971                // args(1) = size of name of the host runtime arg
972                // args(2) = pointer to a argument size (output)
973                let (name_ptr, name_size, size_ptr) = Args::parse(args)?;
974                self.charge_host_function_call(
975                    &host_function_costs.get_named_arg_size,
976                    [name_ptr, name_size, size_ptr],
977                )?;
978                let ret = self.get_named_arg_size(name_ptr, name_size as usize, size_ptr)?;
979                Ok(Some(RuntimeValue::I32(api_error::i32_from(ret))))
980            }
981
982            FunctionIndex::GetRuntimeArgIndex => {
983                // args(0) = pointer to serialized argument name
984                // args(1) = size of serialized argument name
985                // args(2) = pointer to output pointer where host will write argument bytes
986                // args(3) = size of available data under output pointer
987                let (name_ptr, name_size, dest_ptr, dest_size) = Args::parse(args)?;
988                self.charge_host_function_call(
989                    &host_function_costs.get_named_arg,
990                    [name_ptr, name_size, dest_ptr, dest_size],
991                )?;
992                let ret =
993                    self.get_named_arg(name_ptr, name_size as usize, dest_ptr, dest_size as usize)?;
994                Ok(Some(RuntimeValue::I32(api_error::i32_from(ret))))
995            }
996
997            FunctionIndex::RemoveContractUserGroupIndex => {
998                // args(0) = pointer to package key in wasm memory
999                // args(1) = size of package key in wasm memory
1000                // args(2) = pointer to serialized group label
1001                // args(3) = size of serialized group label
1002                let (package_key_ptr, package_key_size, label_ptr, label_size) = Args::parse(args)?;
1003                self.charge_host_function_call(
1004                    &host_function_costs.remove_contract_user_group,
1005                    [package_key_ptr, package_key_size, label_ptr, label_size],
1006                )?;
1007                let package_key = self.t_from_mem(package_key_ptr, package_key_size)?;
1008                let label: Group = self.t_from_mem(label_ptr, label_size)?;
1009
1010                let ret = self.remove_contract_user_group(package_key, label)?;
1011                Ok(Some(RuntimeValue::I32(api_error::i32_from(ret))))
1012            }
1013
1014            FunctionIndex::ExtendContractUserGroupURefsIndex => {
1015                // args(0) = pointer to package key in wasm memory
1016                // args(1) = size of package key in wasm memory
1017                // args(2) = pointer to label name
1018                // args(3) = label size bytes
1019                // args(4) = output of size value of host bytes data
1020                let (package_ptr, package_size, label_ptr, label_size, value_size_ptr) =
1021                    Args::parse(args)?;
1022
1023                self.charge_host_function_call(
1024                    &host_function_costs.provision_contract_user_group_uref,
1025                    [
1026                        package_ptr,
1027                        package_size,
1028                        label_ptr,
1029                        label_size,
1030                        value_size_ptr,
1031                    ],
1032                )?;
1033                let ret = self.provision_contract_user_group_uref(
1034                    package_ptr,
1035                    package_size,
1036                    label_ptr,
1037                    label_size,
1038                    value_size_ptr,
1039                )?;
1040                Ok(Some(RuntimeValue::I32(api_error::i32_from(ret))))
1041            }
1042
1043            FunctionIndex::RemoveContractUserGroupURefsIndex => {
1044                // args(0) = pointer to package key in wasm memory
1045                // args(1) = size of package key in wasm memory
1046                // args(2) = pointer to label name
1047                // args(3) = label size bytes
1048                // args(4) = pointer to urefs
1049                // args(5) = size of urefs pointer
1050                let (package_ptr, package_size, label_ptr, label_size, urefs_ptr, urefs_size) =
1051                    Args::parse(args)?;
1052                self.charge_host_function_call(
1053                    &host_function_costs.remove_contract_user_group_urefs,
1054                    [
1055                        package_ptr,
1056                        package_size,
1057                        label_ptr,
1058                        label_size,
1059                        urefs_ptr,
1060                        urefs_size,
1061                    ],
1062                )?;
1063                let ret = self.remove_contract_user_group_urefs(
1064                    package_ptr,
1065                    package_size,
1066                    label_ptr,
1067                    label_size,
1068                    urefs_ptr,
1069                    urefs_size,
1070                )?;
1071                Ok(Some(RuntimeValue::I32(api_error::i32_from(ret))))
1072            }
1073
1074            FunctionIndex::Blake2b => {
1075                let (in_ptr, in_size, out_ptr, out_size) = Args::parse(args)?;
1076                self.charge_host_function_call(
1077                    &host_function_costs.blake2b,
1078                    [in_ptr, in_size, out_ptr, out_size],
1079                )?;
1080                let digest =
1081                    self.checked_memory_slice(in_ptr as usize, in_size as usize, |input| {
1082                        cryptography::blake2b(input)
1083                    })?;
1084
1085                let result = if digest.len() != out_size as usize {
1086                    Err(ApiError::BufferTooSmall)
1087                } else {
1088                    Ok(())
1089                };
1090                if result.is_err() {
1091                    return Ok(Some(RuntimeValue::I32(api_error::i32_from(result))));
1092                }
1093
1094                self.try_get_memory()?
1095                    .set(out_ptr, &digest)
1096                    .map_err(|error| ExecError::Interpreter(error.into()))?;
1097                Ok(Some(RuntimeValue::I32(0)))
1098            }
1099
1100            FunctionIndex::NewDictionaryFuncIndex => {
1101                // args(0) = pointer to output size (output param)
1102                let (output_size_ptr,): (u32,) = Args::parse(args)?;
1103                const UREF_LEN: u32 = 33u32;
1104                self.charge_host_function_call(&host_function_costs.new_uref, [0, 0, UREF_LEN])?;
1105                let ret = self.new_dictionary(output_size_ptr)?;
1106                Ok(Some(RuntimeValue::I32(api_error::i32_from(ret))))
1107            }
1108
1109            FunctionIndex::DictionaryGetFuncIndex => {
1110                // args(0) = pointer to uref in Wasm memory
1111                // args(1) = size of uref in Wasm memory
1112                // args(2) = pointer to key bytes pointer in Wasm memory
1113                // args(3) = pointer to key bytes size in Wasm memory
1114                // args(4) = pointer to output size (output param)
1115                let (uref_ptr, uref_size, key_bytes_ptr, key_bytes_size, output_size_ptr): (
1116                    _,
1117                    u32,
1118                    _,
1119                    u32,
1120                    _,
1121                ) = Args::parse(args)?;
1122                self.charge_host_function_call(
1123                    &host_function_costs.dictionary_get,
1124                    [key_bytes_ptr, key_bytes_size, output_size_ptr],
1125                )?;
1126                let ret = self.dictionary_get(
1127                    uref_ptr,
1128                    uref_size,
1129                    key_bytes_ptr,
1130                    key_bytes_size,
1131                    output_size_ptr,
1132                )?;
1133                Ok(Some(RuntimeValue::I32(api_error::i32_from(ret))))
1134            }
1135
1136            FunctionIndex::DictionaryPutFuncIndex => {
1137                // args(0) = pointer to uref in Wasm memory
1138                // args(1) = size of uref in Wasm memory
1139                // args(2) = pointer to key bytes pointer in Wasm memory
1140                // args(3) = pointer to key bytes size in Wasm memory
1141                // args(4) = pointer to value bytes pointer in Wasm memory
1142                // args(5) = pointer to value bytes size in Wasm memory
1143                let (uref_ptr, uref_size, key_bytes_ptr, key_bytes_size, value_ptr, value_ptr_size): (_, u32, _, u32, _, u32) = Args::parse(args)?;
1144                self.charge_host_function_call(
1145                    &host_function_costs.dictionary_put,
1146                    [key_bytes_ptr, key_bytes_size, value_ptr, value_ptr_size],
1147                )?;
1148                let ret = self.dictionary_put(
1149                    uref_ptr,
1150                    uref_size,
1151                    key_bytes_ptr,
1152                    key_bytes_size,
1153                    value_ptr,
1154                    value_ptr_size,
1155                )?;
1156                Ok(Some(RuntimeValue::I32(api_error::i32_from(ret))))
1157            }
1158
1159            FunctionIndex::DictionaryReadFuncIndex => {
1160                // args(0) = pointer to key in Wasm memory
1161                // args(1) = size of key in Wasm memory
1162                // args(2) = pointer to output size (output param)
1163                let (key_ptr, key_size, output_size_ptr) = Args::parse(args)?;
1164                self.charge_host_function_call(
1165                    &host_function_costs.read_value,
1166                    [key_ptr, key_size, output_size_ptr],
1167                )?;
1168                let ret = self.dictionary_read(key_ptr, key_size, output_size_ptr)?;
1169                Ok(Some(RuntimeValue::I32(api_error::i32_from(ret))))
1170            }
1171
1172            FunctionIndex::LoadCallStack => {
1173                // args(0) (Output) Pointer to number of elements in the call stack.
1174                // args(1) (Output) Pointer to size in bytes of the serialized call stack.
1175                let (call_stack_len_ptr, result_size_ptr) = Args::parse(args)?;
1176
1177                self.charge_host_function_call(
1178                    &HostFunction::fixed(10_000),
1179                    [call_stack_len_ptr, result_size_ptr],
1180                )?;
1181                let ret = self.load_call_stack(call_stack_len_ptr, result_size_ptr)?;
1182                Ok(Some(RuntimeValue::I32(api_error::i32_from(ret))))
1183            }
1184
1185            FunctionIndex::LoadCallerInformation => {
1186                // args(0) (Input) Type of action
1187                // args(1) (Output) Pointer to number of elements in the call stack.
1188                // args(2) (Output) Pointer to size in bytes of the serialized call stack.
1189                let (action, call_stack_len_ptr, result_size_ptr) = Args::parse(args)?;
1190                self.charge_host_function_call(
1191                    &HostFunction::fixed(10_000),
1192                    [0, call_stack_len_ptr, result_size_ptr],
1193                )?;
1194                let ret =
1195                    self.load_caller_information(action, call_stack_len_ptr, result_size_ptr)?;
1196                Ok(Some(RuntimeValue::I32(api_error::i32_from(ret))))
1197            }
1198
1199            FunctionIndex::LoadAuthorizationKeys => {
1200                // args(0) (Output) Pointer to number of authorization keys.
1201                // args(1) (Output) Pointer to size in bytes of the total bytes.
1202                let (len_ptr, result_size_ptr) = Args::parse(args)?;
1203                self.charge_host_function_call(
1204                    &HostFunction::fixed(10_000),
1205                    [len_ptr, result_size_ptr],
1206                )?;
1207                let ret = self.load_authorization_keys(len_ptr, result_size_ptr)?;
1208                Ok(Some(RuntimeValue::I32(api_error::i32_from(ret))))
1209            }
1210
1211            FunctionIndex::RandomBytes => {
1212                let (out_ptr, out_size) = Args::parse(args)?;
1213                self.charge_host_function_call(
1214                    &host_function_costs.random_bytes,
1215                    [out_ptr, out_size],
1216                )?;
1217
1218                let random_bytes = self.context.random_bytes()?;
1219
1220                let result = if random_bytes.len() != out_size as usize {
1221                    Err(ApiError::BufferTooSmall)
1222                } else {
1223                    Ok(())
1224                };
1225                if result.is_err() {
1226                    return Ok(Some(RuntimeValue::I32(api_error::i32_from(result))));
1227                }
1228
1229                self.try_get_memory()?
1230                    .set(out_ptr, &random_bytes)
1231                    .map_err(|error| ExecError::Interpreter(error.into()))?;
1232
1233                Ok(Some(RuntimeValue::I32(0)))
1234            }
1235
1236            FunctionIndex::EnableContractVersion => {
1237                // args(0) = pointer to package hash in wasm memory
1238                // args(1) = size of package hash in wasm memory
1239                // args(2) = pointer to contract hash in wasm memory
1240                // args(3) = size of contract hash in wasm memory
1241                let (package_key_ptr, package_key_size, contract_hash_ptr, contract_hash_size) =
1242                    Args::parse(args)?;
1243                self.charge_host_function_call(
1244                    &host_function_costs.enable_contract_version,
1245                    [
1246                        package_key_ptr,
1247                        package_key_size,
1248                        contract_hash_ptr,
1249                        contract_hash_size,
1250                    ],
1251                )?;
1252                let contract_package_hash = self.t_from_mem(package_key_ptr, package_key_size)?;
1253                let contract_hash = self.t_from_mem(contract_hash_ptr, contract_hash_size)?;
1254
1255                let result = self.enable_contract_version(contract_package_hash, contract_hash)?;
1256
1257                Ok(Some(RuntimeValue::I32(api_error::i32_from(result))))
1258            }
1259
1260            FunctionIndex::ManageMessageTopic => {
1261                // args(0) = pointer to the serialized topic name string in wasm memory
1262                // args(1) = size of the serialized topic name string in wasm memory
1263                // args(2) = pointer to the operation to be performed for the specified topic
1264                // args(3) = size of the operation
1265                let (topic_name_ptr, topic_name_size, operation_ptr, operation_size) =
1266                    Args::parse(args)?;
1267                self.charge_host_function_call(
1268                    &host_function_costs.manage_message_topic,
1269                    [
1270                        topic_name_ptr,
1271                        topic_name_size,
1272                        operation_ptr,
1273                        operation_size,
1274                    ],
1275                )?;
1276
1277                let limits = self.context.engine_config().wasm_config().messages_limits();
1278
1279                if topic_name_size > limits.max_topic_name_size() {
1280                    return Ok(Some(RuntimeValue::I32(api_error::i32_from(Err(
1281                        ApiError::MaxTopicNameSizeExceeded,
1282                    )))));
1283                }
1284
1285                let topic_name_bytes =
1286                    self.bytes_from_mem(topic_name_ptr, topic_name_size as usize)?;
1287                let topic_name = std::str::from_utf8(&topic_name_bytes)
1288                    .map_err(|e| Trap::from(ExecError::InvalidUtf8Encoding(e)))?;
1289
1290                if operation_size as usize > MessageTopicOperation::max_serialized_len() {
1291                    return Err(Trap::from(ExecError::InvalidImputedOperation));
1292                }
1293                let topic_operation = self
1294                    .t_from_mem(operation_ptr, operation_size)
1295                    .map_err(|_e| Trap::from(ExecError::InvalidImputedOperation))?;
1296
1297                // only allow managing messages from stored contracts
1298                if !self.context.get_context_key().is_smart_contract_key() {
1299                    return Err(Trap::from(ExecError::InvalidContext));
1300                }
1301
1302                let result = match topic_operation {
1303                    MessageTopicOperation::Add => {
1304                        self.add_message_topic(topic_name).map_err(Trap::from)?
1305                    }
1306                };
1307
1308                Ok(Some(RuntimeValue::I32(api_error::i32_from(result))))
1309            }
1310
1311            FunctionIndex::EmitMessage => {
1312                // args(0) = pointer to the serialized topic name string in wasm memory
1313                // args(1) = size of the serialized name string in wasm memory
1314                // args(2) = pointer to the serialized message payload in wasm memory
1315                // args(3) = size of the serialized message payload in wasm memory
1316                let (topic_name_ptr, topic_name_size, message_ptr, message_size) =
1317                    Args::parse(args)?;
1318
1319                // Charge for the call to emit message. This increases for every message emitted
1320                // within an execution so we're not using the static value from the wasm config.
1321                self.context
1322                    .charge_gas(Gas::new(self.context.emit_message_cost()))?;
1323                // Charge for parameter weights.
1324                self.charge_host_function_call(
1325                    &HostFunction::new(0, host_function_costs.emit_message.arguments()),
1326                    &[topic_name_ptr, topic_name_size, message_ptr, message_size],
1327                )?;
1328
1329                let limits = self.context.engine_config().wasm_config().messages_limits();
1330
1331                if topic_name_size > limits.max_topic_name_size() {
1332                    return Ok(Some(RuntimeValue::I32(api_error::i32_from(Err(
1333                        ApiError::MaxTopicNameSizeExceeded,
1334                    )))));
1335                }
1336
1337                if message_size > limits.max_message_size() {
1338                    return Ok(Some(RuntimeValue::I32(api_error::i32_from(Err(
1339                        ApiError::MessageTooLarge,
1340                    )))));
1341                }
1342
1343                let topic_name_bytes =
1344                    self.bytes_from_mem(topic_name_ptr, topic_name_size as usize)?;
1345                let topic_name = std::str::from_utf8(&topic_name_bytes)
1346                    .map_err(|e| Trap::from(ExecError::InvalidUtf8Encoding(e)))?;
1347
1348                let message = self.t_from_mem(message_ptr, message_size)?;
1349
1350                let result = self.emit_message(topic_name, message)?;
1351                if result.is_ok() {
1352                    // Increase the cost for the next call to emit a message.
1353                    let new_cost = self
1354                        .context
1355                        .emit_message_cost()
1356                        .checked_add(host_function_costs.cost_increase_per_message.into())
1357                        .ok_or(ExecError::GasLimit)?;
1358                    self.context.set_emit_message_cost(new_cost);
1359                }
1360                Ok(Some(RuntimeValue::I32(api_error::i32_from(result))))
1361            }
1362
1363            FunctionIndex::GetBlockInfoIndex => {
1364                // args(0) = field selector
1365                // args(1) = pointer to output pointer where host will write argument bytes
1366                let (field_idx, dest_ptr): (u8, u32) = Args::parse(args)?;
1367
1368                self.charge_host_function_call(&host_function_costs.get_block_info, [0u32, 0u32])?;
1369                self.get_block_info(field_idx, dest_ptr)?;
1370                Ok(None)
1371            }
1372
1373            FunctionIndex::GenericHash => {
1374                // args(0) = pointer to input in Wasm memory
1375                // args(1) = size of input in Wasm memory
1376                // args(2) = integer representation of HashAlgorithm enum variant
1377                // args(3) = pointer to output pointer in Wasm memory
1378                // args(4) = size of output
1379                let (in_ptr, in_size, hash_algo_type, out_ptr, out_size) = Args::parse(args)?;
1380                self.charge_host_function_call(
1381                    &host_function_costs.generic_hash,
1382                    [in_ptr, in_size, hash_algo_type, out_ptr, out_size],
1383                )?;
1384                let hash_algo_type = match HashAlgorithm::try_from(hash_algo_type as u8) {
1385                    Ok(v) => v,
1386                    Err(_e) => {
1387                        return Ok(Some(RuntimeValue::I32(api_error::i32_from(Err(
1388                            ApiError::InvalidArgument,
1389                        )))))
1390                    }
1391                };
1392
1393                let digest =
1394                    self.checked_memory_slice(in_ptr as usize, in_size as usize, |input| {
1395                        match hash_algo_type {
1396                            HashAlgorithm::Blake2b => cryptography::blake2b(input),
1397                            HashAlgorithm::Blake3 => cryptography::blake3(input),
1398                            HashAlgorithm::Sha256 => cryptography::sha256(input),
1399                        }
1400                    })?;
1401
1402                let result = if digest.len() > out_size as usize {
1403                    Err(ApiError::BufferTooSmall)
1404                } else {
1405                    Ok(())
1406                };
1407
1408                if result.is_err() {
1409                    return Ok(Some(RuntimeValue::I32(api_error::i32_from(result))));
1410                }
1411
1412                if self.try_get_memory()?.set(out_ptr, &digest).is_err() {
1413                    return Ok(Some(RuntimeValue::I32(
1414                        u32::from(ApiError::HostBufferEmpty) as i32,
1415                    )));
1416                }
1417
1418                Ok(Some(RuntimeValue::I32(0)))
1419            }
1420
1421            FunctionIndex::RecoverSecp256k1 => {
1422                // args(0) = pointer to input bytes in memory
1423                // args(1) = length of input bytes in memory
1424                // args(2) = pointer to signature bytes in memory
1425                // args(3) = length of signature bytes in memory
1426                // args(4) = pointer to public key buffer in memory (size is fixed)
1427                // args(5) = the recovery id
1428
1429                let (
1430                    data_ptr,
1431                    data_size,
1432                    signature_ptr,
1433                    signature_size,
1434                    public_key_ptr,
1435                    recovery_id,
1436                ) = Args::parse(args)?;
1437
1438                self.charge_host_function_call(
1439                    &host_function_costs.recover_secp256k1,
1440                    [
1441                        data_ptr,
1442                        data_size,
1443                        signature_ptr,
1444                        signature_size,
1445                        public_key_ptr,
1446                        recovery_id,
1447                    ],
1448                )?;
1449
1450                if recovery_id >= 4 {
1451                    return Ok(Some(RuntimeValue::I32(
1452                        u32::from(ApiError::InvalidArgument) as i32,
1453                    )));
1454                }
1455
1456                let data = self.bytes_from_mem(data_ptr, data_size as usize)?;
1457                let signature: Signature = self.t_from_mem(signature_ptr, signature_size)?;
1458
1459                let Ok(public_key) =
1460                    casper_types::crypto::recover_secp256k1(data, &signature, recovery_id as u8)
1461                else {
1462                    return Ok(Some(RuntimeValue::I32(
1463                        u32::from(ApiError::InvalidArgument) as i32,
1464                    )));
1465                };
1466
1467                let Ok(key_bytes) = public_key.to_bytes() else {
1468                    return Ok(Some(RuntimeValue::I32(
1469                        u32::from(ApiError::OutOfMemory) as i32
1470                    )));
1471                };
1472
1473                if self
1474                    .try_get_memory()?
1475                    .set(public_key_ptr, &key_bytes)
1476                    .is_err()
1477                {
1478                    return Ok(Some(RuntimeValue::I32(
1479                        u32::from(ApiError::HostBufferEmpty) as i32,
1480                    )));
1481                }
1482
1483                Ok(Some(RuntimeValue::I32(0)))
1484            }
1485
1486            FunctionIndex::VerifySignature => {
1487                // args(0) = pointer to message bytes in memory
1488                // args(1) = length of message bytes
1489                // args(2) = pointer to signature bytes in memory
1490                // args(3) = length of signature bytes
1491                // args(4) = pointer to public key bytes in memory
1492                // args(5) = length of public key bytes
1493                let (
1494                    message_ptr,
1495                    message_size,
1496                    signature_ptr,
1497                    signature_size,
1498                    public_key_ptr,
1499                    public_key_size,
1500                ) = Args::parse(args)?;
1501
1502                self.charge_host_function_call(
1503                    &host_function_costs.verify_signature,
1504                    [
1505                        message_ptr,
1506                        message_size,
1507                        signature_ptr,
1508                        signature_size,
1509                        public_key_ptr,
1510                        public_key_size,
1511                    ],
1512                )?;
1513
1514                let message = self.bytes_from_mem(message_ptr, message_size as usize)?;
1515                let signature: Signature = self.t_from_mem(signature_ptr, signature_size)?;
1516                let public_key: PublicKey = self.t_from_mem(public_key_ptr, public_key_size)?;
1517
1518                if casper_types::crypto::verify(message, &signature, &public_key).is_err() {
1519                    return Ok(Some(RuntimeValue::I32(
1520                        u32::from(ApiError::InvalidArgument) as i32,
1521                    )));
1522                }
1523
1524                Ok(Some(RuntimeValue::I32(0)))
1525            }
1526        }
1527    }
1528}