radix_engine/vm/wasm/
wasm_validator.rs

1use crate::internal_prelude::*;
2use crate::vm::wasm::*;
3use crate::vm::ScryptoVmVersion;
4use radix_engine_interface::blueprints::package::BlueprintDefinitionInit;
5
6pub struct ScryptoV1WasmValidator {
7    pub max_memory_size_in_pages: u32,
8    pub max_initial_table_size: u32,
9    pub max_number_of_br_table_targets: u32,
10    pub max_number_of_functions: u32,
11    pub max_number_of_function_params: u32,
12    pub max_number_of_function_locals: u32,
13    pub max_number_of_globals: u32,
14    pub instrumenter_config: WasmValidatorConfigV1,
15    pub version: ScryptoVmVersion,
16}
17
18impl ScryptoV1WasmValidator {
19    pub fn new(version: ScryptoVmVersion) -> Self {
20        if version > ScryptoVmVersion::latest() {
21            panic!("Invalid minor version: {:?}", version);
22        }
23
24        Self {
25            max_memory_size_in_pages: MAX_MEMORY_SIZE_IN_PAGES,
26            max_initial_table_size: MAX_INITIAL_TABLE_SIZE,
27            max_number_of_br_table_targets: MAX_NUMBER_OF_BR_TABLE_TARGETS,
28            max_number_of_functions: MAX_NUMBER_OF_FUNCTIONS,
29            max_number_of_function_params: MAX_NUMBER_OF_FUNCTION_PARAMS,
30            max_number_of_function_locals: MAX_NUMBER_OF_FUNCTION_LOCALS,
31            max_number_of_globals: MAX_NUMBER_OF_GLOBALS,
32            instrumenter_config: WasmValidatorConfigV1::new(),
33            version,
34        }
35    }
36}
37
38impl ScryptoV1WasmValidator {
39    pub fn validate<'a, I: Iterator<Item = &'a BlueprintDefinitionInit>>(
40        &self,
41        code: &[u8],
42        blueprints: I,
43    ) -> Result<(Vec<u8>, Vec<String>), PrepareError> {
44        WasmModule::init(code)?
45            .enforce_no_start_function()?
46            .enforce_import_constraints(self.version)?
47            .enforce_export_names()?
48            .enforce_memory_limit_and_inject_max(self.max_memory_size_in_pages)?
49            .enforce_table_limit(self.max_initial_table_size)?
50            .enforce_br_table_limit(self.max_number_of_br_table_targets)?
51            .enforce_function_limit(
52                self.max_number_of_functions,
53                self.max_number_of_function_params,
54                self.max_number_of_function_locals,
55            )?
56            .enforce_global_limit(self.max_number_of_globals)?
57            .enforce_export_constraints(blueprints)?
58            .inject_instruction_metering(&self.instrumenter_config)?
59            .inject_stack_metering(self.instrumenter_config.max_stack_size())?
60            .ensure_instantiatable()?
61            .ensure_compilable()?
62            .to_bytes()
63    }
64}
65
66#[cfg(test)]
67mod tests {
68    use radix_engine_interface::blueprints::package::PackageDefinition;
69    use wabt::{wasm2wat, wat2wasm};
70
71    use super::ScryptoV1WasmValidator;
72    use super::ScryptoVmVersion;
73
74    #[test]
75    fn test_validate() {
76        let code = wat2wasm(
77            r#"
78        (module
79
80            ;; Simple function that always returns `()`
81            (func $Test_f (param $0 i64) (result i64)
82              ;; Grow memory
83              (drop
84                (memory.grow (i32.const 1000000))
85              )
86
87              ;; Encode () in SBOR at address 0x0
88              (i32.const 0)
89              (i32.const 92)  ;; prefix
90              (i32.store8)
91              (i32.const 1)
92              (i32.const 33)  ;; tuple value kind
93              (i32.store8)
94              (i32.const 2)
95              (i32.const 0)  ;; tuple length
96              (i32.store8)
97
98              ;; Return slice (ptr = 0, len = 3)
99              (i64.const 3)
100            )
101
102            (memory $0 1)
103            (export "memory" (memory $0))
104            (export "Test_f" (func $Test_f))
105        )"#,
106        )
107        .unwrap();
108
109        let instrumented_code = wasm2wat(
110            ScryptoV1WasmValidator::new(ScryptoVmVersion::latest())
111                .validate(
112                    &code,
113                    PackageDefinition::new_single_function_test_definition("Test", "f")
114                        .blueprints
115                        .values(),
116                )
117                .unwrap()
118                .0,
119        )
120        .unwrap();
121
122        assert_eq!(
123            instrumented_code,
124            r#"(module
125  (type (;0;) (func (param i64) (result i64)))
126  (type (;1;) (func (param i64)))
127  (import "env" "gas" (func (;0;) (type 1)))
128  (func (;1;) (type 0) (param i64) (result i64)
129    i64.const 14788284
130    call 0
131    i32.const 1000000
132    memory.grow
133    drop
134    i32.const 0
135    i32.const 92
136    i32.store8
137    i32.const 1
138    i32.const 33
139    i32.store8
140    i32.const 2
141    i32.const 0
142    i32.store8
143    i64.const 3)
144  (func (;2;) (type 0) (param i64) (result i64)
145    local.get 0
146    global.get 0
147    i32.const 4
148    i32.add
149    global.set 0
150    global.get 0
151    i32.const 1024
152    i32.gt_u
153    if  ;; label = @1
154      unreachable
155    end
156    call 1
157    global.get 0
158    i32.const 4
159    i32.sub
160    global.set 0)
161  (memory (;0;) 1 64)
162  (global (;0;) (mut i32) (i32.const 0))
163  (export "memory" (memory 0))
164  (export "Test_f" (func 2)))
165"#
166        )
167    }
168}