radix_engine/vm/wasm/
wasm_validator.rs1use 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}