1use std::{
2 collections::{BTreeMap, BTreeSet},
3 convert::TryFrom,
4};
5
6use casper_wasmi::{Externals, RuntimeArgs, RuntimeValue, Trap};
7
8use casper_storage::global_state::{error::Error as GlobalStateError, state::StateReader};
9use casper_types::{
10 account::AccountHash,
11 addressable_entity::{EntityEntryPoint, EntryPoints},
12 api_error,
13 bytesrepr::{self, ToBytes},
14 contract_messages::MessageTopicOperation,
15 contracts::{ContractPackageHash, EntryPoints as ContractEntryPoints, NamedKeys},
16 AddressableEntityHash, ApiError, EntityVersion, Gas, Group, HashAlgorithm, HostFunction,
17 HostFunctionCost, Key, PackageHash, PackageStatus, PublicKey, Signature, StoredValue, URef,
18 U512, UREF_SERIALIZED_LENGTH,
19};
20
21use super::{args::Args, ExecError, Runtime};
22use crate::{resolvers::v1_function_index::FunctionIndex, runtime::cryptography};
23
24impl<R> Externals for Runtime<'_, R>
25where
26 R: StateReader<Key, StoredValue, Error = GlobalStateError>,
27{
28 fn invoke_index(
29 &mut self,
30 index: usize,
31 args: RuntimeArgs,
32 ) -> Result<Option<RuntimeValue>, Trap> {
33 let func = FunctionIndex::try_from(index).expect("unknown function index");
34
35 let host_function_costs =
36 (*self.context.engine_config().wasm_config().v1()).take_host_function_costs();
37
38 match func {
39 FunctionIndex::ReadFuncIndex => {
40 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 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 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 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 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 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 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 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 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 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 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 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 self.gas(Gas::new(gas_arg))?;
194 Ok(None)
195 }
196
197 FunctionIndex::IsValidURefFnIndex => {
198 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 let (
616 contract_package_hash_ptr,
617 contract_package_hash_size,
618 version_ptr,
619 entry_points_ptr,
620 entry_points_size,
621 named_keys_ptr,
622 named_keys_size,
623 output_ptr,
624 output_size,
625 bytes_written_ptr,
626 ) = Args::parse(args)?;
627 self.charge_host_function_call(
628 &host_function_costs.add_contract_version,
629 [
630 contract_package_hash_ptr,
631 contract_package_hash_size,
632 version_ptr,
633 entry_points_ptr,
634 entry_points_size,
635 named_keys_ptr,
636 named_keys_size,
637 output_ptr,
638 output_size,
639 bytes_written_ptr,
640 ],
641 )?;
642
643 let contract_package_hash: ContractPackageHash =
644 self.t_from_mem(contract_package_hash_ptr, contract_package_hash_size)?;
645 let package_hash = PackageHash::new(contract_package_hash.value());
646 let entry_points: EntryPoints = {
647 let contract_entry_points: ContractEntryPoints =
648 self.t_from_mem(entry_points_ptr, entry_points_size)?;
649
650 let points: Vec<EntityEntryPoint> = contract_entry_points
651 .take_entry_points()
652 .into_iter()
653 .map(EntityEntryPoint::from)
654 .collect();
655
656 points.into()
657 };
658 let named_keys: NamedKeys = self.t_from_mem(named_keys_ptr, named_keys_size)?;
659 let ret = self.add_contract_version(
660 package_hash,
661 version_ptr,
662 entry_points,
663 named_keys,
664 BTreeMap::new(),
665 output_ptr,
666 )?;
667 Ok(Some(RuntimeValue::I32(api_error::i32_from(ret))))
668 }
669 FunctionIndex::AddContractVersionWithMessageTopics => {
670 let (
682 contract_package_hash_ptr,
683 contract_package_hash_size,
684 version_ptr,
685 entry_points_ptr,
686 entry_points_size,
687 named_keys_ptr,
688 named_keys_size,
689 message_topics_ptr,
690 message_topics_size,
691 output_ptr,
692 output_size,
693 ) = Args::parse(args)?;
694 self.charge_host_function_call(
695 &host_function_costs.add_contract_version_with_message_topics,
696 [
697 contract_package_hash_ptr,
698 contract_package_hash_size,
699 version_ptr,
700 entry_points_ptr,
701 entry_points_size,
702 named_keys_ptr,
703 named_keys_size,
704 message_topics_ptr,
705 message_topics_size,
706 output_ptr,
707 output_size,
708 ],
709 )?;
710
711 if output_size < 32 {
713 return Ok(Some(RuntimeValue::I32(api_error::i32_from(Err(
715 ApiError::BufferTooSmall,
716 )))));
717 }
718
719 let package_hash: PackageHash =
720 self.t_from_mem(contract_package_hash_ptr, contract_package_hash_size)?;
721 let entry_points: EntryPoints =
722 self.t_from_mem(entry_points_ptr, entry_points_size)?;
723 let named_keys: NamedKeys = self.t_from_mem(named_keys_ptr, named_keys_size)?;
724 let message_topics: BTreeMap<String, MessageTopicOperation> =
725 self.t_from_mem(message_topics_ptr, message_topics_size)?;
726
727 let message_limits = self.context.engine_config().wasm_config().messages_limits();
730 for (topic_name, _) in
731 message_topics
732 .iter()
733 .filter(|(_, operation)| match operation {
734 MessageTopicOperation::Add => true,
735 })
736 {
737 if topic_name.len() > message_limits.max_topic_name_size() as usize {
738 return Ok(Some(RuntimeValue::I32(api_error::i32_from(Err(
739 ApiError::MaxTopicNameSizeExceeded,
740 )))));
741 }
742 }
743
744 let ret = self.add_contract_version(
745 package_hash,
746 version_ptr,
747 entry_points,
748 named_keys,
749 message_topics,
750 output_ptr,
751 )?;
752 Ok(Some(RuntimeValue::I32(api_error::i32_from(ret))))
753 }
754
755 FunctionIndex::AddPackageVersionWithMessageTopics => {
756 let (
768 contract_package_hash_ptr,
769 contract_package_hash_size,
770 version_ptr,
771 entry_points_ptr,
772 entry_points_size,
773 named_keys_ptr,
774 named_keys_size,
775 message_topics,
776 message_topics_size,
777 output_ptr,
778 output_size,
779 ) = Args::parse(args)?;
780
781 self.charge_host_function_call(
782 &host_function_costs.add_package_version_with_message_topics,
783 [
784 contract_package_hash_ptr,
785 contract_package_hash_size,
786 version_ptr,
787 entry_points_ptr,
788 entry_points_size,
789 named_keys_ptr,
790 named_keys_size,
791 message_topics,
792 message_topics_size,
793 output_ptr,
794 output_size,
795 ],
796 )?;
797
798 if output_size < 32 {
800 return Ok(Some(RuntimeValue::I32(api_error::i32_from(Err(
802 ApiError::BufferTooSmall,
803 )))));
804 }
805
806 let package_hash: PackageHash =
807 self.t_from_mem(contract_package_hash_ptr, contract_package_hash_size)?;
808 let entry_points: EntryPoints =
809 self.t_from_mem(entry_points_ptr, entry_points_size)?;
810 let named_keys: NamedKeys = self.t_from_mem(named_keys_ptr, named_keys_size)?;
811 let message_topics: BTreeMap<String, MessageTopicOperation> =
812 self.t_from_mem(message_topics, message_topics_size)?;
813
814 let message_limits = self.context.engine_config().wasm_config().messages_limits();
817 for (topic_name, _) in
818 message_topics
819 .iter()
820 .filter(|(_, operation)| match operation {
821 MessageTopicOperation::Add => true,
822 })
823 {
824 if topic_name.len() > message_limits.max_topic_name_size() as usize {
825 return Ok(Some(RuntimeValue::I32(api_error::i32_from(Err(
826 ApiError::MaxTopicNameSizeExceeded,
827 )))));
828 }
829 }
830
831 let ret = self.add_contract_version(
832 package_hash,
833 version_ptr,
834 entry_points,
835 named_keys,
836 message_topics,
837 output_ptr,
838 )?;
839 Ok(Some(RuntimeValue::I32(api_error::i32_from(ret))))
840 }
841
842 FunctionIndex::DisableContractVersion => {
843 let (package_key_ptr, package_key_size, contract_hash_ptr, contract_hash_size) =
848 Args::parse(args)?;
849 self.charge_host_function_call(
850 &host_function_costs.disable_contract_version,
851 [
852 package_key_ptr,
853 package_key_size,
854 contract_hash_ptr,
855 contract_hash_size,
856 ],
857 )?;
858 let contract_package_hash = self.t_from_mem(package_key_ptr, package_key_size)?;
859 let contract_hash = self.t_from_mem(contract_hash_ptr, contract_hash_size)?;
860
861 let result = self.disable_contract_version(contract_package_hash, contract_hash)?;
862
863 Ok(Some(RuntimeValue::I32(api_error::i32_from(result))))
864 }
865
866 FunctionIndex::CallContractFuncIndex => {
867 let (
875 contract_hash_ptr,
876 contract_hash_size,
877 entry_point_name_ptr,
878 entry_point_name_size,
879 args_ptr,
880 args_size,
881 result_size_ptr,
882 ) = Args::parse(args)?;
883 self.charge_host_function_call(
884 &host_function_costs.call_contract,
885 [
886 contract_hash_ptr,
887 contract_hash_size,
888 entry_point_name_ptr,
889 entry_point_name_size,
890 args_ptr,
891 args_size,
892 result_size_ptr,
893 ],
894 )?;
895
896 let contract_hash: AddressableEntityHash =
897 self.t_from_mem(contract_hash_ptr, contract_hash_size)?;
898 let entry_point_name: String =
899 self.t_from_mem(entry_point_name_ptr, entry_point_name_size)?;
900 let args_bytes: Vec<u8> = {
901 let args_size: u32 = args_size;
902 self.bytes_from_mem(args_ptr, args_size as usize)?.to_vec()
903 };
904
905 let ret = self.call_contract_host_buffer(
906 contract_hash,
907 &entry_point_name,
908 &args_bytes,
909 result_size_ptr,
910 )?;
911 Ok(Some(RuntimeValue::I32(api_error::i32_from(ret))))
912 }
913
914 FunctionIndex::CallVersionedContract => {
915 let (
925 contract_package_hash_ptr,
926 contract_package_hash_size,
927 contract_version_ptr,
928 contract_package_size,
929 entry_point_name_ptr,
930 entry_point_name_size,
931 args_ptr,
932 args_size,
933 result_size_ptr,
934 ) = Args::parse(args)?;
935 self.charge_host_function_call(
936 &host_function_costs.call_versioned_contract,
937 [
938 contract_package_hash_ptr,
939 contract_package_hash_size,
940 contract_version_ptr,
941 contract_package_size,
942 entry_point_name_ptr,
943 entry_point_name_size,
944 args_ptr,
945 args_size,
946 result_size_ptr,
947 ],
948 )?;
949
950 let contract_package_hash: PackageHash =
951 self.t_from_mem(contract_package_hash_ptr, contract_package_hash_size)?;
952 let contract_version: Option<EntityVersion> =
953 self.t_from_mem(contract_version_ptr, contract_package_size)?;
954 let entry_point_name: String =
955 self.t_from_mem(entry_point_name_ptr, entry_point_name_size)?;
956 let args_bytes: Vec<u8> = {
957 let args_size: u32 = args_size;
958 self.bytes_from_mem(args_ptr, args_size as usize)?.to_vec()
959 };
960
961 let ret = self.call_versioned_contract_host_buffer(
962 contract_package_hash,
963 contract_version,
964 entry_point_name,
965 &args_bytes,
966 result_size_ptr,
967 )?;
968 Ok(Some(RuntimeValue::I32(api_error::i32_from(ret))))
969 }
970
971 #[cfg(feature = "test-support")]
972 FunctionIndex::PrintIndex => {
973 let (text_ptr, text_size) = Args::parse(args)?;
974 self.charge_host_function_call(&host_function_costs.print, [text_ptr, text_size])?;
975 self.print(text_ptr, text_size)?;
976 Ok(None)
977 }
978
979 FunctionIndex::GetRuntimeArgsizeIndex => {
980 let (name_ptr, name_size, size_ptr) = Args::parse(args)?;
984 self.charge_host_function_call(
985 &host_function_costs.get_named_arg_size,
986 [name_ptr, name_size, size_ptr],
987 )?;
988 let ret = self.get_named_arg_size(name_ptr, name_size as usize, size_ptr)?;
989 Ok(Some(RuntimeValue::I32(api_error::i32_from(ret))))
990 }
991
992 FunctionIndex::GetRuntimeArgIndex => {
993 let (name_ptr, name_size, dest_ptr, dest_size) = Args::parse(args)?;
998 self.charge_host_function_call(
999 &host_function_costs.get_named_arg,
1000 [name_ptr, name_size, dest_ptr, dest_size],
1001 )?;
1002 let ret =
1003 self.get_named_arg(name_ptr, name_size as usize, dest_ptr, dest_size as usize)?;
1004 Ok(Some(RuntimeValue::I32(api_error::i32_from(ret))))
1005 }
1006
1007 FunctionIndex::RemoveContractUserGroupIndex => {
1008 let (package_key_ptr, package_key_size, label_ptr, label_size) = Args::parse(args)?;
1013 self.charge_host_function_call(
1014 &host_function_costs.remove_contract_user_group,
1015 [package_key_ptr, package_key_size, label_ptr, label_size],
1016 )?;
1017 let package_key = self.t_from_mem(package_key_ptr, package_key_size)?;
1018 let label: Group = self.t_from_mem(label_ptr, label_size)?;
1019
1020 let ret = self.remove_contract_user_group(package_key, label)?;
1021 Ok(Some(RuntimeValue::I32(api_error::i32_from(ret))))
1022 }
1023
1024 FunctionIndex::ExtendContractUserGroupURefsIndex => {
1025 let (package_ptr, package_size, label_ptr, label_size, value_size_ptr) =
1031 Args::parse(args)?;
1032
1033 self.charge_host_function_call(
1034 &host_function_costs.provision_contract_user_group_uref,
1035 [
1036 package_ptr,
1037 package_size,
1038 label_ptr,
1039 label_size,
1040 value_size_ptr,
1041 ],
1042 )?;
1043 let ret = self.provision_contract_user_group_uref(
1044 package_ptr,
1045 package_size,
1046 label_ptr,
1047 label_size,
1048 value_size_ptr,
1049 )?;
1050 Ok(Some(RuntimeValue::I32(api_error::i32_from(ret))))
1051 }
1052
1053 FunctionIndex::RemoveContractUserGroupURefsIndex => {
1054 let (package_ptr, package_size, label_ptr, label_size, urefs_ptr, urefs_size) =
1061 Args::parse(args)?;
1062 self.charge_host_function_call(
1063 &host_function_costs.remove_contract_user_group_urefs,
1064 [
1065 package_ptr,
1066 package_size,
1067 label_ptr,
1068 label_size,
1069 urefs_ptr,
1070 urefs_size,
1071 ],
1072 )?;
1073 let ret = self.remove_contract_user_group_urefs(
1074 package_ptr,
1075 package_size,
1076 label_ptr,
1077 label_size,
1078 urefs_ptr,
1079 urefs_size,
1080 )?;
1081 Ok(Some(RuntimeValue::I32(api_error::i32_from(ret))))
1082 }
1083
1084 FunctionIndex::Blake2b => {
1085 let (in_ptr, in_size, out_ptr, out_size) = Args::parse(args)?;
1086 self.charge_host_function_call(
1087 &host_function_costs.blake2b,
1088 [in_ptr, in_size, out_ptr, out_size],
1089 )?;
1090 let digest =
1091 self.checked_memory_slice(in_ptr as usize, in_size as usize, |input| {
1092 cryptography::blake2b(input)
1093 })?;
1094
1095 let result = if digest.len() != out_size as usize {
1096 Err(ApiError::BufferTooSmall)
1097 } else {
1098 Ok(())
1099 };
1100 if result.is_err() {
1101 return Ok(Some(RuntimeValue::I32(api_error::i32_from(result))));
1102 }
1103
1104 self.try_get_memory()?
1105 .set(out_ptr, &digest)
1106 .map_err(|error| ExecError::Interpreter(error.into()))?;
1107 Ok(Some(RuntimeValue::I32(0)))
1108 }
1109
1110 FunctionIndex::NewDictionaryFuncIndex => {
1111 let (output_size_ptr,): (u32,) = Args::parse(args)?;
1113 const UREF_LEN: u32 = 33u32;
1114 self.charge_host_function_call(&host_function_costs.new_uref, [0, 0, UREF_LEN])?;
1115 let ret = self.new_dictionary(output_size_ptr)?;
1116 Ok(Some(RuntimeValue::I32(api_error::i32_from(ret))))
1117 }
1118
1119 FunctionIndex::DictionaryGetFuncIndex => {
1120 let (uref_ptr, uref_size, key_bytes_ptr, key_bytes_size, output_size_ptr): (
1126 _,
1127 u32,
1128 _,
1129 u32,
1130 _,
1131 ) = Args::parse(args)?;
1132 self.charge_host_function_call(
1133 &host_function_costs.dictionary_get,
1134 [key_bytes_ptr, key_bytes_size, output_size_ptr],
1135 )?;
1136 let ret = self.dictionary_get(
1137 uref_ptr,
1138 uref_size,
1139 key_bytes_ptr,
1140 key_bytes_size,
1141 output_size_ptr,
1142 )?;
1143 Ok(Some(RuntimeValue::I32(api_error::i32_from(ret))))
1144 }
1145
1146 FunctionIndex::DictionaryPutFuncIndex => {
1147 let (uref_ptr, uref_size, key_bytes_ptr, key_bytes_size, value_ptr, value_ptr_size): (_, u32, _, u32, _, u32) = Args::parse(args)?;
1154 self.charge_host_function_call(
1155 &host_function_costs.dictionary_put,
1156 [key_bytes_ptr, key_bytes_size, value_ptr, value_ptr_size],
1157 )?;
1158 let ret = self.dictionary_put(
1159 uref_ptr,
1160 uref_size,
1161 key_bytes_ptr,
1162 key_bytes_size,
1163 value_ptr,
1164 value_ptr_size,
1165 )?;
1166 Ok(Some(RuntimeValue::I32(api_error::i32_from(ret))))
1167 }
1168
1169 FunctionIndex::DictionaryReadFuncIndex => {
1170 let (key_ptr, key_size, output_size_ptr) = Args::parse(args)?;
1174 self.charge_host_function_call(
1175 &host_function_costs.read_value,
1176 [key_ptr, key_size, output_size_ptr],
1177 )?;
1178 let ret = self.dictionary_read(key_ptr, key_size, output_size_ptr)?;
1179 Ok(Some(RuntimeValue::I32(api_error::i32_from(ret))))
1180 }
1181
1182 FunctionIndex::LoadCallStack => {
1183 let (call_stack_len_ptr, result_size_ptr) = Args::parse(args)?;
1186
1187 self.charge_host_function_call(
1188 &HostFunction::fixed(10_000),
1189 [call_stack_len_ptr, result_size_ptr],
1190 )?;
1191 let ret = self.load_call_stack(call_stack_len_ptr, result_size_ptr)?;
1192 Ok(Some(RuntimeValue::I32(api_error::i32_from(ret))))
1193 }
1194
1195 FunctionIndex::LoadCallerInformation => {
1196 let (action, call_stack_len_ptr, result_size_ptr) = Args::parse(args)?;
1200 self.charge_host_function_call(
1201 &HostFunction::fixed(10_000),
1202 [0, call_stack_len_ptr, result_size_ptr],
1203 )?;
1204 let ret =
1205 self.load_caller_information(action, call_stack_len_ptr, result_size_ptr)?;
1206 Ok(Some(RuntimeValue::I32(api_error::i32_from(ret))))
1207 }
1208
1209 FunctionIndex::LoadAuthorizationKeys => {
1210 let (len_ptr, result_size_ptr) = Args::parse(args)?;
1213 self.charge_host_function_call(
1214 &HostFunction::fixed(10_000),
1215 [len_ptr, result_size_ptr],
1216 )?;
1217 let ret = self.load_authorization_keys(len_ptr, result_size_ptr)?;
1218 Ok(Some(RuntimeValue::I32(api_error::i32_from(ret))))
1219 }
1220
1221 FunctionIndex::RandomBytes => {
1222 let (out_ptr, out_size) = Args::parse(args)?;
1223 self.charge_host_function_call(
1224 &host_function_costs.random_bytes,
1225 [out_ptr, out_size],
1226 )?;
1227
1228 let random_bytes = self.context.random_bytes()?;
1229
1230 let result = if random_bytes.len() != out_size as usize {
1231 Err(ApiError::BufferTooSmall)
1232 } else {
1233 Ok(())
1234 };
1235 if result.is_err() {
1236 return Ok(Some(RuntimeValue::I32(api_error::i32_from(result))));
1237 }
1238
1239 self.try_get_memory()?
1240 .set(out_ptr, &random_bytes)
1241 .map_err(|error| ExecError::Interpreter(error.into()))?;
1242
1243 Ok(Some(RuntimeValue::I32(0)))
1244 }
1245
1246 FunctionIndex::EnableContractVersion => {
1247 let (package_key_ptr, package_key_size, contract_hash_ptr, contract_hash_size) =
1252 Args::parse(args)?;
1253 self.charge_host_function_call(
1254 &host_function_costs.enable_contract_version,
1255 [
1256 package_key_ptr,
1257 package_key_size,
1258 contract_hash_ptr,
1259 contract_hash_size,
1260 ],
1261 )?;
1262 let contract_package_hash = self.t_from_mem(package_key_ptr, package_key_size)?;
1263 let contract_hash = self.t_from_mem(contract_hash_ptr, contract_hash_size)?;
1264
1265 let result = self.enable_contract_version(contract_package_hash, contract_hash)?;
1266
1267 Ok(Some(RuntimeValue::I32(api_error::i32_from(result))))
1268 }
1269
1270 FunctionIndex::ManageMessageTopic => {
1271 let (topic_name_ptr, topic_name_size, operation_ptr, operation_size) =
1276 Args::parse(args)?;
1277 self.charge_host_function_call(
1278 &host_function_costs.manage_message_topic,
1279 [
1280 topic_name_ptr,
1281 topic_name_size,
1282 operation_ptr,
1283 operation_size,
1284 ],
1285 )?;
1286
1287 let limits = self.context.engine_config().wasm_config().messages_limits();
1288
1289 if topic_name_size > limits.max_topic_name_size() {
1290 return Ok(Some(RuntimeValue::I32(api_error::i32_from(Err(
1291 ApiError::MaxTopicNameSizeExceeded,
1292 )))));
1293 }
1294
1295 let topic_name_bytes =
1296 self.bytes_from_mem(topic_name_ptr, topic_name_size as usize)?;
1297 let topic_name = std::str::from_utf8(&topic_name_bytes)
1298 .map_err(|e| Trap::from(ExecError::InvalidUtf8Encoding(e)))?;
1299
1300 if operation_size as usize > MessageTopicOperation::max_serialized_len() {
1301 return Err(Trap::from(ExecError::InvalidImputedOperation));
1302 }
1303 let topic_operation = self
1304 .t_from_mem(operation_ptr, operation_size)
1305 .map_err(|_e| Trap::from(ExecError::InvalidImputedOperation))?;
1306
1307 if !self.context.get_context_key().is_smart_contract_key() {
1309 return Err(Trap::from(ExecError::InvalidContext));
1310 }
1311
1312 let result = match topic_operation {
1313 MessageTopicOperation::Add => {
1314 self.add_message_topic(topic_name).map_err(Trap::from)?
1315 }
1316 };
1317
1318 Ok(Some(RuntimeValue::I32(api_error::i32_from(result))))
1319 }
1320
1321 FunctionIndex::EmitMessage => {
1322 let (topic_name_ptr, topic_name_size, message_ptr, message_size) =
1327 Args::parse(args)?;
1328
1329 self.context
1332 .charge_gas(Gas::new(self.context.emit_message_cost()))?;
1333 self.charge_host_function_call(
1335 &HostFunction::new(0, host_function_costs.emit_message.arguments()),
1336 &[topic_name_ptr, topic_name_size, message_ptr, message_size],
1337 )?;
1338
1339 let limits = self.context.engine_config().wasm_config().messages_limits();
1340
1341 if topic_name_size > limits.max_topic_name_size() {
1342 return Ok(Some(RuntimeValue::I32(api_error::i32_from(Err(
1343 ApiError::MaxTopicNameSizeExceeded,
1344 )))));
1345 }
1346
1347 if message_size > limits.max_message_size() {
1348 return Ok(Some(RuntimeValue::I32(api_error::i32_from(Err(
1349 ApiError::MessageTooLarge,
1350 )))));
1351 }
1352
1353 let topic_name_bytes =
1354 self.bytes_from_mem(topic_name_ptr, topic_name_size as usize)?;
1355 let topic_name = std::str::from_utf8(&topic_name_bytes)
1356 .map_err(|e| Trap::from(ExecError::InvalidUtf8Encoding(e)))?;
1357
1358 let message = self.t_from_mem(message_ptr, message_size)?;
1359
1360 let result = self.emit_message(topic_name, message)?;
1361 if result.is_ok() {
1362 let new_cost = self
1364 .context
1365 .emit_message_cost()
1366 .checked_add(host_function_costs.cost_increase_per_message.into())
1367 .ok_or(ExecError::GasLimit)?;
1368 self.context.set_emit_message_cost(new_cost);
1369 }
1370 Ok(Some(RuntimeValue::I32(api_error::i32_from(result))))
1371 }
1372
1373 FunctionIndex::GetBlockInfoIndex => {
1374 let (field_idx, dest_ptr): (u8, u32) = Args::parse(args)?;
1377
1378 self.charge_host_function_call(&host_function_costs.get_block_info, [0u32, 0u32])?;
1379 self.get_block_info(field_idx, dest_ptr)?;
1380 Ok(None)
1381 }
1382
1383 FunctionIndex::GenericHash => {
1384 let (in_ptr, in_size, hash_algo_type, out_ptr, out_size) = Args::parse(args)?;
1390 self.charge_host_function_call(
1391 &host_function_costs.generic_hash,
1392 [in_ptr, in_size, hash_algo_type, out_ptr, out_size],
1393 )?;
1394 let hash_algo_type = match HashAlgorithm::try_from(hash_algo_type as u8) {
1395 Ok(v) => v,
1396 Err(_e) => {
1397 return Ok(Some(RuntimeValue::I32(api_error::i32_from(Err(
1398 ApiError::InvalidArgument,
1399 )))))
1400 }
1401 };
1402
1403 let digest =
1404 self.checked_memory_slice(in_ptr as usize, in_size as usize, |input| {
1405 match hash_algo_type {
1406 HashAlgorithm::Blake2b => cryptography::blake2b(input),
1407 HashAlgorithm::Blake3 => cryptography::blake3(input),
1408 HashAlgorithm::Sha256 => cryptography::sha256(input),
1409 }
1410 })?;
1411
1412 let result = if digest.len() > out_size as usize {
1413 Err(ApiError::BufferTooSmall)
1414 } else {
1415 Ok(())
1416 };
1417
1418 if result.is_err() {
1419 return Ok(Some(RuntimeValue::I32(api_error::i32_from(result))));
1420 }
1421
1422 if self.try_get_memory()?.set(out_ptr, &digest).is_err() {
1423 return Ok(Some(RuntimeValue::I32(
1424 u32::from(ApiError::HostBufferEmpty) as i32,
1425 )));
1426 }
1427
1428 Ok(Some(RuntimeValue::I32(0)))
1429 }
1430
1431 FunctionIndex::RecoverSecp256k1 => {
1432 let (
1440 data_ptr,
1441 data_size,
1442 signature_ptr,
1443 signature_size,
1444 public_key_ptr,
1445 recovery_id,
1446 ) = Args::parse(args)?;
1447
1448 self.charge_host_function_call(
1449 &host_function_costs.recover_secp256k1,
1450 [
1451 data_ptr,
1452 data_size,
1453 signature_ptr,
1454 signature_size,
1455 public_key_ptr,
1456 recovery_id,
1457 ],
1458 )?;
1459
1460 if recovery_id >= 4 {
1461 return Ok(Some(RuntimeValue::I32(
1462 u32::from(ApiError::InvalidArgument) as i32,
1463 )));
1464 }
1465
1466 let data = self.bytes_from_mem(data_ptr, data_size as usize)?;
1467 let signature: Signature = self.t_from_mem(signature_ptr, signature_size)?;
1468
1469 let Ok(public_key) =
1470 casper_types::crypto::recover_secp256k1(data, &signature, recovery_id as u8)
1471 else {
1472 return Ok(Some(RuntimeValue::I32(
1473 u32::from(ApiError::InvalidArgument) as i32,
1474 )));
1475 };
1476
1477 let Ok(key_bytes) = public_key.to_bytes() else {
1478 return Ok(Some(RuntimeValue::I32(
1479 u32::from(ApiError::OutOfMemory) as i32
1480 )));
1481 };
1482
1483 if self
1484 .try_get_memory()?
1485 .set(public_key_ptr, &key_bytes)
1486 .is_err()
1487 {
1488 return Ok(Some(RuntimeValue::I32(
1489 u32::from(ApiError::HostBufferEmpty) as i32,
1490 )));
1491 }
1492
1493 Ok(Some(RuntimeValue::I32(0)))
1494 }
1495
1496 FunctionIndex::VerifySignature => {
1497 let (
1504 message_ptr,
1505 message_size,
1506 signature_ptr,
1507 signature_size,
1508 public_key_ptr,
1509 public_key_size,
1510 ) = Args::parse(args)?;
1511
1512 self.charge_host_function_call(
1513 &host_function_costs.verify_signature,
1514 [
1515 message_ptr,
1516 message_size,
1517 signature_ptr,
1518 signature_size,
1519 public_key_ptr,
1520 public_key_size,
1521 ],
1522 )?;
1523
1524 let message = self.bytes_from_mem(message_ptr, message_size as usize)?;
1525 let signature: Signature = self.t_from_mem(signature_ptr, signature_size)?;
1526 let public_key: PublicKey = self.t_from_mem(public_key_ptr, public_key_size)?;
1527
1528 if casper_types::crypto::verify(message, &signature, &public_key).is_err() {
1529 return Ok(Some(RuntimeValue::I32(
1530 u32::from(ApiError::InvalidArgument) as i32,
1531 )));
1532 }
1533
1534 Ok(Some(RuntimeValue::I32(0)))
1535 }
1536 FunctionIndex::CallPackageVersion => {
1537 let (
1549 contract_package_hash_ptr,
1550 contract_package_hash_size,
1551 major_version_ptr,
1552 major_version_size,
1553 contract_version_ptr,
1554 contract_version_size,
1555 entry_point_name_ptr,
1556 entry_point_name_size,
1557 args_ptr,
1558 args_size,
1559 result_size_ptr,
1560 ) = Args::parse(args)?;
1561 self.charge_host_function_call(
1562 &host_function_costs.call_package_version,
1563 [
1564 contract_package_hash_ptr,
1565 contract_package_hash_size,
1566 major_version_ptr,
1567 major_version_size,
1568 contract_version_ptr,
1569 contract_version_size,
1570 entry_point_name_ptr,
1571 entry_point_name_size,
1572 args_ptr,
1573 args_size,
1574 result_size_ptr,
1575 ],
1576 )?;
1577
1578 let contract_package_hash: PackageHash =
1579 self.t_from_mem(contract_package_hash_ptr, contract_package_hash_size)?;
1580 let major_version: u32 = self.t_from_mem(major_version_ptr, major_version_size)?;
1581 let contract_version: EntityVersion =
1582 self.t_from_mem(contract_version_ptr, contract_version_size)?;
1583 let entry_point_name: String =
1584 self.t_from_mem(entry_point_name_ptr, entry_point_name_size)?;
1585 let args_bytes: Vec<u8> = {
1586 let args_size: u32 = args_size;
1587 self.bytes_from_mem(args_ptr, args_size as usize)?.to_vec()
1588 };
1589
1590 let ret = self.call_package_version_host_buffer(
1591 contract_package_hash,
1592 major_version,
1593 contract_version,
1594 entry_point_name,
1595 &args_bytes,
1596 result_size_ptr,
1597 )?;
1598 Ok(Some(RuntimeValue::I32(api_error::i32_from(ret))))
1599 }
1600 }
1601 }
1602}