1extern crate radix_wasm_instrument as wasm_instrument;
2
3use crate::internal_prelude::*;
4use crate::vm::wasm::{constants::*, errors::*, PrepareError};
5use num_traits::CheckedAdd;
6use radix_engine_interface::blueprints::package::BlueprintDefinitionInit;
7use syn::Ident;
8use wasm_instrument::{
9 gas_metering::{self, Rules},
10 inject_stack_limiter,
11 utils::module_info::ModuleInfo,
12};
13use wasmparser::{ExternalKind, FuncType, Operator, Type, TypeRef, ValType, WasmFeatures};
14
15use super::WasmiModule;
16use crate::vm::ScryptoVmVersion;
17
18#[derive(Debug)]
19pub struct WasmModule {
20 module: ModuleInfo,
21}
22
23impl WasmModule {
24 pub fn init(code: &[u8]) -> Result<Self, PrepareError> {
25 let module = ModuleInfo::new(code).map_err(|_| PrepareError::DeserializationError)?;
27
28 let features = WasmFeatures {
30 mutable_global: true,
31 saturating_float_to_int: false,
32 sign_extension: true,
33 reference_types: false,
34 multi_value: false,
35 bulk_memory: false,
36 simd: false,
37 relaxed_simd: false,
38 threads: false,
39 tail_call: false,
40 floats: false,
41 multi_memory: false,
42 exceptions: false,
43 memory64: false,
44 extended_const: false,
45 component_model: false,
46 function_references: false,
47 memory_control: false,
48 gc: false,
49 };
50
51 module
52 .validate(features)
53 .map_err(|err| PrepareError::ValidationError(err.to_string()))?;
54
55 Ok(Self { module })
56 }
57
58 pub fn enforce_no_start_function(self) -> Result<Self, PrepareError> {
59 if self.module.start_function.is_some() {
60 Err(PrepareError::StartFunctionNotAllowed)
61 } else {
62 Ok(self)
63 }
64 }
65
66 pub fn enforce_import_constraints(
67 self,
68 version: ScryptoVmVersion,
69 ) -> Result<Self, PrepareError> {
70 for entry in self
72 .module
73 .import_section()
74 .map_err(|err| PrepareError::ModuleInfoError(err.to_string()))?
75 .unwrap_or(vec![])
76 {
77 if entry.module == MODULE_ENV_NAME {
78 match entry.name {
79 BUFFER_CONSUME_FUNCTION_NAME => {
80 if let TypeRef::Func(type_index) = entry.ty {
81 if Self::function_type_matches(
82 &self.module,
83 type_index,
84 vec![ValType::I32, ValType::I32],
85 vec![],
86 ) {
87 continue;
88 }
89
90 return Err(PrepareError::InvalidImport(
91 InvalidImport::InvalidFunctionType(entry.name.to_string()),
92 ));
93 }
94 }
95 OBJECT_CALL_FUNCTION_NAME => {
96 if let TypeRef::Func(type_index) = entry.ty {
97 if Self::function_type_matches(
98 &self.module,
99 type_index,
100 vec![
101 ValType::I32,
102 ValType::I32,
103 ValType::I32,
104 ValType::I32,
105 ValType::I32,
106 ValType::I32,
107 ],
108 vec![ValType::I64],
109 ) {
110 continue;
111 }
112
113 return Err(PrepareError::InvalidImport(
114 InvalidImport::InvalidFunctionType(entry.name.to_string()),
115 ));
116 }
117 }
118 OBJECT_CALL_MODULE_FUNCTION_NAME => {
119 if let TypeRef::Func(type_index) = entry.ty {
120 if Self::function_type_matches(
121 &self.module,
122 type_index,
123 vec![
124 ValType::I32,
125 ValType::I32,
126 ValType::I32,
127 ValType::I32,
128 ValType::I32,
129 ValType::I32,
130 ValType::I32,
131 ],
132 vec![ValType::I64],
133 ) {
134 continue;
135 }
136
137 return Err(PrepareError::InvalidImport(
138 InvalidImport::InvalidFunctionType(entry.name.to_string()),
139 ));
140 }
141 }
142 OBJECT_CALL_DIRECT_FUNCTION_NAME => {
143 if let TypeRef::Func(type_index) = entry.ty {
144 if Self::function_type_matches(
145 &self.module,
146 type_index,
147 vec![
148 ValType::I32,
149 ValType::I32,
150 ValType::I32,
151 ValType::I32,
152 ValType::I32,
153 ValType::I32,
154 ],
155 vec![ValType::I64],
156 ) {
157 continue;
158 }
159
160 return Err(PrepareError::InvalidImport(
161 InvalidImport::InvalidFunctionType(entry.name.to_string()),
162 ));
163 }
164 }
165 BLUEPRINT_CALL_FUNCTION_NAME => {
166 if let TypeRef::Func(type_index) = entry.ty {
167 if Self::function_type_matches(
168 &self.module,
169 type_index,
170 vec![
171 ValType::I32,
172 ValType::I32,
173 ValType::I32,
174 ValType::I32,
175 ValType::I32,
176 ValType::I32,
177 ValType::I32,
178 ValType::I32,
179 ],
180 vec![ValType::I64],
181 ) {
182 continue;
183 }
184
185 return Err(PrepareError::InvalidImport(
186 InvalidImport::InvalidFunctionType(entry.name.to_string()),
187 ));
188 }
189 }
190 KEY_VALUE_STORE_OPEN_ENTRY_FUNCTION_NAME => {
191 if let TypeRef::Func(type_index) = entry.ty {
192 if Self::function_type_matches(
193 &self.module,
194 type_index,
195 vec![
196 ValType::I32,
197 ValType::I32,
198 ValType::I32,
199 ValType::I32,
200 ValType::I32,
201 ],
202 vec![ValType::I32],
203 ) {
204 continue;
205 }
206
207 return Err(PrepareError::InvalidImport(
208 InvalidImport::InvalidFunctionType(entry.name.to_string()),
209 ));
210 }
211 }
212 KEY_VALUE_ENTRY_READ_FUNCTION_NAME => {
213 if let TypeRef::Func(type_index) = entry.ty {
214 if Self::function_type_matches(
215 &self.module,
216 type_index,
217 vec![ValType::I32],
218 vec![ValType::I64],
219 ) {
220 continue;
221 }
222
223 return Err(PrepareError::InvalidImport(
224 InvalidImport::InvalidFunctionType(entry.name.to_string()),
225 ));
226 }
227 }
228 KEY_VALUE_ENTRY_WRITE_FUNCTION_NAME => {
229 if let TypeRef::Func(type_index) = entry.ty {
230 if Self::function_type_matches(
231 &self.module,
232 type_index,
233 vec![ValType::I32, ValType::I32, ValType::I32],
234 vec![],
235 ) {
236 continue;
237 }
238
239 return Err(PrepareError::InvalidImport(
240 InvalidImport::InvalidFunctionType(entry.name.to_string()),
241 ));
242 }
243 }
244 KEY_VALUE_ENTRY_REMOVE_FUNCTION_NAME => {
245 if let TypeRef::Func(type_index) = entry.ty {
246 if Self::function_type_matches(
247 &self.module,
248 type_index,
249 vec![ValType::I32],
250 vec![ValType::I64],
251 ) {
252 continue;
253 }
254
255 return Err(PrepareError::InvalidImport(
256 InvalidImport::InvalidFunctionType(entry.name.to_string()),
257 ));
258 }
259 }
260 KEY_VALUE_ENTRY_CLOSE_FUNCTION_NAME => {
261 if let TypeRef::Func(type_index) = entry.ty {
262 if Self::function_type_matches(
263 &self.module,
264 type_index,
265 vec![ValType::I32],
266 vec![],
267 ) {
268 continue;
269 }
270
271 return Err(PrepareError::InvalidImport(
272 InvalidImport::InvalidFunctionType(entry.name.to_string()),
273 ));
274 }
275 }
276 KEY_VALUE_STORE_REMOVE_ENTRY_FUNCTION_NAME => {
277 if let TypeRef::Func(type_index) = entry.ty {
278 if Self::function_type_matches(
279 &self.module,
280 type_index,
281 vec![ValType::I32, ValType::I32, ValType::I32, ValType::I32],
282 vec![ValType::I64],
283 ) {
284 continue;
285 }
286
287 return Err(PrepareError::InvalidImport(
288 InvalidImport::InvalidFunctionType(entry.name.to_string()),
289 ));
290 }
291 }
292 ACTOR_OPEN_FIELD_FUNCTION_NAME => {
293 if let TypeRef::Func(type_index) = entry.ty {
294 if Self::function_type_matches(
295 &self.module,
296 type_index,
297 vec![ValType::I32, ValType::I32, ValType::I32],
298 vec![ValType::I32],
299 ) {
300 continue;
301 }
302
303 return Err(PrepareError::InvalidImport(
304 InvalidImport::InvalidFunctionType(entry.name.to_string()),
305 ));
306 }
307 }
308 FIELD_ENTRY_READ_FUNCTION_NAME => {
309 if let TypeRef::Func(type_index) = entry.ty {
310 if Self::function_type_matches(
311 &self.module,
312 type_index,
313 vec![ValType::I32],
314 vec![ValType::I64],
315 ) {
316 continue;
317 }
318
319 return Err(PrepareError::InvalidImport(
320 InvalidImport::InvalidFunctionType(entry.name.to_string()),
321 ));
322 }
323 }
324 FIELD_ENTRY_WRITE_FUNCTION_NAME => {
325 if let TypeRef::Func(type_index) = entry.ty {
326 if Self::function_type_matches(
327 &self.module,
328 type_index,
329 vec![ValType::I32, ValType::I32, ValType::I32],
330 vec![],
331 ) {
332 continue;
333 }
334
335 return Err(PrepareError::InvalidImport(
336 InvalidImport::InvalidFunctionType(entry.name.to_string()),
337 ));
338 }
339 }
340 FIELD_ENTRY_CLOSE_FUNCTION_NAME => {
341 if let TypeRef::Func(type_index) = entry.ty {
342 if Self::function_type_matches(
343 &self.module,
344 type_index,
345 vec![ValType::I32],
346 vec![],
347 ) {
348 continue;
349 }
350
351 return Err(PrepareError::InvalidImport(
352 InvalidImport::InvalidFunctionType(entry.name.to_string()),
353 ));
354 }
355 }
356 ACTOR_GET_OBJECT_ID_FUNCTION_NAME => {
357 if let TypeRef::Func(type_index) = entry.ty {
358 if Self::function_type_matches(
359 &self.module,
360 type_index,
361 vec![ValType::I32],
362 vec![ValType::I64],
363 ) {
364 continue;
365 }
366
367 return Err(PrepareError::InvalidImport(
368 InvalidImport::InvalidFunctionType(entry.name.to_string()),
369 ));
370 }
371 }
372 ACTOR_GET_PACKAGE_ADDRESS_FUNCTION_NAME => {
373 if let TypeRef::Func(type_index) = entry.ty {
374 if Self::function_type_matches(
375 &self.module,
376 type_index,
377 vec![],
378 vec![ValType::I64],
379 ) {
380 continue;
381 }
382
383 return Err(PrepareError::InvalidImport(
384 InvalidImport::InvalidFunctionType(entry.name.to_string()),
385 ));
386 }
387 }
388 ACTOR_GET_BLUEPRINT_NAME_FUNCTION_NAME => {
389 if let TypeRef::Func(type_index) = entry.ty {
390 if Self::function_type_matches(
391 &self.module,
392 type_index,
393 vec![],
394 vec![ValType::I64],
395 ) {
396 continue;
397 }
398
399 return Err(PrepareError::InvalidImport(
400 InvalidImport::InvalidFunctionType(entry.name.to_string()),
401 ));
402 }
403 }
404
405 OBJECT_NEW_FUNCTION_NAME => {
406 if let TypeRef::Func(type_index) = entry.ty {
407 if Self::function_type_matches(
408 &self.module,
409 type_index,
410 vec![ValType::I32, ValType::I32, ValType::I32, ValType::I32],
411 vec![ValType::I64],
412 ) {
413 continue;
414 }
415
416 return Err(PrepareError::InvalidImport(
417 InvalidImport::InvalidFunctionType(entry.name.to_string()),
418 ));
419 }
420 }
421
422 COSTING_GET_EXECUTION_COST_UNIT_LIMIT_FUNCTION_NAME => {
423 if let TypeRef::Func(type_index) = entry.ty {
424 if Self::function_type_matches(
425 &self.module,
426 type_index,
427 vec![],
428 vec![ValType::I32],
429 ) {
430 continue;
431 }
432 return Err(PrepareError::InvalidImport(
433 InvalidImport::InvalidFunctionType(entry.name.to_string()),
434 ));
435 }
436 }
437 COSTING_GET_EXECUTION_COST_UNIT_PRICE_FUNCTION_NAME => {
438 if let TypeRef::Func(type_index) = entry.ty {
439 if Self::function_type_matches(
440 &self.module,
441 type_index,
442 vec![],
443 vec![ValType::I64],
444 ) {
445 continue;
446 }
447 return Err(PrepareError::InvalidImport(
448 InvalidImport::InvalidFunctionType(entry.name.to_string()),
449 ));
450 }
451 }
452 COSTING_GET_FINALIZATION_COST_UNIT_LIMIT_FUNCTION_NAME => {
453 if let TypeRef::Func(type_index) = entry.ty {
454 if Self::function_type_matches(
455 &self.module,
456 type_index,
457 vec![],
458 vec![ValType::I32],
459 ) {
460 continue;
461 }
462 return Err(PrepareError::InvalidImport(
463 InvalidImport::InvalidFunctionType(entry.name.to_string()),
464 ));
465 }
466 }
467 COSTING_GET_FINALIZATION_COST_UNIT_PRICE_FUNCTION_NAME => {
468 if let TypeRef::Func(type_index) = entry.ty {
469 if Self::function_type_matches(
470 &self.module,
471 type_index,
472 vec![],
473 vec![ValType::I64],
474 ) {
475 continue;
476 }
477 return Err(PrepareError::InvalidImport(
478 InvalidImport::InvalidFunctionType(entry.name.to_string()),
479 ));
480 }
481 }
482 COSTING_GET_USD_PRICE_FUNCTION_NAME => {
483 if let TypeRef::Func(type_index) = entry.ty {
484 if Self::function_type_matches(
485 &self.module,
486 type_index,
487 vec![],
488 vec![ValType::I64],
489 ) {
490 continue;
491 }
492 return Err(PrepareError::InvalidImport(
493 InvalidImport::InvalidFunctionType(entry.name.to_string()),
494 ));
495 }
496 }
497 COSTING_GET_TIP_PERCENTAGE_FUNCTION_NAME => {
498 if let TypeRef::Func(type_index) = entry.ty {
499 if Self::function_type_matches(
500 &self.module,
501 type_index,
502 vec![],
503 vec![ValType::I32],
504 ) {
505 continue;
506 }
507 return Err(PrepareError::InvalidImport(
508 InvalidImport::InvalidFunctionType(entry.name.to_string()),
509 ));
510 }
511 }
512 COSTING_GET_FEE_BALANCE_FUNCTION_NAME => {
513 if let TypeRef::Func(type_index) = entry.ty {
514 if Self::function_type_matches(
515 &self.module,
516 type_index,
517 vec![],
518 vec![ValType::I64],
519 ) {
520 continue;
521 }
522 return Err(PrepareError::InvalidImport(
523 InvalidImport::InvalidFunctionType(entry.name.to_string()),
524 ));
525 }
526 }
527
528 ADDRESS_ALLOCATE_FUNCTION_NAME => {
529 if let TypeRef::Func(type_index) = entry.ty {
530 if Self::function_type_matches(
531 &self.module,
532 type_index,
533 vec![ValType::I32, ValType::I32, ValType::I32, ValType::I32],
534 vec![ValType::I64],
535 ) {
536 continue;
537 }
538 return Err(PrepareError::InvalidImport(
539 InvalidImport::InvalidFunctionType(entry.name.to_string()),
540 ));
541 }
542 }
543 ADDRESS_GET_RESERVATION_ADDRESS_FUNCTION_NAME => {
544 if let TypeRef::Func(type_index) = entry.ty {
545 if Self::function_type_matches(
546 &self.module,
547 type_index,
548 vec![ValType::I32, ValType::I32],
549 vec![ValType::I64],
550 ) {
551 continue;
552 }
553 return Err(PrepareError::InvalidImport(
554 InvalidImport::InvalidFunctionType(entry.name.to_string()),
555 ));
556 }
557 }
558 OBJECT_GLOBALIZE_FUNCTION_NAME => {
559 if let TypeRef::Func(type_index) = entry.ty {
560 if Self::function_type_matches(
561 &self.module,
562 type_index,
563 vec![
564 ValType::I32,
565 ValType::I32,
566 ValType::I32,
567 ValType::I32,
568 ValType::I32,
569 ValType::I32,
570 ],
571 vec![ValType::I64],
572 ) {
573 continue;
574 }
575 return Err(PrepareError::InvalidImport(
576 InvalidImport::InvalidFunctionType(entry.name.to_string()),
577 ));
578 }
579 }
580 KEY_VALUE_STORE_NEW_FUNCTION_NAME => {
581 if let TypeRef::Func(type_index) = entry.ty {
582 if Self::function_type_matches(
583 &self.module,
584 type_index,
585 vec![ValType::I32, ValType::I32],
586 vec![ValType::I64],
587 ) {
588 continue;
589 }
590 return Err(PrepareError::InvalidImport(
591 InvalidImport::InvalidFunctionType(entry.name.to_string()),
592 ));
593 }
594 }
595 OBJECT_INSTANCE_OF_FUNCTION_NAME => {
596 if let TypeRef::Func(type_index) = entry.ty {
597 if Self::function_type_matches(
598 &self.module,
599 type_index,
600 vec![
601 ValType::I32,
602 ValType::I32,
603 ValType::I32,
604 ValType::I32,
605 ValType::I32,
606 ValType::I32,
607 ],
608 vec![ValType::I32],
609 ) {
610 continue;
611 }
612 return Err(PrepareError::InvalidImport(
613 InvalidImport::InvalidFunctionType(entry.name.to_string()),
614 ));
615 }
616 }
617 OBJECT_GET_BLUEPRINT_ID_FUNCTION_NAME => {
618 if let TypeRef::Func(type_index) = entry.ty {
619 if Self::function_type_matches(
620 &self.module,
621 type_index,
622 vec![ValType::I32, ValType::I32],
623 vec![ValType::I64],
624 ) {
625 continue;
626 }
627 return Err(PrepareError::InvalidImport(
628 InvalidImport::InvalidFunctionType(entry.name.to_string()),
629 ));
630 }
631 }
632 OBJECT_GET_OUTER_OBJECT_FUNCTION_NAME => {
633 if let TypeRef::Func(type_index) = entry.ty {
634 if Self::function_type_matches(
635 &self.module,
636 type_index,
637 vec![ValType::I32, ValType::I32],
638 vec![ValType::I64],
639 ) {
640 continue;
641 }
642 return Err(PrepareError::InvalidImport(
643 InvalidImport::InvalidFunctionType(entry.name.to_string()),
644 ));
645 }
646 }
647 ACTOR_EMIT_EVENT_FUNCTION_NAME => {
648 if let TypeRef::Func(type_index) = entry.ty {
649 if Self::function_type_matches(
650 &self.module,
651 type_index,
652 vec![
653 ValType::I32,
654 ValType::I32,
655 ValType::I32,
656 ValType::I32,
657 ValType::I32,
658 ],
659 vec![],
660 ) {
661 continue;
662 }
663 return Err(PrepareError::InvalidImport(
664 InvalidImport::InvalidFunctionType(entry.name.to_string()),
665 ));
666 }
667 }
668 SYS_LOG_FUNCTION_NAME => {
669 if let TypeRef::Func(type_index) = entry.ty {
670 if Self::function_type_matches(
671 &self.module,
672 type_index,
673 vec![ValType::I32, ValType::I32, ValType::I32, ValType::I32],
674 vec![],
675 ) {
676 continue;
677 }
678 return Err(PrepareError::InvalidImport(
679 InvalidImport::InvalidFunctionType(entry.name.to_string()),
680 ));
681 }
682 }
683 SYS_BECH32_ENCODE_ADDRESS_FUNCTION_NAME => {
684 if let TypeRef::Func(type_index) = entry.ty {
685 if Self::function_type_matches(
686 &self.module,
687 type_index,
688 vec![ValType::I32, ValType::I32],
689 vec![ValType::I64],
690 ) {
691 continue;
692 }
693 return Err(PrepareError::InvalidImport(
694 InvalidImport::InvalidFunctionType(entry.name.to_string()),
695 ));
696 }
697 }
698 SYS_PANIC_FUNCTION_NAME => {
699 if let TypeRef::Func(type_index) = entry.ty {
700 if Self::function_type_matches(
701 &self.module,
702 type_index,
703 vec![ValType::I32, ValType::I32],
704 vec![],
705 ) {
706 continue;
707 }
708 return Err(PrepareError::InvalidImport(
709 InvalidImport::InvalidFunctionType(entry.name.to_string()),
710 ));
711 }
712 }
713 SYS_GET_TRANSACTION_HASH_FUNCTION_NAME => {
714 if let TypeRef::Func(type_index) = entry.ty {
715 if Self::function_type_matches(
716 &self.module,
717 type_index,
718 vec![],
719 vec![ValType::I64],
720 ) {
721 continue;
722 }
723 return Err(PrepareError::InvalidImport(
724 InvalidImport::InvalidFunctionType(entry.name.to_string()),
725 ));
726 }
727 }
728 SYS_GENERATE_RUID_FUNCTION_NAME => {
729 if let TypeRef::Func(type_index) = entry.ty {
730 if Self::function_type_matches(
731 &self.module,
732 type_index,
733 vec![],
734 vec![ValType::I64],
735 ) {
736 continue;
737 }
738 return Err(PrepareError::InvalidImport(
739 InvalidImport::InvalidFunctionType(entry.name.to_string()),
740 ));
741 }
742 }
743 CRYPTO_UTILS_BLS12381_V1_VERIFY_FUNCTION_NAME => {
745 if version < ScryptoVmVersion::crypto_utils_v1() {
746 return Err(PrepareError::InvalidImport(
747 InvalidImport::ProtocolVersionMismatch {
748 name: entry.name.to_string(),
749 current_version: version.into(),
750 expected_version: ScryptoVmVersion::crypto_utils_v1().into(),
751 },
752 ));
753 }
754
755 if let TypeRef::Func(type_index) = entry.ty {
756 if Self::function_type_matches(
757 &self.module,
758 type_index,
759 vec![
760 ValType::I32,
761 ValType::I32,
762 ValType::I32,
763 ValType::I32,
764 ValType::I32,
765 ValType::I32,
766 ],
767 vec![ValType::I32],
768 ) {
769 continue;
770 }
771 return Err(PrepareError::InvalidImport(
772 InvalidImport::InvalidFunctionType(entry.name.to_string()),
773 ));
774 }
775 }
776 CRYPTO_UTILS_BLS12381_V1_AGGREGATE_VERIFY_FUNCTION_NAME => {
777 if version < ScryptoVmVersion::crypto_utils_v1() {
778 return Err(PrepareError::InvalidImport(
779 InvalidImport::ProtocolVersionMismatch {
780 name: entry.name.to_string(),
781 current_version: version.into(),
782 expected_version: ScryptoVmVersion::crypto_utils_v1().into(),
783 },
784 ));
785 }
786
787 if let TypeRef::Func(type_index) = entry.ty {
788 if Self::function_type_matches(
789 &self.module,
790 type_index,
791 vec![ValType::I32, ValType::I32, ValType::I32, ValType::I32],
792 vec![ValType::I32],
793 ) {
794 continue;
795 }
796 return Err(PrepareError::InvalidImport(
797 InvalidImport::InvalidFunctionType(entry.name.to_string()),
798 ));
799 }
800 }
801 CRYPTO_UTILS_BLS12381_V1_FAST_AGGREGATE_VERIFY_FUNCTION_NAME => {
802 if version < ScryptoVmVersion::crypto_utils_v1() {
803 return Err(PrepareError::InvalidImport(
804 InvalidImport::ProtocolVersionMismatch {
805 name: entry.name.to_string(),
806 current_version: version.into(),
807 expected_version: ScryptoVmVersion::crypto_utils_v1().into(),
808 },
809 ));
810 }
811
812 if let TypeRef::Func(type_index) = entry.ty {
813 if Self::function_type_matches(
814 &self.module,
815 type_index,
816 vec![
817 ValType::I32,
818 ValType::I32,
819 ValType::I32,
820 ValType::I32,
821 ValType::I32,
822 ValType::I32,
823 ],
824 vec![ValType::I32],
825 ) {
826 continue;
827 }
828 return Err(PrepareError::InvalidImport(
829 InvalidImport::InvalidFunctionType(entry.name.to_string()),
830 ));
831 }
832 }
833 CRYPTO_UTILS_BLS12381_G2_SIGNATURE_AGGREGATE_FUNCTION_NAME => {
834 if version < ScryptoVmVersion::crypto_utils_v1() {
835 return Err(PrepareError::InvalidImport(
836 InvalidImport::ProtocolVersionMismatch {
837 name: entry.name.to_string(),
838 current_version: version.into(),
839 expected_version: ScryptoVmVersion::crypto_utils_v1().into(),
840 },
841 ));
842 }
843
844 if let TypeRef::Func(type_index) = entry.ty {
845 if Self::function_type_matches(
846 &self.module,
847 type_index,
848 vec![ValType::I32, ValType::I32],
849 vec![ValType::I64],
850 ) {
851 continue;
852 }
853 return Err(PrepareError::InvalidImport(
854 InvalidImport::InvalidFunctionType(entry.name.to_string()),
855 ));
856 }
857 }
858 CRYPTO_UTILS_KECCAK256_HASH_FUNCTION_NAME => {
859 if version < ScryptoVmVersion::crypto_utils_v1() {
860 return Err(PrepareError::InvalidImport(
861 InvalidImport::ProtocolVersionMismatch {
862 name: entry.name.to_string(),
863 current_version: version.into(),
864 expected_version: ScryptoVmVersion::crypto_utils_v1().into(),
865 },
866 ));
867 }
868
869 if let TypeRef::Func(type_index) = entry.ty {
870 if Self::function_type_matches(
871 &self.module,
872 type_index,
873 vec![ValType::I32, ValType::I32],
874 vec![ValType::I64],
875 ) {
876 continue;
877 }
878 return Err(PrepareError::InvalidImport(
879 InvalidImport::InvalidFunctionType(entry.name.to_string()),
880 ));
881 }
882 }
883 CRYPTO_UTILS_BLAKE2B_256_HASH_FUNCTION_NAME => {
886 if version < ScryptoVmVersion::crypto_utils_v2() {
887 return Err(PrepareError::InvalidImport(
888 InvalidImport::ProtocolVersionMismatch {
889 name: entry.name.to_string(),
890 current_version: version.into(),
891 expected_version: ScryptoVmVersion::crypto_utils_v2().into(),
892 },
893 ));
894 }
895
896 if let TypeRef::Func(type_index) = entry.ty {
897 if Self::function_type_matches(
898 &self.module,
899 type_index,
900 vec![ValType::I32, ValType::I32],
901 vec![ValType::I64],
902 ) {
903 continue;
904 }
905 return Err(PrepareError::InvalidImport(
906 InvalidImport::InvalidFunctionType(entry.name.to_string()),
907 ));
908 }
909 }
910 CRYPTO_UTILS_ED25519_VERIFY_FUNCTION_NAME
911 | CRYPTO_UTILS_SECP256K1_ECDSA_VERIFY_FUNCTION_NAME => {
912 if version < ScryptoVmVersion::crypto_utils_v2() {
913 return Err(PrepareError::InvalidImport(
914 InvalidImport::ProtocolVersionMismatch {
915 name: entry.name.to_string(),
916 current_version: version.into(),
917 expected_version: ScryptoVmVersion::crypto_utils_v2().into(),
918 },
919 ));
920 }
921
922 if let TypeRef::Func(type_index) = entry.ty {
923 if Self::function_type_matches(
924 &self.module,
925 type_index,
926 vec![
927 ValType::I32,
928 ValType::I32,
929 ValType::I32,
930 ValType::I32,
931 ValType::I32,
932 ValType::I32,
933 ],
934 vec![ValType::I32],
935 ) {
936 continue;
937 }
938 return Err(PrepareError::InvalidImport(
939 InvalidImport::InvalidFunctionType(entry.name.to_string()),
940 ));
941 }
942 }
943 CRYPTO_UTILS_SECP256K1_ECDSA_VERIFY_AND_KEY_RECOVER_FUNCTION_NAME => {
944 if version < ScryptoVmVersion::crypto_utils_v2() {
945 return Err(PrepareError::InvalidImport(
946 InvalidImport::ProtocolVersionMismatch {
947 name: entry.name.to_string(),
948 current_version: version.into(),
949 expected_version: ScryptoVmVersion::crypto_utils_v2().into(),
950 },
951 ));
952 }
953
954 if let TypeRef::Func(type_index) = entry.ty {
955 if Self::function_type_matches(
956 &self.module,
957 type_index,
958 vec![ValType::I32, ValType::I32, ValType::I32, ValType::I32],
959 vec![ValType::I64],
960 ) {
961 continue;
962 }
963 return Err(PrepareError::InvalidImport(
964 InvalidImport::InvalidFunctionType(entry.name.to_string()),
965 ));
966 }
967 }
968 CRYPTO_UTILS_SECP256K1_ECDSA_VERIFY_AND_KEY_RECOVER_UNCOMPRESSED_FUNCTION_NAME =>
969 {
970 if version < ScryptoVmVersion::crypto_utils_v2() {
971 return Err(PrepareError::InvalidImport(
972 InvalidImport::ProtocolVersionMismatch {
973 name: entry.name.to_string(),
974 current_version: version.into(),
975 expected_version: ScryptoVmVersion::crypto_utils_v2().into(),
976 },
977 ));
978 }
979
980 if let TypeRef::Func(type_index) = entry.ty {
981 if Self::function_type_matches(
982 &self.module,
983 type_index,
984 vec![ValType::I32, ValType::I32, ValType::I32, ValType::I32],
985 vec![ValType::I64],
986 ) {
987 continue;
988 }
989 return Err(PrepareError::InvalidImport(
990 InvalidImport::InvalidFunctionType(entry.name.to_string()),
991 ));
992 }
993 }
994 _ => {}
996 };
997 }
998
999 return Err(PrepareError::InvalidImport(
1000 InvalidImport::ImportNotAllowed(entry.name.to_string()),
1001 ));
1002 }
1003
1004 Ok(self)
1005 }
1006
1007 pub fn enforce_memory_limit_and_inject_max(
1008 mut self,
1009 max_memory_size_in_pages: u32,
1010 ) -> Result<Self, PrepareError> {
1011 let memory_section = self
1013 .module
1014 .memory_section()
1015 .map_err(|err| PrepareError::ModuleInfoError(err.to_string()))?
1016 .ok_or(PrepareError::InvalidMemory(
1017 InvalidMemory::MissingMemorySection,
1018 ))?;
1019
1020 let mut memory = match memory_section.len() {
1022 0 => Err(PrepareError::InvalidMemory(
1023 InvalidMemory::NoMemoryDefinition,
1024 )),
1025 1 => Ok(memory_section[0]),
1026 _ => Err(PrepareError::InvalidMemory(
1027 InvalidMemory::TooManyMemoryDefinition,
1028 )),
1029 }?;
1030
1031 if memory.initial > max_memory_size_in_pages.into() {
1033 return Err(PrepareError::InvalidMemory(
1034 InvalidMemory::MemorySizeLimitExceeded,
1035 ));
1036 }
1037 if let Some(max) = memory.maximum {
1038 if max > max_memory_size_in_pages.into() {
1039 return Err(PrepareError::InvalidMemory(
1040 InvalidMemory::MemorySizeLimitExceeded,
1041 ));
1042 }
1043 } else {
1044 memory.maximum = Some(max_memory_size_in_pages.into());
1045 self.module
1046 .modify_memory_type(0, memory)
1047 .map_err(|err| PrepareError::ModuleInfoError(err.to_string()))?;
1048 }
1049
1050 if !self
1052 .module
1053 .export_section()
1054 .map_err(|err| PrepareError::ModuleInfoError(err.to_string()))?
1055 .unwrap_or(vec![])
1056 .iter()
1057 .any(|e| e.kind == ExternalKind::Memory && e.name == EXPORT_MEMORY)
1058 {
1059 return Err(PrepareError::InvalidMemory(
1060 InvalidMemory::MemoryNotExported,
1061 ));
1062 }
1063
1064 Ok(self)
1065 }
1066
1067 pub fn enforce_table_limit(self, max_initial_table_size: u32) -> Result<Self, PrepareError> {
1068 let section = self
1069 .module
1070 .table_section()
1071 .map_err(|err| PrepareError::ModuleInfoError(err.to_string()))?;
1072
1073 if let Some(section) = section {
1074 if section.len() > 1 {
1075 return Err(PrepareError::InvalidTable(InvalidTable::MoreThanOneTable));
1077 }
1078
1079 if let Some(table) = section.get(0) {
1080 if table.ty.initial > max_initial_table_size {
1081 return Err(PrepareError::InvalidTable(
1082 InvalidTable::InitialTableSizeLimitExceeded,
1083 ));
1084 }
1085 }
1086 }
1087
1088 Ok(self)
1089 }
1090
1091 pub fn enforce_br_table_limit(
1092 self,
1093 max_number_of_br_table_targets: u32,
1094 ) -> Result<Self, PrepareError> {
1095 for fb in self
1096 .module
1097 .code_section()
1098 .map_err(|err| PrepareError::ModuleInfoError(err.to_string()))?
1099 .unwrap_or(vec![])
1100 {
1101 let reader = fb
1102 .get_operators_reader()
1103 .map_err(|err| PrepareError::WasmParserError(err.to_string()))?;
1104
1105 for op in reader {
1106 let inst = op.map_err(|err| PrepareError::WasmParserError(err.to_string()))?;
1107
1108 if let Operator::BrTable {
1109 targets: table_data,
1110 } = inst
1111 {
1112 if table_data.len() > max_number_of_br_table_targets {
1113 return Err(PrepareError::TooManyTargetsInBrTable);
1114 }
1115 }
1116 }
1117 }
1118 Ok(self)
1119 }
1120
1121 pub fn enforce_function_limit(
1122 self,
1123 max_number_of_functions: u32,
1124 max_number_of_function_params: u32,
1125 max_number_of_function_locals: u32,
1126 ) -> Result<Self, PrepareError> {
1127 if self.module.num_local_functions() > max_number_of_functions {
1128 return Err(PrepareError::TooManyFunctions);
1129 }
1130
1131 for func_idx in 0..self.module.num_local_functions() {
1132 if let wasmparser::Type::Func(ty) = self
1133 .module
1134 .get_type_by_func_idx(func_idx)
1135 .map_err(|err| PrepareError::ModuleInfoError(err.to_string()))?
1136 {
1137 if ty.params().len() > max_number_of_function_params as usize {
1138 return Err(PrepareError::TooManyFunctionParams);
1139 }
1140 }
1141 }
1142
1143 for func_body in self
1144 .module
1145 .code_section()
1146 .map_err(|err| PrepareError::ModuleInfoError(err.to_string()))?
1147 .unwrap_or(vec![])
1148 {
1149 let local_reader = func_body
1150 .get_locals_reader()
1151 .map_err(|err| PrepareError::WasmParserError(err.to_string()))?;
1152 let mut locals_count = 0;
1153
1154 for local in local_reader.into_iter() {
1162 let (count, _ty) =
1164 local.map_err(|err| PrepareError::WasmParserError(err.to_string()))?;
1165 locals_count = locals_count
1166 .checked_add(&count)
1167 .ok_or(PrepareError::Overflow)?;
1168 }
1169
1170 if locals_count > max_number_of_function_locals {
1171 return Err(PrepareError::TooManyFunctionLocals {
1172 max: max_number_of_function_locals,
1173 actual: locals_count,
1174 });
1175 }
1176 }
1177
1178 Ok(self)
1179 }
1180
1181 pub fn enforce_export_names(self) -> Result<Self, PrepareError> {
1182 for name in &self.module.export_names {
1184 syn::parse_str::<Ident>(name)
1185 .map_err(|_| PrepareError::InvalidExportName(name.to_string()))?;
1186 }
1187
1188 Ok(self)
1189 }
1190
1191 pub fn enforce_global_limit(self, max_number_of_globals: u32) -> Result<Self, PrepareError> {
1192 if self.module.num_local_globals() > max_number_of_globals {
1193 return Err(PrepareError::TooManyGlobals {
1194 max: max_number_of_globals,
1195 current: self.module.num_local_globals(),
1196 });
1197 }
1198
1199 Ok(self)
1200 }
1201
1202 pub fn enforce_export_constraints<'a, I: Iterator<Item = &'a BlueprintDefinitionInit>>(
1203 self,
1204 blueprints: I,
1205 ) -> Result<Self, PrepareError> {
1206 let exports = self
1207 .module
1208 .export_section()
1209 .map_err(|err| PrepareError::ModuleInfoError(err.to_string()))?;
1210
1211 if let Some(exports) = exports {
1212 for blueprint_def_init in blueprints {
1213 for export_name in blueprint_def_init.schema.exports() {
1214 if !exports.iter().any(|x| {
1215 x.name.eq(&export_name) && {
1216 if let ExternalKind::Func = x.kind {
1217 Self::function_matches(
1218 &self.module,
1219 x.index as usize,
1220 vec![ValType::I64],
1221 vec![ValType::I64],
1222 )
1223 } else {
1224 false
1225 }
1226 }
1227 }) {
1228 return Err(PrepareError::MissingExport {
1229 export_name: export_name.to_string(),
1230 });
1231 }
1232 }
1233 }
1234
1235 Ok(self)
1236 } else {
1237 Err(PrepareError::NoExportSection)
1238 }
1239 }
1240
1241 pub fn inject_instruction_metering<R: Rules>(
1242 mut self,
1243 rules: &R,
1244 ) -> Result<Self, PrepareError> {
1245 #[cfg(not(feature = "coverage"))]
1246 {
1247 let backend = gas_metering::host_function::Injector::new(
1248 MODULE_ENV_NAME,
1249 COSTING_CONSUME_WASM_EXECUTION_UNITS_FUNCTION_NAME,
1250 );
1251 gas_metering::inject(&mut self.module, backend, rules).map_err(|err| {
1252 PrepareError::RejectedByInstructionMetering {
1253 reason: err.to_string(),
1254 }
1255 })?;
1256 }
1257
1258 Ok(self)
1259 }
1260
1261 pub fn inject_stack_metering(mut self, wasm_max_stack_size: u32) -> Result<Self, PrepareError> {
1262 inject_stack_limiter(&mut self.module, wasm_max_stack_size).map_err(|err| {
1263 PrepareError::RejectedByStackMetering {
1264 reason: err.to_string(),
1265 }
1266 })?;
1267 Ok(self)
1268 }
1269
1270 pub fn ensure_instantiatable(self) -> Result<Self, PrepareError> {
1271 let code = self.module.bytes();
1288 WasmiModule::new(&code[..])
1289 .map_err(|_| PrepareError::NotCompilable)?
1290 .instantiate()
1291 .map_err(|e| PrepareError::NotInstantiatable {
1292 reason: format!("{:?}", e),
1293 })?;
1294
1295 Ok(self)
1296 }
1297
1298 pub fn ensure_compilable(self) -> Result<Self, PrepareError> {
1299 Ok(self)
1308 }
1309
1310 pub fn to_bytes(self) -> Result<(Vec<u8>, Vec<String>), PrepareError> {
1311 let mut function_exports = vec![];
1312
1313 for export in self
1314 .module
1315 .export_section()
1316 .map_err(|err| PrepareError::ModuleInfoError(err.to_string()))?
1317 .unwrap_or(vec![])
1318 {
1319 if let wasmparser::ExternalKind::Func = export.kind {
1320 function_exports.push(export.name.to_string());
1321 }
1322 }
1323 let code = self.module.bytes();
1324
1325 Ok((code, function_exports))
1326 }
1327
1328 fn function_matches(
1329 module: &ModuleInfo,
1330 func_index: usize,
1331 params: Vec<ValType>,
1332 results: Vec<ValType>,
1333 ) -> bool {
1334 match module.function_map.get(func_index) {
1335 Some(type_index) => Self::function_type_matches(module, *type_index, params, results),
1336 None => false,
1337 }
1338 }
1339
1340 fn function_type_matches(
1341 module: &ModuleInfo,
1342 type_index: u32,
1343 params: Vec<ValType>,
1344 results: Vec<ValType>,
1345 ) -> bool {
1346 let ty = module.get_type_by_idx(type_index);
1347 match ty {
1348 Ok(ty) => match ty {
1349 Type::Func(ty) => ty == &FuncType::new(params, results),
1350 _ => false,
1351 },
1352 Err(_) => false,
1353 }
1354 }
1355
1356 #[cfg(feature = "radix_engine_tests")]
1357 pub fn contains_sign_ext_ops(self) -> bool {
1358 for func_body in self
1359 .module
1360 .code_section()
1361 .map_err(|err| PrepareError::ModuleInfoError(err.to_string()))
1362 .unwrap()
1363 .expect("no code section")
1364 {
1365 let reader = func_body
1366 .get_operators_reader()
1367 .map_err(|err| PrepareError::WasmParserError(err.to_string()))
1368 .unwrap();
1369 for op in reader {
1370 let inst = op
1371 .map_err(|err| PrepareError::WasmParserError(err.to_string()))
1372 .unwrap();
1373
1374 match inst {
1375 Operator::I32Extend8S
1376 | Operator::I32Extend16S
1377 | Operator::I64Extend8S
1378 | Operator::I64Extend16S
1379 | Operator::I64Extend32S => return true,
1380 _ => (),
1381 }
1382 }
1383 }
1384
1385 false
1386 }
1387}
1388
1389#[cfg(test)]
1390mod tests {
1391 use super::*;
1393 use radix_blueprint_schema_init::{
1394 BlueprintFunctionsSchemaInit, BlueprintHooksInit, BlueprintSchemaInit,
1395 BlueprintStateSchemaInit, BlueprintTypeSchemaInit, FieldSchema, FunctionSchemaInit,
1396 };
1397 use radix_engine_interface::blueprints::package::BlueprintType;
1398 use sbor::basic_well_known_types::{ANY_TYPE, UNIT_TYPE};
1399 use wabt::{wat2wasm_with_features, Features};
1400
1401 macro_rules! wat2wasm {
1402 ($wat: expr) => {{
1403 let mut features = Features::new();
1404 features.enable_sign_extension();
1405 features.enable_mutable_globals();
1406 let code = wat2wasm_with_features($wat, features).unwrap();
1407 code
1408 }};
1409 }
1410
1411 macro_rules! assert_invalid_wasm {
1412 ($wat: expr, $err: expr) => {
1413 let code = wat2wasm!($wat);
1414 assert_eq!($err, WasmModule::init(&code).unwrap_err());
1415 };
1416
1417 ($wat: expr, $err: expr, $func: expr) => {
1418 let code = wat2wasm!($wat);
1419 assert_eq!($err, WasmModule::init(&code).and_then($func).unwrap_err());
1420 };
1421 }
1422
1423 #[test]
1424 fn test_floating_point() {
1425 assert_invalid_wasm!(
1427 r#"
1428 (module
1429 (func (result f64)
1430 f64.const 123
1431 )
1432 )
1433 "#,
1434 PrepareError::ValidationError(
1435 "WasmParserError(BinaryReaderError { floating-point support is disabled (at offset 0xb) })".to_string()
1436 )
1437 );
1438 assert_invalid_wasm!(
1440 r#"
1441 (module
1442 (func (param f64)
1443 )
1444 )
1445 "#,
1446 PrepareError::ValidationError(
1447 "WasmParserError(BinaryReaderError { floating-point support is disabled (at offset 0xb) })".to_string()
1448 )
1449 );
1450 assert_invalid_wasm!(
1452 r#"
1453 (module
1454 (func
1455 f64.const 1
1456 f64.const 2
1457 f64.add
1458 drop
1459 )
1460 )
1461 "#,
1462 PrepareError::ValidationError(
1463 "WasmParserError(BinaryReaderError { floating-point instruction disallowed (at offset 0x17) })".to_string()
1464 )
1465 );
1466 assert_invalid_wasm!(
1468 r#"
1469 (module
1470 (global $fp f32 (f32.const 10))
1471 )
1472 "#,
1473 PrepareError::ValidationError(
1474 "WasmParserError(BinaryReaderError { floating-point support is disabled (at offset 0xb) })".to_string()
1475 )
1476 );
1477 }
1478
1479 #[test]
1480 fn test_start_function() {
1481 assert_invalid_wasm!(
1482 r#"
1483 (module
1484 (func $main)
1485 (start $main)
1486 )
1487 "#,
1488 PrepareError::StartFunctionNotAllowed,
1489 WasmModule::enforce_no_start_function
1490 );
1491 }
1492
1493 #[test]
1494 fn test_enforce_import_limit() {
1495 let wat = r#"
1496 (module
1497 (import "env" "name_to_replace" (func $some_func (param i32 i32 i32 i32 i32 i32 i32 i32)))
1498 )
1499 "#;
1500 assert_invalid_wasm!(
1501 wat,
1502 PrepareError::InvalidImport(InvalidImport::ImportNotAllowed(
1503 "name_to_replace".to_string()
1504 )),
1505 |s| WasmModule::enforce_import_constraints(s, ScryptoVmVersion::V1_0)
1506 );
1507
1508 for name in [
1509 BUFFER_CONSUME_FUNCTION_NAME,
1510 OBJECT_CALL_FUNCTION_NAME,
1511 OBJECT_CALL_MODULE_FUNCTION_NAME,
1512 OBJECT_CALL_DIRECT_FUNCTION_NAME,
1513 BLUEPRINT_CALL_FUNCTION_NAME,
1514 KEY_VALUE_STORE_OPEN_ENTRY_FUNCTION_NAME,
1515 KEY_VALUE_ENTRY_READ_FUNCTION_NAME,
1516 KEY_VALUE_ENTRY_WRITE_FUNCTION_NAME,
1517 KEY_VALUE_ENTRY_REMOVE_FUNCTION_NAME,
1518 KEY_VALUE_ENTRY_CLOSE_FUNCTION_NAME,
1519 KEY_VALUE_STORE_REMOVE_ENTRY_FUNCTION_NAME,
1520 ACTOR_OPEN_FIELD_FUNCTION_NAME,
1521 FIELD_ENTRY_READ_FUNCTION_NAME,
1522 FIELD_ENTRY_WRITE_FUNCTION_NAME,
1523 FIELD_ENTRY_CLOSE_FUNCTION_NAME,
1524 ACTOR_GET_OBJECT_ID_FUNCTION_NAME,
1525 ACTOR_GET_PACKAGE_ADDRESS_FUNCTION_NAME,
1526 ACTOR_GET_BLUEPRINT_NAME_FUNCTION_NAME,
1527 OBJECT_NEW_FUNCTION_NAME,
1528 COSTING_GET_EXECUTION_COST_UNIT_LIMIT_FUNCTION_NAME,
1529 COSTING_GET_EXECUTION_COST_UNIT_PRICE_FUNCTION_NAME,
1530 COSTING_GET_FINALIZATION_COST_UNIT_LIMIT_FUNCTION_NAME,
1531 COSTING_GET_FINALIZATION_COST_UNIT_PRICE_FUNCTION_NAME,
1532 COSTING_GET_USD_PRICE_FUNCTION_NAME,
1533 COSTING_GET_TIP_PERCENTAGE_FUNCTION_NAME,
1534 COSTING_GET_FEE_BALANCE_FUNCTION_NAME,
1535 ADDRESS_ALLOCATE_FUNCTION_NAME,
1536 ADDRESS_GET_RESERVATION_ADDRESS_FUNCTION_NAME,
1537 OBJECT_GLOBALIZE_FUNCTION_NAME,
1538 KEY_VALUE_STORE_NEW_FUNCTION_NAME,
1539 OBJECT_INSTANCE_OF_FUNCTION_NAME,
1540 OBJECT_GET_BLUEPRINT_ID_FUNCTION_NAME,
1541 OBJECT_GET_OUTER_OBJECT_FUNCTION_NAME,
1542 ACTOR_EMIT_EVENT_FUNCTION_NAME,
1543 SYS_LOG_FUNCTION_NAME,
1544 SYS_BECH32_ENCODE_ADDRESS_FUNCTION_NAME,
1545 SYS_PANIC_FUNCTION_NAME,
1546 SYS_GET_TRANSACTION_HASH_FUNCTION_NAME,
1547 SYS_GENERATE_RUID_FUNCTION_NAME,
1548 ] {
1549 assert_invalid_wasm!(
1550 wat.replace("name_to_replace", name),
1551 PrepareError::InvalidImport(InvalidImport::InvalidFunctionType(name.to_string())),
1552 |w| WasmModule::enforce_import_constraints(w, ScryptoVmVersion::V1_0)
1553 );
1554 }
1555 }
1556
1557 #[test]
1558 fn test_invalid_import_protocol_mismatch() {
1559 let wat = r#"
1560 (module
1561 (import "env" "name_to_replace" (func $some_func (param i32) (result i32)))
1562 )
1563 "#;
1564
1565 for (current_version, expected_version, names) in [
1566 (
1567 ScryptoVmVersion::V1_0,
1568 ScryptoVmVersion::crypto_utils_v1(),
1569 vec![
1570 CRYPTO_UTILS_BLS12381_V1_VERIFY_FUNCTION_NAME,
1571 CRYPTO_UTILS_BLS12381_V1_AGGREGATE_VERIFY_FUNCTION_NAME,
1572 CRYPTO_UTILS_BLS12381_V1_FAST_AGGREGATE_VERIFY_FUNCTION_NAME,
1573 CRYPTO_UTILS_BLS12381_G2_SIGNATURE_AGGREGATE_FUNCTION_NAME,
1574 CRYPTO_UTILS_KECCAK256_HASH_FUNCTION_NAME,
1575 ],
1576 ),
1577 (
1578 ScryptoVmVersion::V1_1,
1579 ScryptoVmVersion::crypto_utils_v2(),
1580 vec![
1581 CRYPTO_UTILS_BLAKE2B_256_HASH_FUNCTION_NAME,
1582 CRYPTO_UTILS_ED25519_VERIFY_FUNCTION_NAME,
1583 CRYPTO_UTILS_SECP256K1_ECDSA_VERIFY_FUNCTION_NAME,
1584 CRYPTO_UTILS_SECP256K1_ECDSA_VERIFY_AND_KEY_RECOVER_FUNCTION_NAME,
1585 CRYPTO_UTILS_SECP256K1_ECDSA_VERIFY_AND_KEY_RECOVER_UNCOMPRESSED_FUNCTION_NAME,
1586 ],
1587 ),
1588 ] {
1589 for name in names {
1590 assert_invalid_wasm!(
1591 wat.replace("name_to_replace", name),
1592 PrepareError::InvalidImport(InvalidImport::ProtocolVersionMismatch {
1593 name: name.to_string(),
1594 current_version: current_version.into(),
1595 expected_version: expected_version.into(),
1596 }),
1597 |w| WasmModule::enforce_import_constraints(w, current_version)
1598 );
1599 }
1600 }
1601 }
1602
1603 #[test]
1604 fn test_enforce_global_limit() {
1605 assert_invalid_wasm!(
1606 r#"
1607 (module
1608 (global $g1 i32 (i32.const 0))
1609 (global $g2 i32 (i32.const 0))
1610 (global $g3 i32 (i32.const 0))
1611 (global $g4 i32 (i32.const 0))
1612 )
1613 "#,
1614 PrepareError::TooManyGlobals { max: 3, current: 4 },
1615 |x| WasmModule::enforce_global_limit(x, 3)
1616 );
1617 }
1618
1619 #[test]
1620 fn test_memory() {
1621 assert_invalid_wasm!(
1622 r#"
1623 (module
1624 )
1625 "#,
1626 PrepareError::InvalidMemory(InvalidMemory::MissingMemorySection),
1627 |x| WasmModule::enforce_memory_limit_and_inject_max(x, 5)
1628 );
1629 assert_invalid_wasm!(
1641 r#"
1642 (module
1643 (memory 6)
1644 )
1645 "#,
1646 PrepareError::InvalidMemory(InvalidMemory::MemorySizeLimitExceeded),
1647 |x| WasmModule::enforce_memory_limit_and_inject_max(x, 5)
1648 );
1649 assert_invalid_wasm!(
1650 r#"
1651 (module
1652 (memory 2)
1653 )
1654 "#,
1655 PrepareError::InvalidMemory(InvalidMemory::MemoryNotExported),
1656 |x| WasmModule::enforce_memory_limit_and_inject_max(x, 5)
1657 );
1658 }
1659
1660 #[test]
1661 fn test_table() {
1662 assert_invalid_wasm!(
1663 r#"
1664 (module
1665 (table 6 funcref)
1666 )
1667 "#,
1668 PrepareError::InvalidTable(InvalidTable::InitialTableSizeLimitExceeded),
1669 |x| WasmModule::enforce_table_limit(x, 5)
1670 );
1671 }
1672
1673 #[test]
1674 fn test_br_table() {
1675 assert_invalid_wasm!(
1676 r#"
1677 (module
1678 (func (param i32) (result i32)
1679 (block
1680 (block
1681 (br_table 1 0 1 0 1 0 1 (local.get 0))
1682 (return (i32.const 21))
1683 )
1684 (return (i32.const 20))
1685 )
1686 (i32.const 22)
1687 )
1688 )
1689 "#,
1690 PrepareError::TooManyTargetsInBrTable,
1691 |x| WasmModule::enforce_br_table_limit(x, 5)
1692 );
1693 }
1694
1695 #[test]
1696 fn test_function_limits() {
1697 assert_invalid_wasm!(
1698 r#"
1699 (module
1700 (func (result i32)
1701 (i32.const 11)
1702 )
1703 (func (result i32)
1704 (i32.const 22)
1705 )
1706 (func (result i32)
1707 (i32.const 33)
1708 )
1709 )
1710 "#,
1711 PrepareError::TooManyFunctions,
1712 |x| WasmModule::enforce_function_limit(x, 2, 3, 3)
1713 );
1714
1715 assert_invalid_wasm!(
1716 r#"
1717 (module
1718 (func (param i32 i32 i32 i32) (result i32)
1719 (i32.const 22)
1720 )
1721 )
1722 "#,
1723 PrepareError::TooManyFunctionParams,
1724 |x| WasmModule::enforce_function_limit(x, 2, 3, 3)
1725 );
1726
1727 assert_invalid_wasm!(
1728 r#"
1729 (module
1730 (func (result i32)
1731 (local $v1 i32)
1732
1733 (local.set $v1 (i32.const 1))
1734
1735 (i32.const 22)
1736 )
1737 (func (result i32)
1738 (local $v1 i32)
1739 (local $v2 i64)
1740 (local $v3 i64)
1741 (local $v4 i32)
1742
1743 (local.set $v1 (i32.const 1))
1744 (local.set $v2 (i64.const 2))
1745 (local.set $v3 (i64.const 3))
1746 (local.set $v4 (i32.const 4))
1747
1748 (i32.const 22)
1749 )
1750 )
1751 "#,
1752 PrepareError::TooManyFunctionLocals { max: 3, actual: 4 },
1753 |x| WasmModule::enforce_function_limit(x, 2, 3, 3)
1754 );
1755 }
1756
1757 #[test]
1758 fn test_blueprint_constraints() {
1759 let mut blueprints = index_map_new();
1760 blueprints.insert(
1761 "Test".to_string(),
1762 BlueprintDefinitionInit {
1763 blueprint_type: BlueprintType::default(),
1764 is_transient: false,
1765 feature_set: indexset!(),
1766 dependencies: indexset!(),
1767
1768 schema: BlueprintSchemaInit {
1769 generics: vec![],
1770 schema: SchemaV1 {
1771 type_kinds: vec![],
1772 type_metadata: vec![],
1773 type_validations: vec![],
1774 }.into_versioned(),
1775 state: BlueprintStateSchemaInit {
1776 fields: vec![FieldSchema::static_field(LocalTypeId::WellKnown(UNIT_TYPE))],
1777 collections: vec![],
1778 },
1779 events: Default::default(),
1780 types: BlueprintTypeSchemaInit::default(),
1781 functions: BlueprintFunctionsSchemaInit {
1782 functions: indexmap!(
1783 "f".to_string() => FunctionSchemaInit {
1784 receiver: Option::None,
1785 input: radix_blueprint_schema_init::TypeRef::Static(LocalTypeId::WellKnown(ANY_TYPE)),
1786 output: radix_blueprint_schema_init::TypeRef::Static(LocalTypeId::WellKnown(UNIT_TYPE)),
1787 export: "Test_f".to_string(),
1788 }
1789 ),
1790 },
1791 hooks: BlueprintHooksInit::default(),
1792 },
1793
1794 royalty_config: Default::default(),
1795 auth_config: Default::default(),
1796 },
1797 );
1798
1799 assert_invalid_wasm!(
1800 r#"
1801 (module
1802 )
1803 "#,
1804 PrepareError::NoExportSection,
1805 |x| WasmModule::enforce_export_constraints(x, blueprints.values())
1806 );
1807 assert_invalid_wasm!(
1809 r#"
1810 (module
1811 (func (export "foo") (result i32)
1812 (i32.const 0)
1813 )
1814 )
1815 "#,
1816 PrepareError::MissingExport {
1817 export_name: "Test_f".to_string()
1818 },
1819 |x| WasmModule::enforce_export_constraints(x, blueprints.values())
1820 );
1821 assert_invalid_wasm!(
1823 r#"
1824 (module
1825 (func (export "Test_f") (result i32)
1826 (i32.const 0)
1827 )
1828 )
1829 "#,
1830 PrepareError::MissingExport {
1831 export_name: "Test_f".to_string()
1832 },
1833 |x| WasmModule::enforce_export_constraints(x, blueprints.values())
1834 );
1835
1836 assert_invalid_wasm!(
1838 r#"
1839 (module
1840 (global (export "Test_f") i32 (i32.const 0))
1841 )
1842 "#,
1843 PrepareError::MissingExport {
1844 export_name: "Test_f".to_string()
1845 },
1846 |x| WasmModule::enforce_export_constraints(x, blueprints.values())
1847 );
1848 }
1849
1850 #[cfg(feature = "radix_engine_tests")]
1851 #[test]
1852 fn test_contains_sign_ext_ops() {
1853 let code = wat2wasm!(
1854 r#"
1855 (module
1856 (func $f
1857 (i64.const 1)
1858 (i64.extend8_s) ;; sign extension op
1859 drop
1860 )
1861 )
1862 "#
1863 );
1864
1865 assert!(WasmModule::init(&code).unwrap().contains_sign_ext_ops());
1866
1867 let code = wat2wasm!(
1868 r#"
1869 (module
1870 (func $f
1871 (i64.const 1)
1872 drop
1873 )
1874 )
1875 "#
1876 );
1877
1878 assert!(!WasmModule::init(&code).unwrap().contains_sign_ext_ops());
1879 }
1880}