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
70    use super::ScryptoV1WasmValidator;
71    use super::ScryptoVmVersion;
72
73    #[test]
74    fn test_validate() {
75        let code = wat::parse_str(
76            r#"
77        (module
78
79            ;; Simple function that always returns `()`
80            (func $Test_f (param $0 i64) (result i64)
81              ;; Grow memory
82              (drop
83                (memory.grow (i32.const 1000000))
84              )
85
86              ;; Encode () in SBOR at address 0x0
87              (i32.const 0)
88              (i32.const 92)  ;; prefix
89              (i32.store8)
90              (i32.const 1)
91              (i32.const 33)  ;; tuple value kind
92              (i32.store8)
93              (i32.const 2)
94              (i32.const 0)  ;; tuple length
95              (i32.store8)
96
97              ;; Return slice (ptr = 0, len = 3)
98              (i64.const 3)
99            )
100
101            (memory $0 1)
102            (export "memory" (memory $0))
103            (export "Test_f" (func $Test_f))
104        )"#,
105        )
106        .unwrap();
107
108        let instrumented_code = wasmprinter::print_bytes(
109            ScryptoV1WasmValidator::new(ScryptoVmVersion::latest())
110                .validate(
111                    &code,
112                    PackageDefinition::new_single_function_test_definition("Test", "f")
113                        .blueprints
114                        .values(),
115                )
116                .unwrap()
117                .0,
118        )
119        .unwrap();
120
121        assert_eq!(
122            instrumented_code,
123            r#"(module
124  (type (;0;) (func (param i64) (result i64)))
125  (type (;1;) (func (param i64)))
126  (import "env" "gas" (func (;0;) (type 1)))
127  (memory (;0;) 1 64)
128  (global (;0;) (mut i32) i32.const 0)
129  (export "memory" (memory 0))
130  (export "Test_f" (func 2))
131  (func (;1;) (type 0) (param i64) (result i64)
132    i64.const 14788284
133    call 0
134    i32.const 1000000
135    memory.grow
136    drop
137    i32.const 0
138    i32.const 92
139    i32.store8
140    i32.const 1
141    i32.const 33
142    i32.store8
143    i32.const 2
144    i32.const 0
145    i32.store8
146    i64.const 3
147  )
148  (func (;2;) (type 0) (param i64) (result i64)
149    local.get 0
150    global.get 0
151    i32.const 4
152    i32.add
153    global.set 0
154    global.get 0
155    i32.const 1024
156    i32.gt_u
157    if ;; label = @1
158      unreachable
159    end
160    call 1
161    global.get 0
162    i32.const 4
163    i32.sub
164    global.set 0
165  )
166)
167"#
168        )
169    }
170}