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.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            // 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    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        // return
1426        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        // input
1439        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        // instruction
1451        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        // global
1467        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        // NOTE: Disabled as MVP only allow 1 memory definition
1630        // assert_invalid_wasm!(
1631        //     r#"
1632        //     (module
1633        //         (memory 2)
1634        //         (memory 2)
1635        //     )
1636        //     "#,
1637        //     PrepareError::InvalidMemory(InvalidMemory::TooManyMemories),
1638        //     |x| WasmModule::enforce_memory_limit(x, 5)
1639        // );
1640        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        // symbol not found
1808        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        // signature does not match
1822        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        // export kind does not match
1837        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}