1use std::{
2 collections::{BTreeMap, BTreeSet},
3 convert::TryFrom,
4};
5
6use casper_wasmi::{Externals, RuntimeArgs, RuntimeValue, Trap};
7
8use casper_storage::global_state::{error::Error as GlobalStateError, state::StateReader};
9use casper_types::{
10 account::AccountHash,
11 addressable_entity::EntryPoints,
12 api_error,
13 bytesrepr::{self, ToBytes},
14 contract_messages::MessageTopicOperation,
15 contracts::{ContractPackageHash, NamedKeys},
16 AddressableEntityHash, ApiError, EntityVersion, Gas, Group, HashAlgorithm, HostFunction,
17 HostFunctionCost, Key, PackageHash, PackageStatus, PublicKey, Signature, StoredValue, URef,
18 U512, UREF_SERIALIZED_LENGTH,
19};
20
21use super::{args::Args, ExecError, Runtime};
22use crate::{resolvers::v1_function_index::FunctionIndex, runtime::cryptography};
23
24impl<R> Externals for Runtime<'_, R>
25where
26 R: StateReader<Key, StoredValue, Error = GlobalStateError>,
27{
28 fn invoke_index(
29 &mut self,
30 index: usize,
31 args: RuntimeArgs,
32 ) -> Result<Option<RuntimeValue>, Trap> {
33 let func = FunctionIndex::try_from(index).expect("unknown function index");
34
35 let host_function_costs =
36 (*self.context.engine_config().wasm_config().v1()).take_host_function_costs();
37
38 match func {
39 FunctionIndex::ReadFuncIndex => {
40 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 self.t_from_mem(entry_points_ptr, entry_points_size)?;
648 let named_keys: NamedKeys = self.t_from_mem(named_keys_ptr, named_keys_size)?;
649 let ret = self.add_contract_version(
650 package_hash,
651 version_ptr,
652 entry_points,
653 named_keys,
654 BTreeMap::new(),
655 output_ptr,
656 )?;
657 Ok(Some(RuntimeValue::I32(api_error::i32_from(ret))))
658 }
659 FunctionIndex::AddContractVersionWithMessageTopics => {
660 let (
672 contract_package_hash_ptr,
673 contract_package_hash_size,
674 version_ptr,
675 entry_points_ptr,
676 entry_points_size,
677 named_keys_ptr,
678 named_keys_size,
679 message_topics_ptr,
680 message_topics_size,
681 output_ptr,
682 output_size,
683 ) = Args::parse(args)?;
684 self.charge_host_function_call(
685 &host_function_costs.add_contract_version_with_message_topics,
686 [
687 contract_package_hash_ptr,
688 contract_package_hash_size,
689 version_ptr,
690 entry_points_ptr,
691 entry_points_size,
692 named_keys_ptr,
693 named_keys_size,
694 message_topics_ptr,
695 message_topics_size,
696 output_ptr,
697 output_size,
698 ],
699 )?;
700
701 if output_size < 32 {
703 return Ok(Some(RuntimeValue::I32(api_error::i32_from(Err(
705 ApiError::BufferTooSmall,
706 )))));
707 }
708
709 let package_hash: PackageHash =
710 self.t_from_mem(contract_package_hash_ptr, contract_package_hash_size)?;
711 let entry_points: EntryPoints =
712 self.t_from_mem(entry_points_ptr, entry_points_size)?;
713 let named_keys: NamedKeys = self.t_from_mem(named_keys_ptr, named_keys_size)?;
714 let message_topics: BTreeMap<String, MessageTopicOperation> =
715 self.t_from_mem(message_topics_ptr, message_topics_size)?;
716
717 let message_limits = self.context.engine_config().wasm_config().messages_limits();
720 for (topic_name, _) in
721 message_topics
722 .iter()
723 .filter(|(_, operation)| match operation {
724 MessageTopicOperation::Add => true,
725 })
726 {
727 if topic_name.len() > message_limits.max_topic_name_size() as usize {
728 return Ok(Some(RuntimeValue::I32(api_error::i32_from(Err(
729 ApiError::MaxTopicNameSizeExceeded,
730 )))));
731 }
732 }
733
734 let ret = self.add_contract_version(
735 package_hash,
736 version_ptr,
737 entry_points,
738 named_keys,
739 message_topics,
740 output_ptr,
741 )?;
742 Ok(Some(RuntimeValue::I32(api_error::i32_from(ret))))
743 }
744
745 FunctionIndex::AddPackageVersionWithMessageTopics => {
746 let (
758 contract_package_hash_ptr,
759 contract_package_hash_size,
760 version_ptr,
761 entry_points_ptr,
762 entry_points_size,
763 named_keys_ptr,
764 named_keys_size,
765 message_topics,
766 message_topics_size,
767 output_ptr,
768 output_size,
769 ) = Args::parse(args)?;
770
771 self.charge_host_function_call(
772 &host_function_costs.add_package_version_with_message_topics,
773 [
774 contract_package_hash_ptr,
775 contract_package_hash_size,
776 version_ptr,
777 entry_points_ptr,
778 entry_points_size,
779 named_keys_ptr,
780 named_keys_size,
781 message_topics,
782 message_topics_size,
783 output_ptr,
784 output_size,
785 ],
786 )?;
787
788 if output_size < 32 {
790 return Ok(Some(RuntimeValue::I32(api_error::i32_from(Err(
792 ApiError::BufferTooSmall,
793 )))));
794 }
795
796 let package_hash: PackageHash =
797 self.t_from_mem(contract_package_hash_ptr, contract_package_hash_size)?;
798 let entry_points: EntryPoints =
799 self.t_from_mem(entry_points_ptr, entry_points_size)?;
800 let named_keys: NamedKeys = self.t_from_mem(named_keys_ptr, named_keys_size)?;
801 let message_topics: BTreeMap<String, MessageTopicOperation> =
802 self.t_from_mem(message_topics, message_topics_size)?;
803
804 let message_limits = self.context.engine_config().wasm_config().messages_limits();
807 for (topic_name, _) in
808 message_topics
809 .iter()
810 .filter(|(_, operation)| match operation {
811 MessageTopicOperation::Add => true,
812 })
813 {
814 if topic_name.len() > message_limits.max_topic_name_size() as usize {
815 return Ok(Some(RuntimeValue::I32(api_error::i32_from(Err(
816 ApiError::MaxTopicNameSizeExceeded,
817 )))));
818 }
819 }
820
821 let ret = self.add_contract_version(
822 package_hash,
823 version_ptr,
824 entry_points,
825 named_keys,
826 message_topics,
827 output_ptr,
828 )?;
829 Ok(Some(RuntimeValue::I32(api_error::i32_from(ret))))
830 }
831
832 FunctionIndex::DisableContractVersion => {
833 let (package_key_ptr, package_key_size, contract_hash_ptr, contract_hash_size) =
838 Args::parse(args)?;
839 self.charge_host_function_call(
840 &host_function_costs.disable_contract_version,
841 [
842 package_key_ptr,
843 package_key_size,
844 contract_hash_ptr,
845 contract_hash_size,
846 ],
847 )?;
848 let contract_package_hash = self.t_from_mem(package_key_ptr, package_key_size)?;
849 let contract_hash = self.t_from_mem(contract_hash_ptr, contract_hash_size)?;
850
851 let result = self.disable_contract_version(contract_package_hash, contract_hash)?;
852
853 Ok(Some(RuntimeValue::I32(api_error::i32_from(result))))
854 }
855
856 FunctionIndex::CallContractFuncIndex => {
857 let (
865 contract_hash_ptr,
866 contract_hash_size,
867 entry_point_name_ptr,
868 entry_point_name_size,
869 args_ptr,
870 args_size,
871 result_size_ptr,
872 ) = Args::parse(args)?;
873 self.charge_host_function_call(
874 &host_function_costs.call_contract,
875 [
876 contract_hash_ptr,
877 contract_hash_size,
878 entry_point_name_ptr,
879 entry_point_name_size,
880 args_ptr,
881 args_size,
882 result_size_ptr,
883 ],
884 )?;
885
886 let contract_hash: AddressableEntityHash =
887 self.t_from_mem(contract_hash_ptr, contract_hash_size)?;
888 let entry_point_name: String =
889 self.t_from_mem(entry_point_name_ptr, entry_point_name_size)?;
890 let args_bytes: Vec<u8> = {
891 let args_size: u32 = args_size;
892 self.bytes_from_mem(args_ptr, args_size as usize)?.to_vec()
893 };
894
895 let ret = self.call_contract_host_buffer(
896 contract_hash,
897 &entry_point_name,
898 &args_bytes,
899 result_size_ptr,
900 )?;
901 Ok(Some(RuntimeValue::I32(api_error::i32_from(ret))))
902 }
903
904 FunctionIndex::CallVersionedContract => {
905 let (
915 contract_package_hash_ptr,
916 contract_package_hash_size,
917 contract_version_ptr,
918 contract_package_size,
919 entry_point_name_ptr,
920 entry_point_name_size,
921 args_ptr,
922 args_size,
923 result_size_ptr,
924 ) = Args::parse(args)?;
925 self.charge_host_function_call(
926 &host_function_costs.call_versioned_contract,
927 [
928 contract_package_hash_ptr,
929 contract_package_hash_size,
930 contract_version_ptr,
931 contract_package_size,
932 entry_point_name_ptr,
933 entry_point_name_size,
934 args_ptr,
935 args_size,
936 result_size_ptr,
937 ],
938 )?;
939
940 let contract_package_hash: PackageHash =
941 self.t_from_mem(contract_package_hash_ptr, contract_package_hash_size)?;
942 let contract_version: Option<EntityVersion> =
943 self.t_from_mem(contract_version_ptr, contract_package_size)?;
944 let entry_point_name: String =
945 self.t_from_mem(entry_point_name_ptr, entry_point_name_size)?;
946 let args_bytes: Vec<u8> = {
947 let args_size: u32 = args_size;
948 self.bytes_from_mem(args_ptr, args_size as usize)?.to_vec()
949 };
950
951 let ret = self.call_versioned_contract_host_buffer(
952 contract_package_hash,
953 contract_version,
954 entry_point_name,
955 &args_bytes,
956 result_size_ptr,
957 )?;
958 Ok(Some(RuntimeValue::I32(api_error::i32_from(ret))))
959 }
960
961 #[cfg(feature = "test-support")]
962 FunctionIndex::PrintIndex => {
963 let (text_ptr, text_size) = Args::parse(args)?;
964 self.charge_host_function_call(&host_function_costs.print, [text_ptr, text_size])?;
965 self.print(text_ptr, text_size)?;
966 Ok(None)
967 }
968
969 FunctionIndex::GetRuntimeArgsizeIndex => {
970 let (name_ptr, name_size, size_ptr) = Args::parse(args)?;
974 self.charge_host_function_call(
975 &host_function_costs.get_named_arg_size,
976 [name_ptr, name_size, size_ptr],
977 )?;
978 let ret = self.get_named_arg_size(name_ptr, name_size as usize, size_ptr)?;
979 Ok(Some(RuntimeValue::I32(api_error::i32_from(ret))))
980 }
981
982 FunctionIndex::GetRuntimeArgIndex => {
983 let (name_ptr, name_size, dest_ptr, dest_size) = Args::parse(args)?;
988 self.charge_host_function_call(
989 &host_function_costs.get_named_arg,
990 [name_ptr, name_size, dest_ptr, dest_size],
991 )?;
992 let ret =
993 self.get_named_arg(name_ptr, name_size as usize, dest_ptr, dest_size as usize)?;
994 Ok(Some(RuntimeValue::I32(api_error::i32_from(ret))))
995 }
996
997 FunctionIndex::RemoveContractUserGroupIndex => {
998 let (package_key_ptr, package_key_size, label_ptr, label_size) = Args::parse(args)?;
1003 self.charge_host_function_call(
1004 &host_function_costs.remove_contract_user_group,
1005 [package_key_ptr, package_key_size, label_ptr, label_size],
1006 )?;
1007 let package_key = self.t_from_mem(package_key_ptr, package_key_size)?;
1008 let label: Group = self.t_from_mem(label_ptr, label_size)?;
1009
1010 let ret = self.remove_contract_user_group(package_key, label)?;
1011 Ok(Some(RuntimeValue::I32(api_error::i32_from(ret))))
1012 }
1013
1014 FunctionIndex::ExtendContractUserGroupURefsIndex => {
1015 let (package_ptr, package_size, label_ptr, label_size, value_size_ptr) =
1021 Args::parse(args)?;
1022
1023 self.charge_host_function_call(
1024 &host_function_costs.provision_contract_user_group_uref,
1025 [
1026 package_ptr,
1027 package_size,
1028 label_ptr,
1029 label_size,
1030 value_size_ptr,
1031 ],
1032 )?;
1033 let ret = self.provision_contract_user_group_uref(
1034 package_ptr,
1035 package_size,
1036 label_ptr,
1037 label_size,
1038 value_size_ptr,
1039 )?;
1040 Ok(Some(RuntimeValue::I32(api_error::i32_from(ret))))
1041 }
1042
1043 FunctionIndex::RemoveContractUserGroupURefsIndex => {
1044 let (package_ptr, package_size, label_ptr, label_size, urefs_ptr, urefs_size) =
1051 Args::parse(args)?;
1052 self.charge_host_function_call(
1053 &host_function_costs.remove_contract_user_group_urefs,
1054 [
1055 package_ptr,
1056 package_size,
1057 label_ptr,
1058 label_size,
1059 urefs_ptr,
1060 urefs_size,
1061 ],
1062 )?;
1063 let ret = self.remove_contract_user_group_urefs(
1064 package_ptr,
1065 package_size,
1066 label_ptr,
1067 label_size,
1068 urefs_ptr,
1069 urefs_size,
1070 )?;
1071 Ok(Some(RuntimeValue::I32(api_error::i32_from(ret))))
1072 }
1073
1074 FunctionIndex::Blake2b => {
1075 let (in_ptr, in_size, out_ptr, out_size) = Args::parse(args)?;
1076 self.charge_host_function_call(
1077 &host_function_costs.blake2b,
1078 [in_ptr, in_size, out_ptr, out_size],
1079 )?;
1080 let digest =
1081 self.checked_memory_slice(in_ptr as usize, in_size as usize, |input| {
1082 cryptography::blake2b(input)
1083 })?;
1084
1085 let result = if digest.len() != out_size as usize {
1086 Err(ApiError::BufferTooSmall)
1087 } else {
1088 Ok(())
1089 };
1090 if result.is_err() {
1091 return Ok(Some(RuntimeValue::I32(api_error::i32_from(result))));
1092 }
1093
1094 self.try_get_memory()?
1095 .set(out_ptr, &digest)
1096 .map_err(|error| ExecError::Interpreter(error.into()))?;
1097 Ok(Some(RuntimeValue::I32(0)))
1098 }
1099
1100 FunctionIndex::NewDictionaryFuncIndex => {
1101 let (output_size_ptr,): (u32,) = Args::parse(args)?;
1103 const UREF_LEN: u32 = 33u32;
1104 self.charge_host_function_call(&host_function_costs.new_uref, [0, 0, UREF_LEN])?;
1105 let ret = self.new_dictionary(output_size_ptr)?;
1106 Ok(Some(RuntimeValue::I32(api_error::i32_from(ret))))
1107 }
1108
1109 FunctionIndex::DictionaryGetFuncIndex => {
1110 let (uref_ptr, uref_size, key_bytes_ptr, key_bytes_size, output_size_ptr): (
1116 _,
1117 u32,
1118 _,
1119 u32,
1120 _,
1121 ) = Args::parse(args)?;
1122 self.charge_host_function_call(
1123 &host_function_costs.dictionary_get,
1124 [key_bytes_ptr, key_bytes_size, output_size_ptr],
1125 )?;
1126 let ret = self.dictionary_get(
1127 uref_ptr,
1128 uref_size,
1129 key_bytes_ptr,
1130 key_bytes_size,
1131 output_size_ptr,
1132 )?;
1133 Ok(Some(RuntimeValue::I32(api_error::i32_from(ret))))
1134 }
1135
1136 FunctionIndex::DictionaryPutFuncIndex => {
1137 let (uref_ptr, uref_size, key_bytes_ptr, key_bytes_size, value_ptr, value_ptr_size): (_, u32, _, u32, _, u32) = Args::parse(args)?;
1144 self.charge_host_function_call(
1145 &host_function_costs.dictionary_put,
1146 [key_bytes_ptr, key_bytes_size, value_ptr, value_ptr_size],
1147 )?;
1148 let ret = self.dictionary_put(
1149 uref_ptr,
1150 uref_size,
1151 key_bytes_ptr,
1152 key_bytes_size,
1153 value_ptr,
1154 value_ptr_size,
1155 )?;
1156 Ok(Some(RuntimeValue::I32(api_error::i32_from(ret))))
1157 }
1158
1159 FunctionIndex::DictionaryReadFuncIndex => {
1160 let (key_ptr, key_size, output_size_ptr) = Args::parse(args)?;
1164 self.charge_host_function_call(
1165 &host_function_costs.read_value,
1166 [key_ptr, key_size, output_size_ptr],
1167 )?;
1168 let ret = self.dictionary_read(key_ptr, key_size, output_size_ptr)?;
1169 Ok(Some(RuntimeValue::I32(api_error::i32_from(ret))))
1170 }
1171
1172 FunctionIndex::LoadCallStack => {
1173 let (call_stack_len_ptr, result_size_ptr) = Args::parse(args)?;
1176
1177 self.charge_host_function_call(
1178 &HostFunction::fixed(10_000),
1179 [call_stack_len_ptr, result_size_ptr],
1180 )?;
1181 let ret = self.load_call_stack(call_stack_len_ptr, result_size_ptr)?;
1182 Ok(Some(RuntimeValue::I32(api_error::i32_from(ret))))
1183 }
1184
1185 FunctionIndex::LoadCallerInformation => {
1186 let (action, call_stack_len_ptr, result_size_ptr) = Args::parse(args)?;
1190 self.charge_host_function_call(
1191 &HostFunction::fixed(10_000),
1192 [0, call_stack_len_ptr, result_size_ptr],
1193 )?;
1194 let ret =
1195 self.load_caller_information(action, call_stack_len_ptr, result_size_ptr)?;
1196 Ok(Some(RuntimeValue::I32(api_error::i32_from(ret))))
1197 }
1198
1199 FunctionIndex::LoadAuthorizationKeys => {
1200 let (len_ptr, result_size_ptr) = Args::parse(args)?;
1203 self.charge_host_function_call(
1204 &HostFunction::fixed(10_000),
1205 [len_ptr, result_size_ptr],
1206 )?;
1207 let ret = self.load_authorization_keys(len_ptr, result_size_ptr)?;
1208 Ok(Some(RuntimeValue::I32(api_error::i32_from(ret))))
1209 }
1210
1211 FunctionIndex::RandomBytes => {
1212 let (out_ptr, out_size) = Args::parse(args)?;
1213 self.charge_host_function_call(
1214 &host_function_costs.random_bytes,
1215 [out_ptr, out_size],
1216 )?;
1217
1218 let random_bytes = self.context.random_bytes()?;
1219
1220 let result = if random_bytes.len() != out_size as usize {
1221 Err(ApiError::BufferTooSmall)
1222 } else {
1223 Ok(())
1224 };
1225 if result.is_err() {
1226 return Ok(Some(RuntimeValue::I32(api_error::i32_from(result))));
1227 }
1228
1229 self.try_get_memory()?
1230 .set(out_ptr, &random_bytes)
1231 .map_err(|error| ExecError::Interpreter(error.into()))?;
1232
1233 Ok(Some(RuntimeValue::I32(0)))
1234 }
1235
1236 FunctionIndex::EnableContractVersion => {
1237 let (package_key_ptr, package_key_size, contract_hash_ptr, contract_hash_size) =
1242 Args::parse(args)?;
1243 self.charge_host_function_call(
1244 &host_function_costs.enable_contract_version,
1245 [
1246 package_key_ptr,
1247 package_key_size,
1248 contract_hash_ptr,
1249 contract_hash_size,
1250 ],
1251 )?;
1252 let contract_package_hash = self.t_from_mem(package_key_ptr, package_key_size)?;
1253 let contract_hash = self.t_from_mem(contract_hash_ptr, contract_hash_size)?;
1254
1255 let result = self.enable_contract_version(contract_package_hash, contract_hash)?;
1256
1257 Ok(Some(RuntimeValue::I32(api_error::i32_from(result))))
1258 }
1259
1260 FunctionIndex::ManageMessageTopic => {
1261 let (topic_name_ptr, topic_name_size, operation_ptr, operation_size) =
1266 Args::parse(args)?;
1267 self.charge_host_function_call(
1268 &host_function_costs.manage_message_topic,
1269 [
1270 topic_name_ptr,
1271 topic_name_size,
1272 operation_ptr,
1273 operation_size,
1274 ],
1275 )?;
1276
1277 let limits = self.context.engine_config().wasm_config().messages_limits();
1278
1279 if topic_name_size > limits.max_topic_name_size() {
1280 return Ok(Some(RuntimeValue::I32(api_error::i32_from(Err(
1281 ApiError::MaxTopicNameSizeExceeded,
1282 )))));
1283 }
1284
1285 let topic_name_bytes =
1286 self.bytes_from_mem(topic_name_ptr, topic_name_size as usize)?;
1287 let topic_name = std::str::from_utf8(&topic_name_bytes)
1288 .map_err(|e| Trap::from(ExecError::InvalidUtf8Encoding(e)))?;
1289
1290 if operation_size as usize > MessageTopicOperation::max_serialized_len() {
1291 return Err(Trap::from(ExecError::InvalidImputedOperation));
1292 }
1293 let topic_operation = self
1294 .t_from_mem(operation_ptr, operation_size)
1295 .map_err(|_e| Trap::from(ExecError::InvalidImputedOperation))?;
1296
1297 if !self.context.get_context_key().is_smart_contract_key() {
1299 return Err(Trap::from(ExecError::InvalidContext));
1300 }
1301
1302 let result = match topic_operation {
1303 MessageTopicOperation::Add => {
1304 self.add_message_topic(topic_name).map_err(Trap::from)?
1305 }
1306 };
1307
1308 Ok(Some(RuntimeValue::I32(api_error::i32_from(result))))
1309 }
1310
1311 FunctionIndex::EmitMessage => {
1312 let (topic_name_ptr, topic_name_size, message_ptr, message_size) =
1317 Args::parse(args)?;
1318
1319 self.context
1322 .charge_gas(Gas::new(self.context.emit_message_cost()))?;
1323 self.charge_host_function_call(
1325 &HostFunction::new(0, host_function_costs.emit_message.arguments()),
1326 &[topic_name_ptr, topic_name_size, message_ptr, message_size],
1327 )?;
1328
1329 let limits = self.context.engine_config().wasm_config().messages_limits();
1330
1331 if topic_name_size > limits.max_topic_name_size() {
1332 return Ok(Some(RuntimeValue::I32(api_error::i32_from(Err(
1333 ApiError::MaxTopicNameSizeExceeded,
1334 )))));
1335 }
1336
1337 if message_size > limits.max_message_size() {
1338 return Ok(Some(RuntimeValue::I32(api_error::i32_from(Err(
1339 ApiError::MessageTooLarge,
1340 )))));
1341 }
1342
1343 let topic_name_bytes =
1344 self.bytes_from_mem(topic_name_ptr, topic_name_size as usize)?;
1345 let topic_name = std::str::from_utf8(&topic_name_bytes)
1346 .map_err(|e| Trap::from(ExecError::InvalidUtf8Encoding(e)))?;
1347
1348 let message = self.t_from_mem(message_ptr, message_size)?;
1349
1350 let result = self.emit_message(topic_name, message)?;
1351 if result.is_ok() {
1352 let new_cost = self
1354 .context
1355 .emit_message_cost()
1356 .checked_add(host_function_costs.cost_increase_per_message.into())
1357 .ok_or(ExecError::GasLimit)?;
1358 self.context.set_emit_message_cost(new_cost);
1359 }
1360 Ok(Some(RuntimeValue::I32(api_error::i32_from(result))))
1361 }
1362
1363 FunctionIndex::GetBlockInfoIndex => {
1364 let (field_idx, dest_ptr): (u8, u32) = Args::parse(args)?;
1367
1368 self.charge_host_function_call(&host_function_costs.get_block_info, [0u32, 0u32])?;
1369 self.get_block_info(field_idx, dest_ptr)?;
1370 Ok(None)
1371 }
1372
1373 FunctionIndex::GenericHash => {
1374 let (in_ptr, in_size, hash_algo_type, out_ptr, out_size) = Args::parse(args)?;
1380 self.charge_host_function_call(
1381 &host_function_costs.generic_hash,
1382 [in_ptr, in_size, hash_algo_type, out_ptr, out_size],
1383 )?;
1384 let hash_algo_type = match HashAlgorithm::try_from(hash_algo_type as u8) {
1385 Ok(v) => v,
1386 Err(_e) => {
1387 return Ok(Some(RuntimeValue::I32(api_error::i32_from(Err(
1388 ApiError::InvalidArgument,
1389 )))))
1390 }
1391 };
1392
1393 let digest =
1394 self.checked_memory_slice(in_ptr as usize, in_size as usize, |input| {
1395 match hash_algo_type {
1396 HashAlgorithm::Blake2b => cryptography::blake2b(input),
1397 HashAlgorithm::Blake3 => cryptography::blake3(input),
1398 HashAlgorithm::Sha256 => cryptography::sha256(input),
1399 }
1400 })?;
1401
1402 let result = if digest.len() > out_size as usize {
1403 Err(ApiError::BufferTooSmall)
1404 } else {
1405 Ok(())
1406 };
1407
1408 if result.is_err() {
1409 return Ok(Some(RuntimeValue::I32(api_error::i32_from(result))));
1410 }
1411
1412 if self.try_get_memory()?.set(out_ptr, &digest).is_err() {
1413 return Ok(Some(RuntimeValue::I32(
1414 u32::from(ApiError::HostBufferEmpty) as i32,
1415 )));
1416 }
1417
1418 Ok(Some(RuntimeValue::I32(0)))
1419 }
1420
1421 FunctionIndex::RecoverSecp256k1 => {
1422 let (
1430 data_ptr,
1431 data_size,
1432 signature_ptr,
1433 signature_size,
1434 public_key_ptr,
1435 recovery_id,
1436 ) = Args::parse(args)?;
1437
1438 self.charge_host_function_call(
1439 &host_function_costs.recover_secp256k1,
1440 [
1441 data_ptr,
1442 data_size,
1443 signature_ptr,
1444 signature_size,
1445 public_key_ptr,
1446 recovery_id,
1447 ],
1448 )?;
1449
1450 if recovery_id >= 4 {
1451 return Ok(Some(RuntimeValue::I32(
1452 u32::from(ApiError::InvalidArgument) as i32,
1453 )));
1454 }
1455
1456 let data = self.bytes_from_mem(data_ptr, data_size as usize)?;
1457 let signature: Signature = self.t_from_mem(signature_ptr, signature_size)?;
1458
1459 let Ok(public_key) =
1460 casper_types::crypto::recover_secp256k1(data, &signature, recovery_id as u8)
1461 else {
1462 return Ok(Some(RuntimeValue::I32(
1463 u32::from(ApiError::InvalidArgument) as i32,
1464 )));
1465 };
1466
1467 let Ok(key_bytes) = public_key.to_bytes() else {
1468 return Ok(Some(RuntimeValue::I32(
1469 u32::from(ApiError::OutOfMemory) as i32
1470 )));
1471 };
1472
1473 if self
1474 .try_get_memory()?
1475 .set(public_key_ptr, &key_bytes)
1476 .is_err()
1477 {
1478 return Ok(Some(RuntimeValue::I32(
1479 u32::from(ApiError::HostBufferEmpty) as i32,
1480 )));
1481 }
1482
1483 Ok(Some(RuntimeValue::I32(0)))
1484 }
1485
1486 FunctionIndex::VerifySignature => {
1487 let (
1494 message_ptr,
1495 message_size,
1496 signature_ptr,
1497 signature_size,
1498 public_key_ptr,
1499 public_key_size,
1500 ) = Args::parse(args)?;
1501
1502 self.charge_host_function_call(
1503 &host_function_costs.verify_signature,
1504 [
1505 message_ptr,
1506 message_size,
1507 signature_ptr,
1508 signature_size,
1509 public_key_ptr,
1510 public_key_size,
1511 ],
1512 )?;
1513
1514 let message = self.bytes_from_mem(message_ptr, message_size as usize)?;
1515 let signature: Signature = self.t_from_mem(signature_ptr, signature_size)?;
1516 let public_key: PublicKey = self.t_from_mem(public_key_ptr, public_key_size)?;
1517
1518 if casper_types::crypto::verify(message, &signature, &public_key).is_err() {
1519 return Ok(Some(RuntimeValue::I32(
1520 u32::from(ApiError::InvalidArgument) as i32,
1521 )));
1522 }
1523
1524 Ok(Some(RuntimeValue::I32(0)))
1525 }
1526 }
1527 }
1528}