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