1#![cfg_attr(not(feature = "std"), no_std)]
21
22extern crate alloc;
23
24use sp_runtime_interface::{
25 pass_by::{
26 AllocateAndReturnByCodec, AllocateAndReturnFatPointer, AllocateAndReturnPointer, PassAs,
27 PassFatPointerAndDecode, PassFatPointerAndDecodeSlice, PassFatPointerAndRead,
28 PassFatPointerAndReadWrite, PassPointerAndRead, PassPointerAndReadCopy,
29 PassPointerAndWrite, ReturnAs,
30 },
31 runtime_interface,
32};
33
34#[cfg(not(feature = "std"))]
35use core::mem;
36
37use alloc::{vec, vec::Vec};
38use sp_core::{sr25519::Public, wasm_export_functions};
39
40#[cfg(feature = "std")]
42include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));
43
44#[cfg(feature = "std")]
46pub fn wasm_binary_unwrap() -> &'static [u8] {
47 WASM_BINARY.expect(
48 "Development wasm binary is not available. Testing is only \
49 supported with the flag disabled.",
50 )
51}
52
53const TEST_ARRAY: [u8; 16] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
55
56#[runtime_interface]
57pub trait TestApi {
58 fn return_input(data: PassFatPointerAndRead<Vec<u8>>) -> AllocateAndReturnFatPointer<Vec<u8>> {
60 data
61 }
62
63 fn return_16kb() -> AllocateAndReturnByCodec<Vec<u32>> {
71 vec![0; 4 * 1024]
72 }
73
74 fn return_option_vec() -> AllocateAndReturnByCodec<Option<Vec<u8>>> {
75 let mut vec = Vec::new();
76 vec.resize(16 * 1024, 0xAA);
77 Some(vec)
78 }
79
80 fn return_option_bytes() -> AllocateAndReturnByCodec<Option<bytes::Bytes>> {
81 let mut vec = Vec::new();
82 vec.resize(16 * 1024, 0xAA);
83 Some(vec.into())
84 }
85
86 fn set_storage(
88 &mut self,
89 key: PassFatPointerAndRead<&[u8]>,
90 data: PassFatPointerAndRead<&[u8]>,
91 ) {
92 self.place_storage(key.to_vec(), Some(data.to_vec()));
93 }
94
95 fn return_value_into_mutable_reference(&self, data: PassFatPointerAndReadWrite<&mut [u8]>) {
97 let res = "hello";
98 data[..res.len()].copy_from_slice(res.as_bytes());
99 }
100
101 fn return_option_input(
103 data: PassFatPointerAndRead<Vec<u8>>,
104 ) -> AllocateAndReturnByCodec<Option<Vec<u8>>> {
105 Some(data)
106 }
107
108 fn get_and_return_array(
110 data: PassPointerAndReadCopy<[u8; 34], 34>,
111 ) -> AllocateAndReturnPointer<[u8; 16], 16> {
112 let mut res = [0u8; 16];
113 res.copy_from_slice(&data[..16]);
114 res
115 }
116
117 fn array_as_mutable_reference(data: PassPointerAndWrite<&mut [u8; 16], 16>) {
119 data.copy_from_slice(&TEST_ARRAY);
120 }
121
122 fn return_input_public_key(
124 key: PassPointerAndReadCopy<Public, 32>,
125 ) -> AllocateAndReturnPointer<Public, 32> {
126 key
127 }
128
129 fn invalid_utf8_data(_: PassFatPointerAndRead<&str>) {}
133
134 fn overwrite_native_function_implementation() -> bool {
137 false
138 }
139
140 fn test_versioning(&self, data: u32) -> bool {
141 data == 42 || data == 50
142 }
143
144 #[version(2)]
145 fn test_versioning(&self, data: u32) -> bool {
146 data == 42
147 }
148
149 fn test_versioning_register_only(&self, data: u32) -> bool {
150 data == 80
151 }
152
153 #[version(2, register_only)]
154 fn test_versioning_register_only(&self, data: u32) -> bool {
155 data == 42
156 }
157
158 fn return_input_as_tuple(
160 a: PassFatPointerAndRead<Vec<u8>>,
161 b: u32,
162 c: PassFatPointerAndDecode<Option<Vec<u32>>>,
163 d: u8,
164 ) -> AllocateAndReturnByCodec<(Vec<u8>, u32, Option<Vec<u32>>, u8)> {
165 (a, b, c, d)
166 }
167
168 fn pass_pointer_and_read_copy(value: PassPointerAndReadCopy<[u8; 3], 3>) {
171 assert_eq!(value, [1, 2, 3]);
172 }
173
174 fn pass_pointer_and_read(value: PassPointerAndRead<&[u8; 3], 3>) {
175 assert_eq!(value, &[1, 2, 3]);
176 }
177
178 fn pass_fat_pointer_and_read(value: PassFatPointerAndRead<&[u8]>) {
179 assert_eq!(value, [1, 2, 3]);
180 }
181
182 fn pass_fat_pointer_and_read_write(value: PassFatPointerAndReadWrite<&mut [u8]>) {
183 assert_eq!(value, [1, 2, 3]);
184 value.copy_from_slice(&[4, 5, 6]);
185 }
186
187 fn pass_pointer_and_write(value: PassPointerAndWrite<&mut [u8; 3], 3>) {
188 assert_eq!(*value, [0, 0, 0]);
189 *value = [1, 2, 3];
190 }
191
192 fn pass_by_codec(value: PassFatPointerAndDecode<Vec<u16>>) {
193 assert_eq!(value, [1, 2, 3]);
194 }
195
196 fn pass_slice_ref_by_codec(value: PassFatPointerAndDecodeSlice<&[u16]>) {
197 assert_eq!(value, [1, 2, 3]);
198 }
199
200 fn pass_as(value: PassAs<Opaque, u32>) {
201 assert_eq!(value.0, 123);
202 }
203
204 fn return_as() -> ReturnAs<Opaque, u32> {
205 Opaque(123)
206 }
207
208 fn allocate_and_return_pointer() -> AllocateAndReturnPointer<[u8; 3], 3> {
209 [1, 2, 3]
210 }
211
212 fn allocate_and_return_fat_pointer() -> AllocateAndReturnFatPointer<Vec<u8>> {
213 vec![1, 2, 3]
214 }
215
216 fn allocate_and_return_by_codec() -> AllocateAndReturnByCodec<Vec<u16>> {
217 vec![1, 2, 3]
218 }
219}
220
221#[derive(Copy, Clone, PartialEq, Eq, Debug)]
222pub struct Opaque(u32);
223
224impl From<Opaque> for u32 {
225 fn from(value: Opaque) -> Self {
226 value.0
227 }
228}
229
230impl TryFrom<u32> for Opaque {
231 type Error = ();
232 fn try_from(value: u32) -> Result<Self, Self::Error> {
233 Ok(Opaque(value))
234 }
235}
236
237#[no_mangle]
240pub fn import_sp_io() {
241 sp_io::misc::print_utf8(&[]);
242}
243
244wasm_export_functions! {
245 fn test_return_data() {
246 let input = vec![1, 2, 3, 4, 5, 6];
247 let res = test_api::return_input(input.clone());
248
249 assert_eq!(input, res);
250 }
251
252 fn test_return_option_data() {
253 let input = vec![1, 2, 3, 4, 5, 6];
254 let res = test_api::return_option_input(input.clone());
255
256 assert_eq!(Some(input), res);
257 }
258
259 fn test_set_storage() {
260 let key = "hello";
261 let value = "world";
262
263 test_api::set_storage(key.as_bytes(), value.as_bytes());
264 }
265
266 fn test_return_value_into_mutable_reference() {
267 let mut data = vec![1, 2, 3, 4, 5, 6];
268
269 test_api::return_value_into_mutable_reference(&mut data);
270
271 let expected = "hello";
272 assert_eq!(expected.as_bytes(), &data[..expected.len()]);
273 }
274
275 fn test_get_and_return_array() {
276 let mut input = unsafe { mem::MaybeUninit::<[u8; 34]>::zeroed().assume_init() };
277 input.copy_from_slice(&[
278 24, 3, 23, 20, 2, 16, 32, 1, 12, 26, 27, 8, 29, 31, 6, 5, 4, 19, 10, 28, 34, 21, 18, 33, 9,
279 13, 22, 25, 15, 11, 30, 7, 14, 17,
280 ]);
281
282 let res = test_api::get_and_return_array(input);
283
284 assert_eq!(&res, &input[..16]);
285 }
286
287 fn test_array_as_mutable_reference() {
288 let mut array = [0u8; 16];
289 test_api::array_as_mutable_reference(&mut array);
290
291 assert_eq!(array, TEST_ARRAY);
292 }
293
294 fn test_return_input_public_key() {
295 let key = Public::try_from(
296 &[
297 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
298 25, 26, 27, 28, 29, 30, 31, 32,
299 ][..],
300 ).unwrap();
301 let ret_key = test_api::return_input_public_key(key.clone());
302
303 let key_data: &[u8] = key.as_ref();
304 let ret_key_data: &[u8] = ret_key.as_ref();
305 assert_eq!(key_data, ret_key_data);
306 }
307
308 fn test_invalid_utf8_data_should_return_an_error() {
309 let data = vec![0, 159, 146, 150];
310 let data_str = unsafe { alloc::str::from_utf8_unchecked(&data) };
312
313 test_api::invalid_utf8_data(data_str);
314 }
315
316 fn test_overwrite_native_function_implementation() {
317 fn new_implementation() -> bool {
318 true
319 }
320
321 assert!(!test_api::overwrite_native_function_implementation());
323
324 let _guard = test_api::host_overwrite_native_function_implementation
325 .replace_implementation(new_implementation);
326
327 assert!(test_api::overwrite_native_function_implementation());
328 }
329
330 fn test_vec_return_value_memory_is_freed() {
331 let mut len = 0;
332 for _ in 0..1024 {
333 len += test_api::return_16kb().len();
334 }
335 assert_eq!(1024 * 1024 * 4, len);
336 }
337
338 fn test_encoded_return_value_memory_is_freed() {
339 let mut len = 0;
340 for _ in 0..1024 {
341 len += test_api::return_option_input(vec![0; 16 * 1024]).map(|v| v.len()).unwrap();
342 }
343 assert_eq!(1024 * 1024 * 16, len);
344 }
345
346 fn test_array_return_value_memory_is_freed() {
347 let mut len = 0;
348 for _ in 0..1024 * 1024 {
349 len += test_api::get_and_return_array([0; 34])[1];
350 }
351 assert_eq!(0, len);
352 }
353
354 fn test_versioning_works() {
355 assert!(test_api::test_versioning(42));
359
360 assert!(!test_api::test_versioning(50));
361 assert!(!test_api::test_versioning(102));
362 }
363
364 fn test_versioning_register_only_works() {
365 assert!(!test_api::test_versioning_register_only(42));
368 assert!(test_api::test_versioning_register_only(80));
369 }
370
371 fn test_return_input_as_tuple() {
372 let a = vec![1, 3, 4, 5];
373 let b = 10000;
374 let c = Some(vec![2, 3]);
375 let d = 5;
376
377 let res = test_api::return_input_as_tuple(a.clone(), b, c.clone(), d);
378
379 assert_eq!(a, res.0);
380 assert_eq!(b, res.1);
381 assert_eq!(c, res.2);
382 assert_eq!(d, res.3);
383 }
384
385 fn test_return_option_vec() {
386 test_api::return_option_vec();
387 }
388
389 fn test_return_option_bytes() {
390 test_api::return_option_bytes();
391 }
392
393 fn test_marshalling_strategies() {
394 test_api::pass_pointer_and_read_copy([1_u8, 2, 3]);
395 test_api::pass_pointer_and_read(&[1_u8, 2, 3]);
396 test_api::pass_fat_pointer_and_read(&[1_u8, 2, 3][..]);
397 {
398 let mut slice = [1_u8, 2, 3];
399 test_api::pass_fat_pointer_and_read_write(&mut slice);
400 assert_eq!(slice, [4_u8, 5, 6]);
401 }
402 {
403 let mut slice = [9_u8, 9, 9];
404 test_api::pass_pointer_and_write(&mut slice);
405 assert_eq!(slice, [1_u8, 2, 3]);
406 }
407 test_api::pass_by_codec(vec![1_u16, 2, 3]);
408 test_api::pass_slice_ref_by_codec(&[1_u16, 2, 3][..]);
409 test_api::pass_as(Opaque(123));
410 assert_eq!(test_api::return_as(), Opaque(123));
411 assert_eq!(test_api::allocate_and_return_pointer(), [1_u8, 2, 3]);
412 assert_eq!(test_api::allocate_and_return_fat_pointer(), vec![1_u8, 2, 3]);
413 assert_eq!(test_api::allocate_and_return_by_codec(), vec![1_u16, 2, 3]);
414 }
415}