radix_engine/vm/wasm/
prepare.rs

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        // deserialize
26        let module = ModuleInfo::new(code).map_err(|_| PrepareError::DeserializationError)?;
27
28        // Radix Engine supports MVP + proposals: mutable globals and sign-extension-ops
29        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        // Only allow `env::radix_engine` import
71        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 v1 begin
744                    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 v1 end
884                    // Crypto Utils v2 begin
885                    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                    // Crypto Utils v2 end
995                    _ => {}
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        // Check if memory section exists
1012        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        // Check if there is only one memory definition
1021        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        // Check the memory limits
1032        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        // Check if the memory is exported
1051        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                // Sanity check MVP rule
1076                return Err(PrepareError::InvalidTable(InvalidTable::MoreThanOneTable));
1077            }
1078
1079            if let Some(table) = section.first() {
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            // According to the documentation local_reader.get_count() would do the job here
1155            // see: https://docs.rs/wasmparser/latest/wasmparser/struct.LocalsReader.html#method.get_count
1156            // But the description is misleading, get_count() returns the number of different types of
1157            // locals (or number of LocalReader iterator items).
1158            // To get the number of locals we need to iterate over LocalReader, which
1159            // returns following tuple for each item:
1160            //  ( u32, ValType) - where u32 is the number of locals of ValType
1161            for local in local_reader.into_iter() {
1162                // Number of locals of some type
1163                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        // Any exported name should follow Rust Identifier specification
1183        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        // During instantiation time, the following procedures are applied:
1272
1273        // 1. Resolve imports with external values
1274        // This should always succeed as we only allow `env::radix_engine` function import
1275
1276        // 2. Allocate externals, functions, tables, memory and globals
1277        // This should always succeed as we enforce an upper bound for each type
1278
1279        // 3. Update table with elements
1280        // It may fail if the offset is out of bound
1281
1282        // 4. Update memory with data segments
1283        // It may fail if the offset is out of bound
1284
1285        // Because the offset can be an `InitExpr` that requires evaluation against an WASM instance,
1286        // we're using the `wasmi` logic as a shortcut.
1287        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        // TODO: Understand WASM JIT compilability
1300        //
1301        // Can we make the assumption that all "prepared" modules are compilable,
1302        // if machine resource is "sufficient"?
1303        //
1304        // Another option is to attempt to compile, although it may make RE protocol
1305        // coupled with a specific implementation.
1306
1307        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    // Note this useful idiom: importing names from outer (for mod tests) scope.
1392    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
1400    macro_rules! wat2wasm {
1401        ($wat: expr) => {{
1402            ::wat::parse_str($wat).unwrap()
1403        }};
1404    }
1405
1406    macro_rules! assert_invalid_wasm {
1407        ($wat: expr, $err: expr) => {
1408            let code = wat2wasm!($wat);
1409            assert_eq!($err, WasmModule::init(&code).unwrap_err());
1410        };
1411
1412        ($wat: expr, $err: expr, $func: expr) => {
1413            let code = wat2wasm!($wat);
1414            assert_eq!($err, WasmModule::init(&code).and_then($func).unwrap_err());
1415        };
1416    }
1417
1418    #[test]
1419    fn test_floating_point() {
1420        // return
1421        assert_invalid_wasm!(
1422            r#"
1423            (module
1424                (func (result f64)
1425                    f64.const 123
1426                )
1427            )
1428            "#,
1429            PrepareError::ValidationError(
1430                "WasmParserError(BinaryReaderError { floating-point support is disabled (at offset 0xb) })".to_string()
1431            )
1432        );
1433        // input
1434        assert_invalid_wasm!(
1435            r#"
1436            (module
1437                (func (param f64)
1438                )
1439            )
1440            "#,
1441            PrepareError::ValidationError(
1442                "WasmParserError(BinaryReaderError { floating-point support is disabled (at offset 0xb) })".to_string()
1443            )
1444        );
1445        // instruction
1446        assert_invalid_wasm!(
1447            r#"
1448            (module
1449                (func
1450                    f64.const 1
1451                    f64.const 2
1452                    f64.add
1453                    drop
1454                )
1455            )
1456            "#,
1457            PrepareError::ValidationError(
1458                "WasmParserError(BinaryReaderError { floating-point instruction disallowed (at offset 0x17) })".to_string()
1459            )
1460        );
1461        // global
1462        assert_invalid_wasm!(
1463            r#"
1464            (module
1465                (global $fp f32 (f32.const 10))
1466            )
1467            "#,
1468            PrepareError::ValidationError(
1469                "WasmParserError(BinaryReaderError { floating-point support is disabled (at offset 0xb) })".to_string()
1470            )
1471        );
1472    }
1473
1474    #[test]
1475    fn test_start_function() {
1476        assert_invalid_wasm!(
1477            r#"
1478            (module
1479                (func $main)
1480                (start $main)
1481            )
1482            "#,
1483            PrepareError::StartFunctionNotAllowed,
1484            WasmModule::enforce_no_start_function
1485        );
1486    }
1487
1488    #[test]
1489    fn test_enforce_import_limit() {
1490        let wat = r#"
1491            (module
1492                (import "env" "name_to_replace" (func $some_func (param i32 i32 i32 i32 i32 i32 i32 i32)))
1493            )
1494            "#;
1495        assert_invalid_wasm!(
1496            wat,
1497            PrepareError::InvalidImport(InvalidImport::ImportNotAllowed(
1498                "name_to_replace".to_string()
1499            )),
1500            |s| WasmModule::enforce_import_constraints(s, ScryptoVmVersion::V1_0)
1501        );
1502
1503        for name in [
1504            BUFFER_CONSUME_FUNCTION_NAME,
1505            OBJECT_CALL_FUNCTION_NAME,
1506            OBJECT_CALL_MODULE_FUNCTION_NAME,
1507            OBJECT_CALL_DIRECT_FUNCTION_NAME,
1508            BLUEPRINT_CALL_FUNCTION_NAME,
1509            KEY_VALUE_STORE_OPEN_ENTRY_FUNCTION_NAME,
1510            KEY_VALUE_ENTRY_READ_FUNCTION_NAME,
1511            KEY_VALUE_ENTRY_WRITE_FUNCTION_NAME,
1512            KEY_VALUE_ENTRY_REMOVE_FUNCTION_NAME,
1513            KEY_VALUE_ENTRY_CLOSE_FUNCTION_NAME,
1514            KEY_VALUE_STORE_REMOVE_ENTRY_FUNCTION_NAME,
1515            ACTOR_OPEN_FIELD_FUNCTION_NAME,
1516            FIELD_ENTRY_READ_FUNCTION_NAME,
1517            FIELD_ENTRY_WRITE_FUNCTION_NAME,
1518            FIELD_ENTRY_CLOSE_FUNCTION_NAME,
1519            ACTOR_GET_OBJECT_ID_FUNCTION_NAME,
1520            ACTOR_GET_PACKAGE_ADDRESS_FUNCTION_NAME,
1521            ACTOR_GET_BLUEPRINT_NAME_FUNCTION_NAME,
1522            OBJECT_NEW_FUNCTION_NAME,
1523            COSTING_GET_EXECUTION_COST_UNIT_LIMIT_FUNCTION_NAME,
1524            COSTING_GET_EXECUTION_COST_UNIT_PRICE_FUNCTION_NAME,
1525            COSTING_GET_FINALIZATION_COST_UNIT_LIMIT_FUNCTION_NAME,
1526            COSTING_GET_FINALIZATION_COST_UNIT_PRICE_FUNCTION_NAME,
1527            COSTING_GET_USD_PRICE_FUNCTION_NAME,
1528            COSTING_GET_TIP_PERCENTAGE_FUNCTION_NAME,
1529            COSTING_GET_FEE_BALANCE_FUNCTION_NAME,
1530            ADDRESS_ALLOCATE_FUNCTION_NAME,
1531            ADDRESS_GET_RESERVATION_ADDRESS_FUNCTION_NAME,
1532            OBJECT_GLOBALIZE_FUNCTION_NAME,
1533            KEY_VALUE_STORE_NEW_FUNCTION_NAME,
1534            OBJECT_INSTANCE_OF_FUNCTION_NAME,
1535            OBJECT_GET_BLUEPRINT_ID_FUNCTION_NAME,
1536            OBJECT_GET_OUTER_OBJECT_FUNCTION_NAME,
1537            ACTOR_EMIT_EVENT_FUNCTION_NAME,
1538            SYS_LOG_FUNCTION_NAME,
1539            SYS_BECH32_ENCODE_ADDRESS_FUNCTION_NAME,
1540            SYS_PANIC_FUNCTION_NAME,
1541            SYS_GET_TRANSACTION_HASH_FUNCTION_NAME,
1542            SYS_GENERATE_RUID_FUNCTION_NAME,
1543        ] {
1544            assert_invalid_wasm!(
1545                wat.replace("name_to_replace", name),
1546                PrepareError::InvalidImport(InvalidImport::InvalidFunctionType(name.to_string())),
1547                |w| WasmModule::enforce_import_constraints(w, ScryptoVmVersion::V1_0)
1548            );
1549        }
1550    }
1551
1552    #[test]
1553    fn test_invalid_import_protocol_mismatch() {
1554        let wat = r#"
1555            (module
1556                (import "env" "name_to_replace" (func $some_func (param i32) (result i32)))
1557            )
1558            "#;
1559
1560        for (current_version, expected_version, names) in [
1561            (
1562                ScryptoVmVersion::V1_0,
1563                ScryptoVmVersion::crypto_utils_v1(),
1564                vec![
1565                    CRYPTO_UTILS_BLS12381_V1_VERIFY_FUNCTION_NAME,
1566                    CRYPTO_UTILS_BLS12381_V1_AGGREGATE_VERIFY_FUNCTION_NAME,
1567                    CRYPTO_UTILS_BLS12381_V1_FAST_AGGREGATE_VERIFY_FUNCTION_NAME,
1568                    CRYPTO_UTILS_BLS12381_G2_SIGNATURE_AGGREGATE_FUNCTION_NAME,
1569                    CRYPTO_UTILS_KECCAK256_HASH_FUNCTION_NAME,
1570                ],
1571            ),
1572            (
1573                ScryptoVmVersion::V1_1,
1574                ScryptoVmVersion::crypto_utils_v2(),
1575                vec![
1576                    CRYPTO_UTILS_BLAKE2B_256_HASH_FUNCTION_NAME,
1577                    CRYPTO_UTILS_ED25519_VERIFY_FUNCTION_NAME,
1578                    CRYPTO_UTILS_SECP256K1_ECDSA_VERIFY_FUNCTION_NAME,
1579                    CRYPTO_UTILS_SECP256K1_ECDSA_VERIFY_AND_KEY_RECOVER_FUNCTION_NAME,
1580                    CRYPTO_UTILS_SECP256K1_ECDSA_VERIFY_AND_KEY_RECOVER_UNCOMPRESSED_FUNCTION_NAME,
1581                ],
1582            ),
1583        ] {
1584            for name in names {
1585                assert_invalid_wasm!(
1586                    wat.replace("name_to_replace", name),
1587                    PrepareError::InvalidImport(InvalidImport::ProtocolVersionMismatch {
1588                        name: name.to_string(),
1589                        current_version: current_version.into(),
1590                        expected_version: expected_version.into(),
1591                    }),
1592                    |w| WasmModule::enforce_import_constraints(w, current_version)
1593                );
1594            }
1595        }
1596    }
1597
1598    #[test]
1599    fn test_enforce_global_limit() {
1600        assert_invalid_wasm!(
1601            r#"
1602            (module
1603                (global $g1 i32 (i32.const 0))
1604                (global $g2 i32 (i32.const 0))
1605                (global $g3 i32 (i32.const 0))
1606                (global $g4 i32 (i32.const 0))
1607            )
1608            "#,
1609            PrepareError::TooManyGlobals { max: 3, current: 4 },
1610            |x| WasmModule::enforce_global_limit(x, 3)
1611        );
1612    }
1613
1614    #[test]
1615    fn test_memory() {
1616        assert_invalid_wasm!(
1617            r#"
1618            (module
1619            )
1620            "#,
1621            PrepareError::InvalidMemory(InvalidMemory::MissingMemorySection),
1622            |x| WasmModule::enforce_memory_limit_and_inject_max(x, 5)
1623        );
1624        // NOTE: Disabled as MVP only allow 1 memory definition
1625        // assert_invalid_wasm!(
1626        //     r#"
1627        //     (module
1628        //         (memory 2)
1629        //         (memory 2)
1630        //     )
1631        //     "#,
1632        //     PrepareError::InvalidMemory(InvalidMemory::TooManyMemories),
1633        //     |x| WasmModule::enforce_memory_limit(x, 5)
1634        // );
1635        assert_invalid_wasm!(
1636            r#"
1637            (module
1638                (memory 6)
1639            )
1640            "#,
1641            PrepareError::InvalidMemory(InvalidMemory::MemorySizeLimitExceeded),
1642            |x| WasmModule::enforce_memory_limit_and_inject_max(x, 5)
1643        );
1644        assert_invalid_wasm!(
1645            r#"
1646            (module
1647                (memory 2)
1648            )
1649            "#,
1650            PrepareError::InvalidMemory(InvalidMemory::MemoryNotExported),
1651            |x| WasmModule::enforce_memory_limit_and_inject_max(x, 5)
1652        );
1653    }
1654
1655    #[test]
1656    fn test_table() {
1657        assert_invalid_wasm!(
1658            r#"
1659            (module
1660                (table 6 funcref)
1661            )
1662            "#,
1663            PrepareError::InvalidTable(InvalidTable::InitialTableSizeLimitExceeded),
1664            |x| WasmModule::enforce_table_limit(x, 5)
1665        );
1666    }
1667
1668    #[test]
1669    fn test_br_table() {
1670        assert_invalid_wasm!(
1671            r#"
1672            (module
1673                (func (param i32) (result i32)
1674                    (block
1675                        (block
1676                            (br_table 1 0 1 0 1 0 1 (local.get 0))
1677                            (return (i32.const 21))
1678                        )
1679                        (return (i32.const 20))
1680                    )
1681                    (i32.const 22)
1682                )
1683            )
1684            "#,
1685            PrepareError::TooManyTargetsInBrTable,
1686            |x| WasmModule::enforce_br_table_limit(x, 5)
1687        );
1688    }
1689
1690    #[test]
1691    fn test_function_limits() {
1692        assert_invalid_wasm!(
1693            r#"
1694            (module
1695                (func (result i32)
1696                    (i32.const 11)
1697                )
1698                (func (result i32)
1699                    (i32.const 22)
1700                )
1701                (func (result i32)
1702                    (i32.const 33)
1703                )
1704            )
1705            "#,
1706            PrepareError::TooManyFunctions,
1707            |x| WasmModule::enforce_function_limit(x, 2, 3, 3)
1708        );
1709
1710        assert_invalid_wasm!(
1711            r#"
1712            (module
1713                (func (param i32 i32 i32 i32) (result i32)
1714                    (i32.const 22)
1715                )
1716            )
1717            "#,
1718            PrepareError::TooManyFunctionParams,
1719            |x| WasmModule::enforce_function_limit(x, 2, 3, 3)
1720        );
1721
1722        assert_invalid_wasm!(
1723            r#"
1724            (module
1725                (func (result i32)
1726                    (local $v1 i32)
1727
1728                    (local.set $v1 (i32.const 1))
1729
1730                    (i32.const 22)
1731                )
1732                (func (result i32)
1733                    (local $v1 i32)
1734                    (local $v2 i64)
1735                    (local $v3 i64)
1736                    (local $v4 i32)
1737
1738                    (local.set $v1 (i32.const 1))
1739                    (local.set $v2 (i64.const 2))
1740                    (local.set $v3 (i64.const 3))
1741                    (local.set $v4 (i32.const 4))
1742
1743                    (i32.const 22)
1744                )
1745            )
1746            "#,
1747            PrepareError::TooManyFunctionLocals { max: 3, actual: 4 },
1748            |x| WasmModule::enforce_function_limit(x, 2, 3, 3)
1749        );
1750    }
1751
1752    #[test]
1753    fn test_blueprint_constraints() {
1754        let mut blueprints = index_map_new();
1755        blueprints.insert(
1756            "Test".to_string(),
1757            BlueprintDefinitionInit {
1758                blueprint_type: BlueprintType::default(),
1759                is_transient: false,
1760                feature_set: indexset!(),
1761                dependencies: indexset!(),
1762
1763                schema: BlueprintSchemaInit {
1764                    generics: vec![],
1765                    schema: SchemaV1 {
1766                        type_kinds: vec![],
1767                        type_metadata: vec![],
1768                        type_validations: vec![],
1769                    }.into_versioned(),
1770                    state: BlueprintStateSchemaInit {
1771                        fields: vec![FieldSchema::static_field(LocalTypeId::WellKnown(UNIT_TYPE))],
1772                        collections: vec![],
1773                    },
1774                    events: Default::default(),
1775                    types: BlueprintTypeSchemaInit::default(),
1776                    functions: BlueprintFunctionsSchemaInit {
1777                        functions: indexmap!(
1778                            "f".to_string() => FunctionSchemaInit {
1779                                receiver: Option::None,
1780                                input: radix_blueprint_schema_init::TypeRef::Static(LocalTypeId::WellKnown(ANY_TYPE)),
1781                                output: radix_blueprint_schema_init::TypeRef::Static(LocalTypeId::WellKnown(UNIT_TYPE)),
1782                                export: "Test_f".to_string(),
1783                            }
1784                        ),
1785                    },
1786                    hooks: BlueprintHooksInit::default(),
1787                },
1788
1789                royalty_config: Default::default(),
1790                auth_config: Default::default(),
1791            },
1792        );
1793
1794        assert_invalid_wasm!(
1795            r#"
1796            (module
1797            )
1798            "#,
1799            PrepareError::NoExportSection,
1800            |x| WasmModule::enforce_export_constraints(x, blueprints.values())
1801        );
1802        // symbol not found
1803        assert_invalid_wasm!(
1804            r#"
1805            (module
1806                (func (export "foo") (result i32)
1807                    (i32.const 0)
1808                )
1809            )
1810            "#,
1811            PrepareError::MissingExport {
1812                export_name: "Test_f".to_string()
1813            },
1814            |x| WasmModule::enforce_export_constraints(x, blueprints.values())
1815        );
1816        // signature does not match
1817        assert_invalid_wasm!(
1818            r#"
1819            (module
1820                (func (export "Test_f") (result i32)
1821                    (i32.const 0)
1822                )
1823            )
1824            "#,
1825            PrepareError::MissingExport {
1826                export_name: "Test_f".to_string()
1827            },
1828            |x| WasmModule::enforce_export_constraints(x, blueprints.values())
1829        );
1830
1831        // export kind does not match
1832        assert_invalid_wasm!(
1833            r#"
1834            (module
1835                (global (export "Test_f") i32 (i32.const 0))
1836            )
1837            "#,
1838            PrepareError::MissingExport {
1839                export_name: "Test_f".to_string()
1840            },
1841            |x| WasmModule::enforce_export_constraints(x, blueprints.values())
1842        );
1843    }
1844
1845    #[cfg(feature = "radix_engine_tests")]
1846    #[test]
1847    fn test_contains_sign_ext_ops() {
1848        let code = wat2wasm!(
1849            r#"
1850            (module
1851                (func $f
1852                    (i64.const 1)
1853                    (i64.extend8_s) ;; sign extension op
1854                    drop
1855                )
1856            )
1857            "#
1858        );
1859
1860        assert!(WasmModule::init(&code).unwrap().contains_sign_ext_ops());
1861
1862        let code = wat2wasm!(
1863            r#"
1864            (module
1865                (func $f
1866                    (i64.const 1)
1867                    drop
1868                )
1869            )
1870            "#
1871        );
1872
1873        assert!(!WasmModule::init(&code).unwrap().contains_sign_ext_ops());
1874    }
1875}