17
17
// along with this program. If not, see <https://www.gnu.org/licenses/>.
18
18
19
19
use crate :: { error:: WasmError , wasm_runtime:: HeapAllocStrategy } ;
20
- use wasm_instrument:: {
21
- export_mutable_globals,
22
- parity_wasm:: elements:: {
23
- deserialize_buffer, serialize, ExportEntry , External , Internal , MemorySection , MemoryType ,
24
- Module , Section ,
25
- } ,
20
+ use wasm_instrument:: parity_wasm:: elements:: {
21
+ deserialize_buffer, serialize, ExportEntry , External , Internal , MemorySection , MemoryType ,
22
+ Module , Section ,
26
23
} ;
27
24
28
- /// A bunch of information collected from a WebAssembly module .
25
+ /// A program blob containing a Substrate runtime .
29
26
#[ derive( Clone ) ]
30
- pub struct RuntimeBlob {
31
- raw_module : Module ,
27
+ pub struct RuntimeBlob ( BlobKind ) ;
28
+
29
+ #[ derive( Clone ) ]
30
+ enum BlobKind {
31
+ WebAssembly ( Module ) ,
32
+ PolkaVM ( polkavm:: ProgramBlob < ' static > ) ,
32
33
}
33
34
34
35
impl RuntimeBlob {
35
- /// Create `RuntimeBlob` from the given wasm code. Will attempt to decompress the code before
36
- /// deserializing it.
36
+ /// Create `RuntimeBlob` from the given WASM or PolkaVM compressed program blob.
37
37
///
38
38
/// See [`sp_maybe_compressed_blob`] for details about decompression.
39
39
pub fn uncompress_if_needed ( wasm_code : & [ u8 ] ) -> Result < Self , WasmError > {
@@ -43,31 +43,26 @@ impl RuntimeBlob {
43
43
Self :: new ( & wasm_code)
44
44
}
45
45
46
- /// Create `RuntimeBlob` from the given wasm code .
46
+ /// Create `RuntimeBlob` from the given WASM or PolkaVM program blob .
47
47
///
48
- /// Returns `Err` if the wasm code cannot be deserialized.
49
- pub fn new ( wasm_code : & [ u8 ] ) -> Result < Self , WasmError > {
50
- let raw_module: Module = deserialize_buffer ( wasm_code)
51
- . map_err ( |e| WasmError :: Other ( format ! ( "cannot deserialize module: {:?}" , e) ) ) ?;
52
- Ok ( Self { raw_module } )
53
- }
54
-
55
- /// The number of globals defined in locally in this module.
56
- pub fn declared_globals_count ( & self ) -> u32 {
57
- self . raw_module
58
- . global_section ( )
59
- . map ( |gs| gs. entries ( ) . len ( ) as u32 )
60
- . unwrap_or ( 0 )
61
- }
62
-
63
- /// The number of imports of globals.
64
- pub fn imported_globals_count ( & self ) -> u32 {
65
- self . raw_module . import_section ( ) . map ( |is| is. globals ( ) as u32 ) . unwrap_or ( 0 )
66
- }
48
+ /// Returns `Err` if the blob cannot be deserialized.
49
+ ///
50
+ /// Will only accept a PolkaVM program if the `SUBSTRATE_ENABLE_POLKAVM` environment
51
+ /// variable is set to `1`.
52
+ pub fn new ( raw_blob : & [ u8 ] ) -> Result < Self , WasmError > {
53
+ if raw_blob. starts_with ( b"PVM\0 " ) {
54
+ if crate :: is_polkavm_enabled ( ) {
55
+ return Ok ( Self ( BlobKind :: PolkaVM (
56
+ polkavm:: ProgramBlob :: parse ( raw_blob) ?. into_owned ( ) ,
57
+ ) ) ) ;
58
+ } else {
59
+ return Err ( WasmError :: Other ( "expected a WASM runtime blob, found a PolkaVM runtime blob; set the 'SUBSTRATE_ENABLE_POLKAVM' environment variable to enable the experimental PolkaVM-based executor" . to_string ( ) ) ) ;
60
+ }
61
+ }
67
62
68
- /// Perform an instrumentation that makes sure that the mutable globals are exported.
69
- pub fn expose_mutable_globals ( & mut self ) {
70
- export_mutable_globals ( & mut self . raw_module , "exported_internal_global" ) ;
63
+ let raw_module : Module = deserialize_buffer ( raw_blob )
64
+ . map_err ( |e| WasmError :: Other ( format ! ( "cannot deserialize module: {:?}" , e ) ) ) ? ;
65
+ Ok ( Self ( BlobKind :: WebAssembly ( raw_module) ) )
71
66
}
72
67
73
68
/// Run a pass that instrument this module so as to introduce a deterministic stack height
@@ -80,35 +75,28 @@ impl RuntimeBlob {
80
75
///
81
76
/// The stack cost of a function is computed based on how much locals there are and the maximum
82
77
/// depth of the wasm operand stack.
78
+ ///
79
+ /// Only valid for WASM programs; will return an error if the blob is a PolkaVM program.
83
80
pub fn inject_stack_depth_metering ( self , stack_depth_limit : u32 ) -> Result < Self , WasmError > {
84
81
let injected_module =
85
- wasm_instrument:: inject_stack_limiter ( self . raw_module , stack_depth_limit) . map_err (
86
- |e| WasmError :: Other ( format ! ( "cannot inject the stack limiter: {:?}" , e) ) ,
87
- ) ?;
88
-
89
- Ok ( Self { raw_module : injected_module } )
90
- }
82
+ wasm_instrument:: inject_stack_limiter ( self . into_webassembly_blob ( ) ?, stack_depth_limit)
83
+ . map_err ( |e| {
84
+ WasmError :: Other ( format ! ( "cannot inject the stack limiter: {:?}" , e) )
85
+ } ) ?;
91
86
92
- /// Perform an instrumentation that makes sure that a specific function `entry_point` is
93
- /// exported
94
- pub fn entry_point_exists ( & self , entry_point : & str ) -> bool {
95
- self . raw_module
96
- . export_section ( )
97
- . map ( |e| {
98
- e. entries ( ) . iter ( ) . any ( |e| {
99
- matches ! ( e. internal( ) , Internal :: Function ( _) ) && e. field ( ) == entry_point
100
- } )
101
- } )
102
- . unwrap_or_default ( )
87
+ Ok ( Self ( BlobKind :: WebAssembly ( injected_module) ) )
103
88
}
104
89
105
90
/// Converts a WASM memory import into a memory section and exports it.
106
91
///
107
92
/// Does nothing if there's no memory import.
108
93
///
109
94
/// May return an error in case the WASM module is invalid.
95
+ ///
96
+ /// Only valid for WASM programs; will return an error if the blob is a PolkaVM program.
110
97
pub fn convert_memory_import_into_export ( & mut self ) -> Result < ( ) , WasmError > {
111
- let import_section = match self . raw_module . import_section_mut ( ) {
98
+ let raw_module = self . as_webassembly_blob_mut ( ) ?;
99
+ let import_section = match raw_module. import_section_mut ( ) {
112
100
Some ( import_section) => import_section,
113
101
None => return Ok ( ( ) ) ,
114
102
} ;
@@ -124,7 +112,7 @@ impl RuntimeBlob {
124
112
let memory_name = entry. field ( ) . to_owned ( ) ;
125
113
import_entries. remove ( index) ;
126
114
127
- self . raw_module
115
+ raw_module
128
116
. insert_section ( Section :: Memory ( MemorySection :: with_entries ( vec ! [ memory_ty] ) ) )
129
117
. map_err ( |error| {
130
118
WasmError :: Other ( format ! (
@@ -133,14 +121,14 @@ impl RuntimeBlob {
133
121
) )
134
122
} ) ?;
135
123
136
- if self . raw_module . export_section_mut ( ) . is_none ( ) {
124
+ if raw_module. export_section_mut ( ) . is_none ( ) {
137
125
// A module without an export section is somewhat unrealistic, but let's do this
138
126
// just in case to cover all of our bases.
139
- self . raw_module
127
+ raw_module
140
128
. insert_section ( Section :: Export ( Default :: default ( ) ) )
141
129
. expect ( "an export section can be always inserted if it doesn't exist; qed" ) ;
142
130
}
143
- self . raw_module
131
+ raw_module
144
132
. export_section_mut ( )
145
133
. expect ( "export section already existed or we just added it above, so it always exists; qed" )
146
134
. entries_mut ( )
@@ -156,12 +144,14 @@ impl RuntimeBlob {
156
144
///
157
145
/// Will return an error in case there is no memory section present,
158
146
/// or if the memory section is empty.
147
+ ///
148
+ /// Only valid for WASM programs; will return an error if the blob is a PolkaVM program.
159
149
pub fn setup_memory_according_to_heap_alloc_strategy (
160
150
& mut self ,
161
151
heap_alloc_strategy : HeapAllocStrategy ,
162
152
) -> Result < ( ) , WasmError > {
163
- let memory_section = self
164
- . raw_module
153
+ let raw_module = self . as_webassembly_blob_mut ( ) ? ;
154
+ let memory_section = raw_module
165
155
. memory_section_mut ( )
166
156
. ok_or_else ( || WasmError :: Other ( "no memory section found" . into ( ) ) ) ?;
167
157
@@ -187,20 +177,57 @@ impl RuntimeBlob {
187
177
188
178
/// Scans the wasm blob for the first section with the name that matches the given. Returns the
189
179
/// contents of the custom section if found or `None` otherwise.
180
+ ///
181
+ /// Only valid for WASM programs; will return an error if the blob is a PolkaVM program.
190
182
pub fn custom_section_contents ( & self , section_name : & str ) -> Option < & [ u8 ] > {
191
- self . raw_module
183
+ self . as_webassembly_blob ( )
184
+ . ok ( ) ?
192
185
. custom_sections ( )
193
186
. find ( |cs| cs. name ( ) == section_name)
194
187
. map ( |cs| cs. payload ( ) )
195
188
}
196
189
197
190
/// Consumes this runtime blob and serializes it.
198
191
pub fn serialize ( self ) -> Vec < u8 > {
199
- serialize ( self . raw_module ) . expect ( "serializing into a vec should succeed; qed" )
192
+ match self . 0 {
193
+ BlobKind :: WebAssembly ( raw_module) =>
194
+ serialize ( raw_module) . expect ( "serializing into a vec should succeed; qed" ) ,
195
+ BlobKind :: PolkaVM ( ref blob) => blob. as_bytes ( ) . to_vec ( ) ,
196
+ }
197
+ }
198
+
199
+ fn as_webassembly_blob ( & self ) -> Result < & Module , WasmError > {
200
+ match self . 0 {
201
+ BlobKind :: WebAssembly ( ref raw_module) => Ok ( raw_module) ,
202
+ BlobKind :: PolkaVM ( ..) => Err ( WasmError :: Other (
203
+ "expected a WebAssembly program; found a PolkaVM program blob" . into ( ) ,
204
+ ) ) ,
205
+ }
200
206
}
201
207
202
- /// Destructure this structure into the underlying parity-wasm Module.
203
- pub fn into_inner ( self ) -> Module {
204
- self . raw_module
208
+ fn as_webassembly_blob_mut ( & mut self ) -> Result < & mut Module , WasmError > {
209
+ match self . 0 {
210
+ BlobKind :: WebAssembly ( ref mut raw_module) => Ok ( raw_module) ,
211
+ BlobKind :: PolkaVM ( ..) => Err ( WasmError :: Other (
212
+ "expected a WebAssembly program; found a PolkaVM program blob" . into ( ) ,
213
+ ) ) ,
214
+ }
215
+ }
216
+
217
+ fn into_webassembly_blob ( self ) -> Result < Module , WasmError > {
218
+ match self . 0 {
219
+ BlobKind :: WebAssembly ( raw_module) => Ok ( raw_module) ,
220
+ BlobKind :: PolkaVM ( ..) => Err ( WasmError :: Other (
221
+ "expected a WebAssembly program; found a PolkaVM program blob" . into ( ) ,
222
+ ) ) ,
223
+ }
224
+ }
225
+
226
+ /// Gets a reference to the inner PolkaVM program blob, if this is a PolkaVM program.
227
+ pub fn as_polkavm_blob ( & self ) -> Option < & polkavm:: ProgramBlob > {
228
+ match self . 0 {
229
+ BlobKind :: WebAssembly ( ..) => None ,
230
+ BlobKind :: PolkaVM ( ref blob) => Some ( blob) ,
231
+ }
205
232
}
206
233
}
0 commit comments