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
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}