radix_engine/vm/wasm/
wasmi.rs

1use crate::errors::InvokeError;
2use crate::internal_prelude::*;
3#[cfg(feature = "coverage")]
4use crate::utils::save_coverage_data;
5use crate::vm::wasm::constants::*;
6use crate::vm::wasm::errors::*;
7use crate::vm::wasm::traits::*;
8use crate::vm::wasm::WasmEngine;
9use radix_engine_interface::api::actor_api::EventFlags;
10use radix_engine_interface::blueprints::package::CodeHash;
11use sbor::rust::mem::MaybeUninit;
12#[cfg(not(feature = "fuzzing"))]
13use sbor::rust::sync::Arc;
14use wasmi::core::HostError;
15use wasmi::errors::InstantiationError;
16use wasmi::*;
17
18type HostState = WasmiInstanceEnv;
19
20/// A `WasmiModule` defines a compiled WASM module
21pub struct WasmiModule {
22    module: Module,
23    #[allow(dead_code)]
24    code_size_bytes: usize,
25}
26
27/// A `WasmiModule` defines
28/// - an instantiated WASM module
29/// - a Store , which keeps user data
30/// - a Memory - linear memory reference to the Store
31pub struct WasmiInstance {
32    store: Store<HostState>,
33    instance: Instance,
34    memory: Memory,
35}
36
37/// This is to construct a `Store<WasmiInstanceEnv>`
38pub struct WasmiInstanceEnv {
39    runtime_ptr: MaybeUninit<*mut Box<dyn WasmRuntime>>,
40}
41
42impl WasmiInstanceEnv {
43    pub fn new() -> Self {
44        Self {
45            runtime_ptr: MaybeUninit::uninit(),
46        }
47    }
48}
49
50impl Default for WasmiInstanceEnv {
51    fn default() -> Self {
52        Self::new()
53    }
54}
55
56macro_rules! grab_runtime {
57    ($caller: expr) => {{
58        let runtime: &mut Box<dyn WasmRuntime> =
59            unsafe { &mut *$caller.data().runtime_ptr.assume_init() };
60        runtime
61    }};
62}
63macro_rules! grab_memory {
64    ($caller: expr) => {{
65        match $caller.get_export(EXPORT_MEMORY) {
66            Some(Extern::Memory(memory)) => memory,
67            _ => panic!("Failed to find memory export"),
68        }
69    }};
70}
71
72// native functions start
73fn consume_buffer(
74    caller: Caller<'_, HostState>,
75    buffer_id: BufferId,
76    destination_ptr: u32,
77) -> Result<(), InvokeError<WasmRuntimeError>> {
78    let runtime = grab_runtime!(caller);
79    let memory = grab_memory!(caller);
80
81    let result = runtime.buffer_consume(buffer_id);
82    match result {
83        Ok(slice) => {
84            write_memory(caller, memory, destination_ptr, &slice)?;
85            Ok(())
86        }
87        Err(e) => Err(e),
88    }
89}
90
91fn call_method(
92    mut caller: Caller<'_, HostState>,
93    receiver_ptr: u32,
94    receiver_len: u32,
95    ident_ptr: u32,
96    ident_len: u32,
97    args_ptr: u32,
98    args_len: u32,
99) -> Result<u64, InvokeError<WasmRuntimeError>> {
100    let runtime = grab_runtime!(caller);
101    let memory = grab_memory!(caller);
102
103    let receiver = read_memory(caller.as_context_mut(), memory, receiver_ptr, receiver_len)?;
104    let ident = read_memory(caller.as_context_mut(), memory, ident_ptr, ident_len)?;
105    let args = read_memory(caller.as_context_mut(), memory, args_ptr, args_len)?;
106
107    runtime
108        .object_call(receiver, ident, args)
109        .map(|buffer| buffer.0)
110}
111
112fn call_direct_method(
113    mut caller: Caller<'_, HostState>,
114    receiver_ptr: u32,
115    receiver_len: u32,
116    ident_ptr: u32,
117    ident_len: u32,
118    args_ptr: u32,
119    args_len: u32,
120) -> Result<u64, InvokeError<WasmRuntimeError>> {
121    let runtime = grab_runtime!(caller);
122    let memory = grab_memory!(caller);
123
124    let receiver = read_memory(caller.as_context_mut(), memory, receiver_ptr, receiver_len)?;
125    let ident = read_memory(caller.as_context_mut(), memory, ident_ptr, ident_len)?;
126    let args = read_memory(caller.as_context_mut(), memory, args_ptr, args_len)?;
127
128    runtime
129        .object_call_direct(receiver, ident, args)
130        .map(|buffer| buffer.0)
131}
132
133#[allow(clippy::too_many_arguments)]
134fn call_module_method(
135    mut caller: Caller<'_, HostState>,
136    receiver_ptr: u32,
137    receiver_len: u32,
138    module_id: u32,
139    ident_ptr: u32,
140    ident_len: u32,
141    args_ptr: u32,
142    args_len: u32,
143) -> Result<u64, InvokeError<WasmRuntimeError>> {
144    let runtime = grab_runtime!(caller);
145    let memory = grab_memory!(caller);
146
147    let receiver = read_memory(caller.as_context_mut(), memory, receiver_ptr, receiver_len)?;
148    let ident = read_memory(caller.as_context_mut(), memory, ident_ptr, ident_len)?;
149    let args = read_memory(caller.as_context_mut(), memory, args_ptr, args_len)?;
150
151    runtime
152        .object_call_module(receiver, module_id, ident, args)
153        .map(|buffer| buffer.0)
154}
155
156#[allow(clippy::too_many_arguments)]
157fn call_function(
158    mut caller: Caller<'_, HostState>,
159    package_address_ptr: u32,
160    package_address_len: u32,
161    blueprint_name_ptr: u32,
162    blueprint_name_len: u32,
163    ident_ptr: u32,
164    ident_len: u32,
165    args_ptr: u32,
166    args_len: u32,
167) -> Result<u64, InvokeError<WasmRuntimeError>> {
168    let runtime = grab_runtime!(caller);
169    let memory = grab_memory!(caller);
170
171    let package_address = read_memory(
172        caller.as_context_mut(),
173        memory,
174        package_address_ptr,
175        package_address_len,
176    )?;
177    let blueprint_name = read_memory(
178        caller.as_context_mut(),
179        memory,
180        blueprint_name_ptr,
181        blueprint_name_len,
182    )?;
183    let ident = read_memory(caller.as_context_mut(), memory, ident_ptr, ident_len)?;
184    let args = read_memory(caller.as_context_mut(), memory, args_ptr, args_len)?;
185
186    runtime
187        .blueprint_call(package_address, blueprint_name, ident, args)
188        .map(|buffer| buffer.0)
189}
190
191fn new_object(
192    mut caller: Caller<'_, HostState>,
193    blueprint_name_ptr: u32,
194    blueprint_name_len: u32,
195    object_states_ptr: u32,
196    object_states_len: u32,
197) -> Result<u64, InvokeError<WasmRuntimeError>> {
198    let runtime = grab_runtime!(caller);
199    let memory = grab_memory!(caller);
200
201    runtime
202        .object_new(
203            read_memory(
204                caller.as_context_mut(),
205                memory,
206                blueprint_name_ptr,
207                blueprint_name_len,
208            )?,
209            read_memory(
210                caller.as_context_mut(),
211                memory,
212                object_states_ptr,
213                object_states_len,
214            )?,
215        )
216        .map(|buffer| buffer.0)
217}
218
219fn new_key_value_store(
220    mut caller: Caller<'_, HostState>,
221    schema_id_ptr: u32,
222    schema_id_len: u32,
223) -> Result<u64, InvokeError<WasmRuntimeError>> {
224    let runtime = grab_runtime!(caller);
225    let memory = grab_memory!(caller);
226
227    runtime
228        .key_value_store_new(read_memory(
229            caller.as_context_mut(),
230            memory,
231            schema_id_ptr,
232            schema_id_len,
233        )?)
234        .map(|buffer| buffer.0)
235}
236
237fn allocate_global_address(
238    mut caller: Caller<'_, HostState>,
239    package_address_ptr: u32,
240    package_address_len: u32,
241    blueprint_name_ptr: u32,
242    blueprint_name_len: u32,
243) -> Result<u64, InvokeError<WasmRuntimeError>> {
244    let runtime = grab_runtime!(caller);
245    let memory = grab_memory!(caller);
246
247    runtime
248        .address_allocate(
249            read_memory(
250                caller.as_context_mut(),
251                memory,
252                package_address_ptr,
253                package_address_len,
254            )?,
255            read_memory(
256                caller.as_context_mut(),
257                memory,
258                blueprint_name_ptr,
259                blueprint_name_len,
260            )?,
261        )
262        .map(|buffer| buffer.0)
263}
264
265fn get_reservation_address(
266    mut caller: Caller<'_, HostState>,
267    node_id_ptr: u32,
268    node_id_len: u32,
269) -> Result<u64, InvokeError<WasmRuntimeError>> {
270    let runtime = grab_runtime!(caller);
271    let memory = grab_memory!(caller);
272
273    runtime
274        .address_get_reservation_address(read_memory(
275            caller.as_context_mut(),
276            memory,
277            node_id_ptr,
278            node_id_len,
279        )?)
280        .map(|buffer| buffer.0)
281}
282
283fn execution_cost_unit_limit(
284    caller: Caller<'_, HostState>,
285) -> Result<u32, InvokeError<WasmRuntimeError>> {
286    let runtime = grab_runtime!(caller);
287
288    runtime.costing_get_execution_cost_unit_limit()
289}
290
291fn execution_cost_unit_price(
292    caller: Caller<'_, HostState>,
293) -> Result<u64, InvokeError<WasmRuntimeError>> {
294    let runtime = grab_runtime!(caller);
295
296    runtime
297        .costing_get_execution_cost_unit_price()
298        .map(|buffer| buffer.0)
299}
300
301fn finalization_cost_unit_limit(
302    caller: Caller<'_, HostState>,
303) -> Result<u32, InvokeError<WasmRuntimeError>> {
304    let runtime = grab_runtime!(caller);
305
306    runtime.costing_get_finalization_cost_unit_limit()
307}
308
309fn finalization_cost_unit_price(
310    caller: Caller<'_, HostState>,
311) -> Result<u64, InvokeError<WasmRuntimeError>> {
312    let runtime = grab_runtime!(caller);
313
314    runtime
315        .costing_get_finalization_cost_unit_price()
316        .map(|buffer| buffer.0)
317}
318
319fn usd_price(caller: Caller<'_, HostState>) -> Result<u64, InvokeError<WasmRuntimeError>> {
320    let runtime = grab_runtime!(caller);
321
322    runtime.costing_get_usd_price().map(|buffer| buffer.0)
323}
324
325fn tip_percentage(caller: Caller<'_, HostState>) -> Result<u32, InvokeError<WasmRuntimeError>> {
326    let runtime = grab_runtime!(caller);
327
328    runtime.costing_get_tip_percentage()
329}
330
331fn fee_balance(caller: Caller<'_, HostState>) -> Result<u64, InvokeError<WasmRuntimeError>> {
332    let runtime = grab_runtime!(caller);
333
334    runtime.costing_get_fee_balance().map(|buffer| buffer.0)
335}
336
337fn globalize_object(
338    mut caller: Caller<'_, HostState>,
339    obj_id_ptr: u32,
340    obj_id_len: u32,
341    modules_ptr: u32,
342    modules_len: u32,
343    address_ptr: u32,
344    address_len: u32,
345) -> Result<u64, InvokeError<WasmRuntimeError>> {
346    let runtime = grab_runtime!(caller);
347    let memory = grab_memory!(caller);
348
349    runtime
350        .globalize_object(
351            read_memory(caller.as_context_mut(), memory, obj_id_ptr, obj_id_len)?,
352            read_memory(caller.as_context_mut(), memory, modules_ptr, modules_len)?,
353            read_memory(caller.as_context_mut(), memory, address_ptr, address_len)?,
354        )
355        .map(|buffer| buffer.0)
356}
357
358fn instance_of(
359    mut caller: Caller<'_, HostState>,
360    component_id_ptr: u32,
361    component_id_len: u32,
362    package_address_ptr: u32,
363    package_address_len: u32,
364    blueprint_name_ptr: u32,
365    blueprint_name_len: u32,
366) -> Result<u32, InvokeError<WasmRuntimeError>> {
367    let runtime = grab_runtime!(caller);
368    let memory = grab_memory!(caller);
369
370    runtime.instance_of(
371        read_memory(
372            caller.as_context_mut(),
373            memory,
374            component_id_ptr,
375            component_id_len,
376        )?,
377        read_memory(
378            caller.as_context_mut(),
379            memory,
380            package_address_ptr,
381            package_address_len,
382        )?,
383        read_memory(
384            caller.as_context_mut(),
385            memory,
386            blueprint_name_ptr,
387            blueprint_name_len,
388        )?,
389    )
390}
391
392fn blueprint_id(
393    mut caller: Caller<'_, HostState>,
394    component_id_ptr: u32,
395    component_id_len: u32,
396) -> Result<u64, InvokeError<WasmRuntimeError>> {
397    let runtime = grab_runtime!(caller);
398    let memory = grab_memory!(caller);
399
400    runtime
401        .blueprint_id(read_memory(
402            caller.as_context_mut(),
403            memory,
404            component_id_ptr,
405            component_id_len,
406        )?)
407        .map(|buffer| buffer.0)
408}
409
410fn get_outer_object(
411    mut caller: Caller<'_, HostState>,
412    component_id_ptr: u32,
413    component_id_len: u32,
414) -> Result<u64, InvokeError<WasmRuntimeError>> {
415    let runtime = grab_runtime!(caller);
416    let memory = grab_memory!(caller);
417
418    runtime
419        .get_outer_object(read_memory(
420            caller.as_context_mut(),
421            memory,
422            component_id_ptr,
423            component_id_len,
424        )?)
425        .map(|buffer| buffer.0)
426}
427
428fn lock_key_value_store_entry(
429    mut caller: Caller<'_, HostState>,
430    node_id_ptr: u32,
431    node_id_len: u32,
432    offset_ptr: u32,
433    offset_len: u32,
434    flags: u32,
435) -> Result<u32, InvokeError<WasmRuntimeError>> {
436    let runtime = grab_runtime!(caller);
437    let memory = grab_memory!(caller);
438
439    let node_id = read_memory(caller.as_context_mut(), memory, node_id_ptr, node_id_len)?;
440    let substate_key = read_memory(caller.as_context_mut(), memory, offset_ptr, offset_len)?;
441
442    runtime.key_value_store_open_entry(node_id, substate_key, flags)
443}
444
445fn key_value_entry_get(
446    caller: Caller<'_, HostState>,
447    handle: u32,
448) -> Result<u64, InvokeError<WasmRuntimeError>> {
449    let runtime = grab_runtime!(caller);
450
451    runtime.key_value_entry_get(handle).map(|buffer| buffer.0)
452}
453
454fn key_value_entry_set(
455    mut caller: Caller<'_, HostState>,
456    handle: u32,
457    buffer_ptr: u32,
458    buffer_len: u32,
459) -> Result<(), InvokeError<WasmRuntimeError>> {
460    let runtime = grab_runtime!(caller);
461    let memory = grab_memory!(caller);
462    let data = read_memory(caller.as_context_mut(), memory, buffer_ptr, buffer_len)?;
463    runtime.key_value_entry_set(handle, data)
464}
465
466fn key_value_entry_remove(
467    caller: Caller<'_, HostState>,
468    handle: u32,
469) -> Result<u64, InvokeError<WasmRuntimeError>> {
470    let runtime = grab_runtime!(caller);
471
472    runtime
473        .key_value_entry_remove(handle)
474        .map(|buffer| buffer.0)
475}
476
477fn unlock_key_value_entry(
478    caller: Caller<'_, HostState>,
479    handle: u32,
480) -> Result<(), InvokeError<WasmRuntimeError>> {
481    let runtime = grab_runtime!(caller);
482
483    runtime.key_value_entry_close(handle)
484}
485
486fn key_value_store_remove(
487    mut caller: Caller<'_, HostState>,
488    node_id_ptr: u32,
489    node_id_len: u32,
490    key_ptr: u32,
491    key_len: u32,
492) -> Result<u64, InvokeError<WasmRuntimeError>> {
493    let runtime = grab_runtime!(caller);
494    let memory = grab_memory!(caller);
495    let node_id = read_memory(caller.as_context_mut(), memory, node_id_ptr, node_id_len)?;
496    let key = read_memory(caller.as_context_mut(), memory, key_ptr, key_len)?;
497
498    runtime
499        .key_value_store_remove_entry(node_id, key)
500        .map(|buffer| buffer.0)
501}
502
503fn lock_field(
504    caller: Caller<'_, HostState>,
505    object_handle: u32,
506    field: u32,
507    flags: u32,
508) -> Result<u32, InvokeError<WasmRuntimeError>> {
509    let runtime = grab_runtime!(caller);
510
511    runtime.actor_open_field(object_handle, field as u8, flags)
512}
513
514fn field_lock_read(
515    caller: Caller<'_, HostState>,
516    handle: u32,
517) -> Result<u64, InvokeError<WasmRuntimeError>> {
518    let runtime = grab_runtime!(caller);
519
520    runtime.field_entry_read(handle).map(|buffer| buffer.0)
521}
522
523fn field_lock_write(
524    mut caller: Caller<'_, HostState>,
525    handle: u32,
526    data_ptr: u32,
527    data_len: u32,
528) -> Result<(), InvokeError<WasmRuntimeError>> {
529    let runtime = grab_runtime!(caller);
530    let memory = grab_memory!(caller);
531
532    let data = read_memory(caller.as_context_mut(), memory, data_ptr, data_len)?;
533
534    runtime.field_entry_write(handle, data)
535}
536
537fn field_lock_release(
538    caller: Caller<'_, HostState>,
539    handle: u32,
540) -> Result<(), InvokeError<WasmRuntimeError>> {
541    let runtime = grab_runtime!(caller);
542
543    runtime.field_entry_close(handle)
544}
545
546fn actor_get_node_id(
547    caller: Caller<'_, HostState>,
548    handle: u32,
549) -> Result<u64, InvokeError<WasmRuntimeError>> {
550    let runtime = grab_runtime!(caller);
551
552    runtime.actor_get_node_id(handle).map(|buffer| buffer.0)
553}
554
555fn get_package_address(
556    caller: Caller<'_, HostState>,
557) -> Result<u64, InvokeError<WasmRuntimeError>> {
558    let runtime = grab_runtime!(caller);
559
560    runtime.actor_get_package_address().map(|buffer| buffer.0)
561}
562
563fn get_blueprint_name(caller: Caller<'_, HostState>) -> Result<u64, InvokeError<WasmRuntimeError>> {
564    let runtime = grab_runtime!(caller);
565
566    runtime.actor_get_blueprint_name().map(|buffer| buffer.0)
567}
568
569#[inline]
570fn consume_wasm_execution_units(
571    caller: Caller<'_, HostState>,
572    n: u64,
573) -> Result<(), InvokeError<WasmRuntimeError>> {
574    let runtime: &mut Box<dyn WasmRuntime> =
575        unsafe { &mut *caller.data().runtime_ptr.assume_init() };
576
577    // TODO: wasm-instrument uses u64 for cost units. We need to decide if we want to move from u32
578    // to u64 as well.
579    runtime.consume_wasm_execution_units(n as u32)
580}
581
582fn emit_event(
583    mut caller: Caller<'_, HostState>,
584    event_name_ptr: u32,
585    event_name_len: u32,
586    event_data_ptr: u32,
587    event_data_len: u32,
588    flags: u32,
589) -> Result<(), InvokeError<WasmRuntimeError>> {
590    let runtime = grab_runtime!(caller);
591    let memory = grab_memory!(caller);
592
593    let event_name = read_memory(
594        caller.as_context_mut(),
595        memory,
596        event_name_ptr,
597        event_name_len,
598    )?;
599    let event_data = read_memory(
600        caller.as_context_mut(),
601        memory,
602        event_data_ptr,
603        event_data_len,
604    )?;
605    let event_flags = EventFlags::from_bits(flags).ok_or(InvokeError::SelfError(
606        WasmRuntimeError::InvalidEventFlags(flags),
607    ))?;
608
609    runtime.actor_emit_event(event_name, event_data, event_flags)
610}
611
612fn get_transaction_hash(
613    caller: Caller<'_, HostState>,
614) -> Result<u64, InvokeError<WasmRuntimeError>> {
615    let runtime = grab_runtime!(caller);
616
617    runtime.sys_get_transaction_hash().map(|buffer| buffer.0)
618}
619
620fn generate_ruid(caller: Caller<'_, HostState>) -> Result<u64, InvokeError<WasmRuntimeError>> {
621    let runtime = grab_runtime!(caller);
622
623    runtime.sys_generate_ruid().map(|buffer| buffer.0)
624}
625
626fn emit_log(
627    mut caller: Caller<'_, HostState>,
628    level_ptr: u32,
629    level_len: u32,
630    message_ptr: u32,
631    message_len: u32,
632) -> Result<(), InvokeError<WasmRuntimeError>> {
633    let runtime = grab_runtime!(caller);
634    let memory = grab_memory!(caller);
635
636    let level = read_memory(caller.as_context_mut(), memory, level_ptr, level_len)?;
637    let message = read_memory(caller.as_context_mut(), memory, message_ptr, message_len)?;
638
639    runtime.sys_log(level, message)
640}
641
642fn bech32_encode_address(
643    mut caller: Caller<'_, HostState>,
644    address_ptr: u32,
645    address_len: u32,
646) -> Result<u64, InvokeError<WasmRuntimeError>> {
647    let runtime = grab_runtime!(caller);
648    let memory = grab_memory!(caller);
649
650    let address = read_memory(caller.as_context_mut(), memory, address_ptr, address_len)?;
651
652    runtime
653        .sys_bech32_encode_address(address)
654        .map(|buffer| buffer.0)
655}
656
657fn panic(
658    mut caller: Caller<'_, HostState>,
659    message_ptr: u32,
660    message_len: u32,
661) -> Result<(), InvokeError<WasmRuntimeError>> {
662    let runtime = grab_runtime!(caller);
663    let memory = grab_memory!(caller);
664
665    let message = read_memory(caller.as_context_mut(), memory, message_ptr, message_len)?;
666
667    runtime.sys_panic(message)
668}
669
670fn bls12381_v1_verify(
671    mut caller: Caller<'_, HostState>,
672    message_ptr: u32,
673    message_len: u32,
674    public_key_ptr: u32,
675    public_key_len: u32,
676    signature_ptr: u32,
677    signature_len: u32,
678) -> Result<u32, InvokeError<WasmRuntimeError>> {
679    let runtime = grab_runtime!(caller);
680    let memory = grab_memory!(caller);
681
682    let message = read_memory(caller.as_context_mut(), memory, message_ptr, message_len)?;
683    let public_key = read_memory(
684        caller.as_context_mut(),
685        memory,
686        public_key_ptr,
687        public_key_len,
688    )?;
689    let signature = read_memory(
690        caller.as_context_mut(),
691        memory,
692        signature_ptr,
693        signature_len,
694    )?;
695
696    runtime.crypto_utils_bls12381_v1_verify(message, public_key, signature)
697}
698
699fn bls12381_v1_aggregate_verify(
700    mut caller: Caller<'_, HostState>,
701    pub_keys_and_msgs_ptr: u32,
702    pub_keys_and_msgs_len: u32,
703    signature_ptr: u32,
704    signature_len: u32,
705) -> Result<u32, InvokeError<WasmRuntimeError>> {
706    let runtime = grab_runtime!(caller);
707    let memory = grab_memory!(caller);
708
709    let pub_keys_and_msgs = read_memory(
710        caller.as_context_mut(),
711        memory,
712        pub_keys_and_msgs_ptr,
713        pub_keys_and_msgs_len,
714    )?;
715    let signature = read_memory(
716        caller.as_context_mut(),
717        memory,
718        signature_ptr,
719        signature_len,
720    )?;
721
722    runtime.crypto_utils_bls12381_v1_aggregate_verify(pub_keys_and_msgs, signature)
723}
724
725fn bls12381_v1_fast_aggregate_verify(
726    mut caller: Caller<'_, HostState>,
727    message_ptr: u32,
728    message_len: u32,
729    public_keys_ptr: u32,
730    public_keys_len: u32,
731    signature_ptr: u32,
732    signature_len: u32,
733) -> Result<u32, InvokeError<WasmRuntimeError>> {
734    let runtime = grab_runtime!(caller);
735    let memory = grab_memory!(caller);
736
737    let message = read_memory(caller.as_context_mut(), memory, message_ptr, message_len)?;
738    let public_keys = read_memory(
739        caller.as_context_mut(),
740        memory,
741        public_keys_ptr,
742        public_keys_len,
743    )?;
744    let signature = read_memory(
745        caller.as_context_mut(),
746        memory,
747        signature_ptr,
748        signature_len,
749    )?;
750
751    runtime.crypto_utils_bls12381_v1_fast_aggregate_verify(message, public_keys, signature)
752}
753
754fn bls12381_g2_signature_aggregate(
755    mut caller: Caller<'_, HostState>,
756    signatures_ptr: u32,
757    signatures_len: u32,
758) -> Result<u64, InvokeError<WasmRuntimeError>> {
759    let runtime = grab_runtime!(caller);
760    let memory = grab_memory!(caller);
761
762    let signatures = read_memory(
763        caller.as_context_mut(),
764        memory,
765        signatures_ptr,
766        signatures_len,
767    )?;
768
769    runtime
770        .crypto_utils_bls12381_g2_signature_aggregate(signatures)
771        .map(|buffer| buffer.0)
772}
773
774fn keccak256_hash(
775    mut caller: Caller<'_, HostState>,
776    data_ptr: u32,
777    data_len: u32,
778) -> Result<u64, InvokeError<WasmRuntimeError>> {
779    let runtime = grab_runtime!(caller);
780    let memory = grab_memory!(caller);
781
782    let data = read_memory(caller.as_context_mut(), memory, data_ptr, data_len)?;
783
784    runtime
785        .crypto_utils_keccak256_hash(data)
786        .map(|buffer| buffer.0)
787}
788
789fn blake2b_256_hash(
790    mut caller: Caller<'_, HostState>,
791    data_ptr: u32,
792    data_len: u32,
793) -> Result<u64, InvokeError<WasmRuntimeError>> {
794    let runtime = grab_runtime!(caller);
795    let memory = grab_memory!(caller);
796
797    let data = read_memory(caller.as_context_mut(), memory, data_ptr, data_len)?;
798
799    runtime
800        .crypto_utils_blake2b_256_hash(data)
801        .map(|buffer| buffer.0)
802}
803
804fn ed25519_verify(
805    mut caller: Caller<'_, HostState>,
806    message_ptr: u32,
807    message_len: u32,
808    public_key_ptr: u32,
809    public_key_len: u32,
810    signature_ptr: u32,
811    signature_len: u32,
812) -> Result<u32, InvokeError<WasmRuntimeError>> {
813    let runtime = grab_runtime!(caller);
814    let memory = grab_memory!(caller);
815
816    let message = read_memory(caller.as_context_mut(), memory, message_ptr, message_len)?;
817    let public_key = read_memory(
818        caller.as_context_mut(),
819        memory,
820        public_key_ptr,
821        public_key_len,
822    )?;
823    let signature = read_memory(
824        caller.as_context_mut(),
825        memory,
826        signature_ptr,
827        signature_len,
828    )?;
829
830    runtime.crypto_utils_ed25519_verify(message, public_key, signature)
831}
832
833fn secp256k1_ecdsa_verify(
834    mut caller: Caller<'_, HostState>,
835    message_ptr: u32,
836    message_len: u32,
837    public_key_ptr: u32,
838    public_key_len: u32,
839    signature_ptr: u32,
840    signature_len: u32,
841) -> Result<u32, InvokeError<WasmRuntimeError>> {
842    let runtime = grab_runtime!(caller);
843    let memory = grab_memory!(caller);
844
845    let message = read_memory(caller.as_context_mut(), memory, message_ptr, message_len)?;
846    let public_key = read_memory(
847        caller.as_context_mut(),
848        memory,
849        public_key_ptr,
850        public_key_len,
851    )?;
852    let signature = read_memory(
853        caller.as_context_mut(),
854        memory,
855        signature_ptr,
856        signature_len,
857    )?;
858
859    runtime.crypto_utils_secp256k1_ecdsa_verify(message, public_key, signature)
860}
861
862fn secp256k1_ecdsa_verify_and_key_recover(
863    mut caller: Caller<'_, HostState>,
864    message_ptr: u32,
865    message_len: u32,
866    signature_ptr: u32,
867    signature_len: u32,
868) -> Result<u64, InvokeError<WasmRuntimeError>> {
869    let runtime = grab_runtime!(caller);
870    let memory = grab_memory!(caller);
871
872    let message = read_memory(caller.as_context_mut(), memory, message_ptr, message_len)?;
873    let signature = read_memory(
874        caller.as_context_mut(),
875        memory,
876        signature_ptr,
877        signature_len,
878    )?;
879
880    runtime
881        .crypto_utils_secp256k1_ecdsa_verify_and_key_recover(message, signature)
882        .map(|buffer| buffer.0)
883}
884
885fn secp256k1_ecdsa_verify_and_key_recover_uncompressed(
886    mut caller: Caller<'_, HostState>,
887    message_ptr: u32,
888    message_len: u32,
889    signature_ptr: u32,
890    signature_len: u32,
891) -> Result<u64, InvokeError<WasmRuntimeError>> {
892    let runtime = grab_runtime!(caller);
893    let memory = grab_memory!(caller);
894
895    let message = read_memory(caller.as_context_mut(), memory, message_ptr, message_len)?;
896    let signature = read_memory(
897        caller.as_context_mut(),
898        memory,
899        signature_ptr,
900        signature_len,
901    )?;
902
903    runtime
904        .crypto_utils_secp256k1_ecdsa_verify_and_key_recover_uncompressed(message, signature)
905        .map(|buffer| buffer.0)
906}
907
908#[cfg(feature = "radix_engine_tests")]
909fn test_host_read_memory(
910    mut caller: Caller<'_, HostState>,
911    memory_offs: u32,
912    data_len: u32,
913) -> Result<(), InvokeError<WasmRuntimeError>> {
914    // - attempt to read data of given length data starting from given memory offset memory_ptr
915    let memory = grab_memory!(caller);
916
917    read_memory(caller.as_context_mut(), memory, memory_offs, data_len)?;
918
919    Ok(())
920}
921
922#[cfg(feature = "radix_engine_tests")]
923fn test_host_write_memory(
924    mut caller: Caller<'_, HostState>,
925    memory_ptr: u32,
926    data_len: u32,
927) -> Result<(), InvokeError<WasmRuntimeError>> {
928    // - generate some random data of of given length data_len
929    // - attempt to write this data into given memory offset memory_ptr
930    let memory = grab_memory!(caller);
931
932    let data = vec![0u8; data_len as usize];
933    write_memory(caller.as_context_mut(), memory, memory_ptr, &data)?;
934
935    Ok(())
936}
937
938#[cfg(feature = "radix_engine_tests")]
939fn test_host_check_memory_is_clean(
940    caller: Caller<'_, HostState>,
941) -> Result<u64, InvokeError<WasmRuntimeError>> {
942    // - attempt to read data of given length data starting from given memory offset memory_ptr
943    let memory = grab_memory!(caller);
944    let store_ctx = caller.as_context();
945
946    let data = memory.data(&store_ctx);
947    let clean = !data.iter().any(|&x| x != 0x0);
948
949    Ok(clean as u64)
950}
951// native functions ends
952
953macro_rules! linker_define {
954    ($linker: expr, $name: expr, $var: expr) => {
955        $linker
956            .define(MODULE_ENV_NAME, $name, $var)
957            .expect(stringify!("Failed to define new linker item {}", $name));
958    };
959}
960
961#[derive(Debug)]
962pub enum WasmiInstantiationError {
963    CompilationError(Error),
964    PreInstantiationError(Error),
965    InstantiationError(InstantiationError),
966}
967
968impl WasmiModule {
969    pub fn new(code: &[u8]) -> Result<Self, WasmiInstantiationError> {
970        let mut config = wasmi::Config::default();
971
972        // In order to speed compilation we deliberately
973        // - use LazyTranslation compilation mode
974        // - compiling without WASM validation (Module::new_checked())
975        // (for more details see: https://github.com/wasmi-labs/wasmi/releases/tag/v0.32.0)
976        //
977        // It is assumed that WASM code passed here is already WASM validated,
978        // so above combination should be fine.
979        config.compilation_mode(wasmi::CompilationMode::LazyTranslation);
980        let engine = Engine::new(&config);
981
982        let module = unsafe {
983            Module::new_unchecked(&engine, code)
984                .map_err(WasmiInstantiationError::CompilationError)?
985        };
986
987        Ok(Self {
988            module,
989            code_size_bytes: code.len(),
990        })
991    }
992
993    fn host_funcs_set(module: &Module, store: &mut Store<HostState>) -> Result<InstancePre, Error> {
994        let host_consume_buffer = Func::wrap(
995            store.as_context_mut(),
996            |caller: Caller<'_, HostState>,
997             buffer_id: BufferId,
998             destination_ptr: u32|
999             -> Result<(), Error> {
1000                consume_buffer(caller, buffer_id, destination_ptr).map_err(Error::host)
1001            },
1002        );
1003
1004        let host_call_method = Func::wrap(
1005            store.as_context_mut(),
1006            |caller: Caller<'_, HostState>,
1007             receiver_ptr: u32,
1008             receiver_len: u32,
1009             ident_ptr: u32,
1010             ident_len: u32,
1011             args_ptr: u32,
1012             args_len: u32|
1013             -> Result<u64, Error> {
1014                call_method(
1015                    caller,
1016                    receiver_ptr,
1017                    receiver_len,
1018                    ident_ptr,
1019                    ident_len,
1020                    args_ptr,
1021                    args_len,
1022                )
1023                .map_err(Error::host)
1024            },
1025        );
1026
1027        let host_call_module_method = Func::wrap(
1028            store.as_context_mut(),
1029            |caller: Caller<'_, HostState>,
1030             receiver_ptr: u32,
1031             receiver_len: u32,
1032             module_id: u32,
1033             ident_ptr: u32,
1034             ident_len: u32,
1035             args_ptr: u32,
1036             args_len: u32|
1037             -> Result<u64, Error> {
1038                call_module_method(
1039                    caller,
1040                    receiver_ptr,
1041                    receiver_len,
1042                    module_id,
1043                    ident_ptr,
1044                    ident_len,
1045                    args_ptr,
1046                    args_len,
1047                )
1048                .map_err(Error::host)
1049            },
1050        );
1051
1052        let host_call_direct_method = Func::wrap(
1053            store.as_context_mut(),
1054            |caller: Caller<'_, HostState>,
1055             receiver_ptr: u32,
1056             receiver_len: u32,
1057             ident_ptr: u32,
1058             ident_len: u32,
1059             args_ptr: u32,
1060             args_len: u32|
1061             -> Result<u64, Error> {
1062                call_direct_method(
1063                    caller,
1064                    receiver_ptr,
1065                    receiver_len,
1066                    ident_ptr,
1067                    ident_len,
1068                    args_ptr,
1069                    args_len,
1070                )
1071                .map_err(Error::host)
1072            },
1073        );
1074
1075        let host_blueprint_call = Func::wrap(
1076            store.as_context_mut(),
1077            |caller: Caller<'_, HostState>,
1078             package_address_ptr: u32,
1079             package_address_len: u32,
1080             blueprint_name_ptr: u32,
1081             blueprint_name_len: u32,
1082             ident_ptr: u32,
1083             ident_len: u32,
1084             args_ptr: u32,
1085             args_len: u32|
1086             -> Result<u64, Error> {
1087                call_function(
1088                    caller,
1089                    package_address_ptr,
1090                    package_address_len,
1091                    blueprint_name_ptr,
1092                    blueprint_name_len,
1093                    ident_ptr,
1094                    ident_len,
1095                    args_ptr,
1096                    args_len,
1097                )
1098                .map_err(Error::host)
1099            },
1100        );
1101
1102        let host_new_component = Func::wrap(
1103            store.as_context_mut(),
1104            |caller: Caller<'_, HostState>,
1105             blueprint_name_ptr: u32,
1106             blueprint_name_len: u32,
1107             object_states_ptr: u32,
1108             object_states_len: u32|
1109             -> Result<u64, Error> {
1110                new_object(
1111                    caller,
1112                    blueprint_name_ptr,
1113                    blueprint_name_len,
1114                    object_states_ptr,
1115                    object_states_len,
1116                )
1117                .map_err(Error::host)
1118            },
1119        );
1120
1121        let host_new_key_value_store = Func::wrap(
1122            store.as_context_mut(),
1123            |caller: Caller<'_, HostState>,
1124             schema_ptr: u32,
1125             schema_len: u32|
1126             -> Result<u64, Error> {
1127                new_key_value_store(caller, schema_ptr, schema_len).map_err(Error::host)
1128            },
1129        );
1130
1131        let host_allocate_global_address = Func::wrap(
1132            store.as_context_mut(),
1133            |caller: Caller<'_, HostState>,
1134             package_address_ptr: u32,
1135             package_address_len: u32,
1136             blueprint_name_ptr: u32,
1137             blueprint_name_len: u32|
1138             -> Result<u64, Error> {
1139                allocate_global_address(
1140                    caller,
1141                    package_address_ptr,
1142                    package_address_len,
1143                    blueprint_name_ptr,
1144                    blueprint_name_len,
1145                )
1146                .map_err(Error::host)
1147            },
1148        );
1149
1150        let host_get_reservation_address = Func::wrap(
1151            store.as_context_mut(),
1152            |caller: Caller<'_, HostState>,
1153             node_id_ptr: u32,
1154             node_id_len: u32|
1155             -> Result<u64, Error> {
1156                get_reservation_address(caller, node_id_ptr, node_id_len).map_err(Error::host)
1157            },
1158        );
1159
1160        let host_execution_cost_unit_limit = Func::wrap(
1161            store.as_context_mut(),
1162            |caller: Caller<'_, HostState>| -> Result<u32, Error> {
1163                execution_cost_unit_limit(caller).map_err(Error::host)
1164            },
1165        );
1166
1167        let host_execution_cost_unit_price = Func::wrap(
1168            store.as_context_mut(),
1169            |caller: Caller<'_, HostState>| -> Result<u64, Error> {
1170                execution_cost_unit_price(caller).map_err(Error::host)
1171            },
1172        );
1173
1174        let host_finalization_cost_unit_limit = Func::wrap(
1175            store.as_context_mut(),
1176            |caller: Caller<'_, HostState>| -> Result<u32, Error> {
1177                finalization_cost_unit_limit(caller).map_err(Error::host)
1178            },
1179        );
1180
1181        let host_finalization_cost_unit_price = Func::wrap(
1182            store.as_context_mut(),
1183            |caller: Caller<'_, HostState>| -> Result<u64, Error> {
1184                finalization_cost_unit_price(caller).map_err(Error::host)
1185            },
1186        );
1187
1188        let host_usd_price = Func::wrap(
1189            store.as_context_mut(),
1190            |caller: Caller<'_, HostState>| -> Result<u64, Error> {
1191                usd_price(caller).map_err(Error::host)
1192            },
1193        );
1194
1195        let host_tip_percentage = Func::wrap(
1196            store.as_context_mut(),
1197            |caller: Caller<'_, HostState>| -> Result<u32, Error> {
1198                tip_percentage(caller).map_err(Error::host)
1199            },
1200        );
1201
1202        let host_fee_balance = Func::wrap(
1203            store.as_context_mut(),
1204            |caller: Caller<'_, HostState>| -> Result<u64, Error> {
1205                fee_balance(caller).map_err(Error::host)
1206            },
1207        );
1208
1209        let host_globalize_object = Func::wrap(
1210            store.as_context_mut(),
1211            |caller: Caller<'_, HostState>,
1212             obj_ptr: u32,
1213             obj_len: u32,
1214             modules_ptr: u32,
1215             modules_len: u32,
1216             address_ptr: u32,
1217             address_len: u32|
1218             -> Result<u64, Error> {
1219                globalize_object(
1220                    caller,
1221                    obj_ptr,
1222                    obj_len,
1223                    modules_ptr,
1224                    modules_len,
1225                    address_ptr,
1226                    address_len,
1227                )
1228                .map_err(Error::host)
1229            },
1230        );
1231
1232        let host_instance_of = Func::wrap(
1233            store.as_context_mut(),
1234            |caller: Caller<'_, HostState>,
1235             object_id_ptr: u32,
1236             object_id_len: u32,
1237             package_address_ptr: u32,
1238             package_address_len: u32,
1239             blueprint_name_ptr: u32,
1240             blueprint_name_len: u32|
1241             -> Result<u32, Error> {
1242                instance_of(
1243                    caller,
1244                    object_id_ptr,
1245                    object_id_len,
1246                    package_address_ptr,
1247                    package_address_len,
1248                    blueprint_name_ptr,
1249                    blueprint_name_len,
1250                )
1251                .map_err(Error::host)
1252            },
1253        );
1254
1255        let host_get_blueprint_id = Func::wrap(
1256            store.as_context_mut(),
1257            |caller: Caller<'_, HostState>,
1258             object_id_ptr: u32,
1259             object_id_len: u32|
1260             -> Result<u64, Error> {
1261                blueprint_id(caller, object_id_ptr, object_id_len).map_err(Error::host)
1262            },
1263        );
1264
1265        let host_get_outer_object = Func::wrap(
1266            store.as_context_mut(),
1267            |caller: Caller<'_, HostState>,
1268             object_id_ptr: u32,
1269             object_id_len: u32|
1270             -> Result<u64, Error> {
1271                get_outer_object(caller, object_id_ptr, object_id_len).map_err(Error::host)
1272            },
1273        );
1274
1275        let host_lock_key_value_store_entry = Func::wrap(
1276            store.as_context_mut(),
1277            |caller: Caller<'_, HostState>,
1278             node_id_ptr: u32,
1279             node_id_len: u32,
1280             offset_ptr: u32,
1281             offset_len: u32,
1282             mutable: u32|
1283             -> Result<u32, Error> {
1284                lock_key_value_store_entry(
1285                    caller,
1286                    node_id_ptr,
1287                    node_id_len,
1288                    offset_ptr,
1289                    offset_len,
1290                    mutable,
1291                )
1292                .map_err(Error::host)
1293            },
1294        );
1295
1296        let host_key_value_entry_get = Func::wrap(
1297            store.as_context_mut(),
1298            |caller: Caller<'_, HostState>, handle: u32| -> Result<u64, Error> {
1299                key_value_entry_get(caller, handle).map_err(Error::host)
1300            },
1301        );
1302
1303        let host_key_value_entry_set = Func::wrap(
1304            store.as_context_mut(),
1305            |caller: Caller<'_, HostState>,
1306             handle: u32,
1307             buffer_ptr: u32,
1308             buffer_len: u32|
1309             -> Result<(), Error> {
1310                key_value_entry_set(caller, handle, buffer_ptr, buffer_len).map_err(Error::host)
1311            },
1312        );
1313
1314        let host_key_value_entry_remove = Func::wrap(
1315            store.as_context_mut(),
1316            |caller: Caller<'_, HostState>, handle: u32| -> Result<u64, Error> {
1317                key_value_entry_remove(caller, handle).map_err(Error::host)
1318            },
1319        );
1320
1321        let host_unlock_key_value_entry = Func::wrap(
1322            store.as_context_mut(),
1323            |caller: Caller<'_, HostState>, handle: u32| -> Result<(), Error> {
1324                unlock_key_value_entry(caller, handle).map_err(Error::host)
1325            },
1326        );
1327
1328        let host_key_value_store_remove = Func::wrap(
1329            store.as_context_mut(),
1330            |caller: Caller<'_, HostState>,
1331             node_id_ptr: u32,
1332             node_id_len: u32,
1333             key_ptr: u32,
1334             key_len: u32|
1335             -> Result<u64, Error> {
1336                key_value_store_remove(caller, node_id_ptr, node_id_len, key_ptr, key_len)
1337                    .map_err(Error::host)
1338            },
1339        );
1340
1341        let host_lock_field = Func::wrap(
1342            store.as_context_mut(),
1343            |caller: Caller<'_, HostState>,
1344             object_handle: u32,
1345             field: u32,
1346             lock_flags: u32|
1347             -> Result<u32, Error> {
1348                lock_field(caller, object_handle, field, lock_flags).map_err(Error::host)
1349            },
1350        );
1351
1352        let host_field_lock_read = Func::wrap(
1353            store.as_context_mut(),
1354            |caller: Caller<'_, HostState>, handle: u32| -> Result<u64, Error> {
1355                field_lock_read(caller, handle).map_err(Error::host)
1356            },
1357        );
1358
1359        let host_field_lock_write = Func::wrap(
1360            store.as_context_mut(),
1361            |caller: Caller<'_, HostState>,
1362             handle: u32,
1363             data_ptr: u32,
1364             data_len: u32|
1365             -> Result<(), Error> {
1366                field_lock_write(caller, handle, data_ptr, data_len).map_err(Error::host)
1367            },
1368        );
1369
1370        let host_field_lock_release = Func::wrap(
1371            store.as_context_mut(),
1372            |caller: Caller<'_, HostState>, handle: u32| -> Result<(), Error> {
1373                field_lock_release(caller, handle).map_err(Error::host)
1374            },
1375        );
1376
1377        let host_actor_get_node_id = Func::wrap(
1378            store.as_context_mut(),
1379            |caller: Caller<'_, HostState>, handle: u32| -> Result<u64, Error> {
1380                actor_get_node_id(caller, handle).map_err(Error::host)
1381            },
1382        );
1383
1384        let host_get_package_address = Func::wrap(
1385            store.as_context_mut(),
1386            |caller: Caller<'_, HostState>| -> Result<u64, Error> {
1387                get_package_address(caller).map_err(Error::host)
1388            },
1389        );
1390
1391        let host_get_blueprint_name = Func::wrap(
1392            store.as_context_mut(),
1393            |caller: Caller<'_, HostState>| -> Result<u64, Error> {
1394                get_blueprint_name(caller).map_err(Error::host)
1395            },
1396        );
1397
1398        let host_consume_wasm_execution_units = Func::wrap(
1399            store.as_context_mut(),
1400            |caller: Caller<'_, HostState>, n: u64| -> Result<(), Error> {
1401                consume_wasm_execution_units(caller, n).map_err(Error::host)
1402            },
1403        );
1404
1405        let host_emit_event = Func::wrap(
1406            store.as_context_mut(),
1407            |caller: Caller<'_, HostState>,
1408             event_name_ptr: u32,
1409             event_name_len: u32,
1410             event_data_ptr: u32,
1411             event_data_len: u32,
1412             flags: u32|
1413             -> Result<(), Error> {
1414                emit_event(
1415                    caller,
1416                    event_name_ptr,
1417                    event_name_len,
1418                    event_data_ptr,
1419                    event_data_len,
1420                    flags,
1421                )
1422                .map_err(Error::host)
1423            },
1424        );
1425
1426        let host_emit_log = Func::wrap(
1427            store.as_context_mut(),
1428            |caller: Caller<'_, HostState>,
1429             level_ptr: u32,
1430             level_len: u32,
1431             message_ptr: u32,
1432             message_len: u32|
1433             -> Result<(), Error> {
1434                emit_log(caller, level_ptr, level_len, message_ptr, message_len)
1435                    .map_err(Error::host)
1436            },
1437        );
1438
1439        let host_panic = Func::wrap(
1440            store.as_context_mut(),
1441            |caller: Caller<'_, HostState>,
1442             message_ptr: u32,
1443             message_len: u32|
1444             -> Result<(), Error> {
1445                panic(caller, message_ptr, message_len).map_err(Error::host)
1446            },
1447        );
1448
1449        let host_bech32_encode_address = Func::wrap(
1450            store.as_context_mut(),
1451            |caller: Caller<'_, HostState>,
1452             address_ptr: u32,
1453             address_len: u32|
1454             -> Result<u64, Error> {
1455                bech32_encode_address(caller, address_ptr, address_len).map_err(Error::host)
1456            },
1457        );
1458
1459        let host_get_transaction_hash = Func::wrap(
1460            store.as_context_mut(),
1461            |caller: Caller<'_, HostState>| -> Result<u64, Error> {
1462                get_transaction_hash(caller).map_err(Error::host)
1463            },
1464        );
1465
1466        let host_generate_ruid = Func::wrap(
1467            store.as_context_mut(),
1468            |caller: Caller<'_, HostState>| -> Result<u64, Error> {
1469                generate_ruid(caller).map_err(Error::host)
1470            },
1471        );
1472
1473        let host_bls12381_v1_verify = Func::wrap(
1474            store.as_context_mut(),
1475            |caller: Caller<'_, HostState>,
1476             message_ptr: u32,
1477             message_len: u32,
1478             public_key_ptr: u32,
1479             public_key_len: u32,
1480             signature_ptr: u32,
1481             signature_len: u32|
1482             -> Result<u32, Error> {
1483                bls12381_v1_verify(
1484                    caller,
1485                    message_ptr,
1486                    message_len,
1487                    public_key_ptr,
1488                    public_key_len,
1489                    signature_ptr,
1490                    signature_len,
1491                )
1492                .map_err(Error::host)
1493            },
1494        );
1495
1496        let host_bls12381_v1_aggregate_verify = Func::wrap(
1497            store.as_context_mut(),
1498            |caller: Caller<'_, HostState>,
1499             pub_keys_and_msgs_ptr: u32,
1500             pub_keys_and_msgs_len: u32,
1501             signature_ptr: u32,
1502             signature_len: u32|
1503             -> Result<u32, Error> {
1504                bls12381_v1_aggregate_verify(
1505                    caller,
1506                    pub_keys_and_msgs_ptr,
1507                    pub_keys_and_msgs_len,
1508                    signature_ptr,
1509                    signature_len,
1510                )
1511                .map_err(Error::host)
1512            },
1513        );
1514
1515        let host_bls12381_v1_fast_aggregate_verify = Func::wrap(
1516            store.as_context_mut(),
1517            |caller: Caller<'_, HostState>,
1518             message_ptr: u32,
1519             message_len: u32,
1520             public_keys_ptr: u32,
1521             public_keys_len: u32,
1522             signature_ptr: u32,
1523             signature_len: u32|
1524             -> Result<u32, Error> {
1525                bls12381_v1_fast_aggregate_verify(
1526                    caller,
1527                    message_ptr,
1528                    message_len,
1529                    public_keys_ptr,
1530                    public_keys_len,
1531                    signature_ptr,
1532                    signature_len,
1533                )
1534                .map_err(Error::host)
1535            },
1536        );
1537
1538        let host_bls12381_g2_signature_aggregate = Func::wrap(
1539            store.as_context_mut(),
1540            |caller: Caller<'_, HostState>,
1541             signatures_ptr: u32,
1542             signatures_len: u32|
1543             -> Result<u64, Error> {
1544                bls12381_g2_signature_aggregate(caller, signatures_ptr, signatures_len)
1545                    .map_err(Error::host)
1546            },
1547        );
1548
1549        let host_keccak256_hash = Func::wrap(
1550            store.as_context_mut(),
1551            |caller: Caller<'_, HostState>, data_ptr: u32, data_len: u32| -> Result<u64, Error> {
1552                keccak256_hash(caller, data_ptr, data_len).map_err(Error::host)
1553            },
1554        );
1555
1556        let host_blake2b_256_hash = Func::wrap(
1557            store.as_context_mut(),
1558            |caller: Caller<'_, HostState>, data_ptr: u32, data_len: u32| -> Result<u64, Error> {
1559                blake2b_256_hash(caller, data_ptr, data_len).map_err(Error::host)
1560            },
1561        );
1562
1563        let host_ed25519_verify = Func::wrap(
1564            store.as_context_mut(),
1565            |caller: Caller<'_, HostState>,
1566             message_ptr: u32,
1567             message_len: u32,
1568             public_key_ptr: u32,
1569             public_key_len: u32,
1570             signature_ptr: u32,
1571             signature_len: u32|
1572             -> Result<u32, Error> {
1573                ed25519_verify(
1574                    caller,
1575                    message_ptr,
1576                    message_len,
1577                    public_key_ptr,
1578                    public_key_len,
1579                    signature_ptr,
1580                    signature_len,
1581                )
1582                .map_err(Error::host)
1583            },
1584        );
1585        let host_secp2561k1_ecdsa_verify = Func::wrap(
1586            store.as_context_mut(),
1587            |caller: Caller<'_, HostState>,
1588             message_ptr: u32,
1589             message_len: u32,
1590             public_key_ptr: u32,
1591             public_key_len: u32,
1592             signature_ptr: u32,
1593             signature_len: u32|
1594             -> Result<u32, Error> {
1595                secp256k1_ecdsa_verify(
1596                    caller,
1597                    message_ptr,
1598                    message_len,
1599                    public_key_ptr,
1600                    public_key_len,
1601                    signature_ptr,
1602                    signature_len,
1603                )
1604                .map_err(Error::host)
1605            },
1606        );
1607        let host_secp2561k1_ecdsa_verify_and_key_recover = Func::wrap(
1608            store.as_context_mut(),
1609            |caller: Caller<'_, HostState>,
1610             message_ptr: u32,
1611             message_len: u32,
1612             signature_ptr: u32,
1613             signature_len: u32|
1614             -> Result<u64, Error> {
1615                secp256k1_ecdsa_verify_and_key_recover(
1616                    caller,
1617                    message_ptr,
1618                    message_len,
1619                    signature_ptr,
1620                    signature_len,
1621                )
1622                .map_err(Error::host)
1623            },
1624        );
1625        let host_secp2561k1_ecdsa_verify_and_key_recover_uncompressed = Func::wrap(
1626            store.as_context_mut(),
1627            |caller: Caller<'_, HostState>,
1628             message_ptr: u32,
1629             message_len: u32,
1630             signature_ptr: u32,
1631             signature_len: u32|
1632             -> Result<u64, Error> {
1633                secp256k1_ecdsa_verify_and_key_recover_uncompressed(
1634                    caller,
1635                    message_ptr,
1636                    message_len,
1637                    signature_ptr,
1638                    signature_len,
1639                )
1640                .map_err(Error::host)
1641            },
1642        );
1643
1644        let mut linker = <Linker<HostState>>::new(module.engine());
1645
1646        linker_define!(linker, BUFFER_CONSUME_FUNCTION_NAME, host_consume_buffer);
1647        linker_define!(linker, OBJECT_CALL_FUNCTION_NAME, host_call_method);
1648        linker_define!(
1649            linker,
1650            OBJECT_CALL_MODULE_FUNCTION_NAME,
1651            host_call_module_method
1652        );
1653        linker_define!(
1654            linker,
1655            OBJECT_CALL_DIRECT_FUNCTION_NAME,
1656            host_call_direct_method
1657        );
1658        linker_define!(linker, BLUEPRINT_CALL_FUNCTION_NAME, host_blueprint_call);
1659        linker_define!(linker, OBJECT_NEW_FUNCTION_NAME, host_new_component);
1660
1661        linker_define!(
1662            linker,
1663            ADDRESS_ALLOCATE_FUNCTION_NAME,
1664            host_allocate_global_address
1665        );
1666        linker_define!(
1667            linker,
1668            ADDRESS_GET_RESERVATION_ADDRESS_FUNCTION_NAME,
1669            host_get_reservation_address
1670        );
1671        linker_define!(
1672            linker,
1673            COSTING_GET_EXECUTION_COST_UNIT_LIMIT_FUNCTION_NAME,
1674            host_execution_cost_unit_limit
1675        );
1676        linker_define!(
1677            linker,
1678            COSTING_GET_EXECUTION_COST_UNIT_PRICE_FUNCTION_NAME,
1679            host_execution_cost_unit_price
1680        );
1681        linker_define!(
1682            linker,
1683            COSTING_GET_FINALIZATION_COST_UNIT_LIMIT_FUNCTION_NAME,
1684            host_finalization_cost_unit_limit
1685        );
1686        linker_define!(
1687            linker,
1688            COSTING_GET_FINALIZATION_COST_UNIT_PRICE_FUNCTION_NAME,
1689            host_finalization_cost_unit_price
1690        );
1691        linker_define!(linker, COSTING_GET_USD_PRICE_FUNCTION_NAME, host_usd_price);
1692        linker_define!(
1693            linker,
1694            COSTING_GET_TIP_PERCENTAGE_FUNCTION_NAME,
1695            host_tip_percentage
1696        );
1697        linker_define!(
1698            linker,
1699            COSTING_GET_FEE_BALANCE_FUNCTION_NAME,
1700            host_fee_balance
1701        );
1702        linker_define!(
1703            linker,
1704            OBJECT_GLOBALIZE_FUNCTION_NAME,
1705            host_globalize_object
1706        );
1707        linker_define!(linker, OBJECT_INSTANCE_OF_FUNCTION_NAME, host_instance_of);
1708        linker_define!(
1709            linker,
1710            OBJECT_GET_BLUEPRINT_ID_FUNCTION_NAME,
1711            host_get_blueprint_id
1712        );
1713        linker_define!(
1714            linker,
1715            OBJECT_GET_OUTER_OBJECT_FUNCTION_NAME,
1716            host_get_outer_object
1717        );
1718        linker_define!(linker, ACTOR_OPEN_FIELD_FUNCTION_NAME, host_lock_field);
1719
1720        linker_define!(
1721            linker,
1722            KEY_VALUE_STORE_NEW_FUNCTION_NAME,
1723            host_new_key_value_store
1724        );
1725        linker_define!(
1726            linker,
1727            KEY_VALUE_STORE_OPEN_ENTRY_FUNCTION_NAME,
1728            host_lock_key_value_store_entry
1729        );
1730        linker_define!(
1731            linker,
1732            KEY_VALUE_ENTRY_READ_FUNCTION_NAME,
1733            host_key_value_entry_get
1734        );
1735        linker_define!(
1736            linker,
1737            KEY_VALUE_ENTRY_WRITE_FUNCTION_NAME,
1738            host_key_value_entry_set
1739        );
1740        linker_define!(
1741            linker,
1742            KEY_VALUE_ENTRY_REMOVE_FUNCTION_NAME,
1743            host_key_value_entry_remove
1744        );
1745        linker_define!(
1746            linker,
1747            KEY_VALUE_ENTRY_CLOSE_FUNCTION_NAME,
1748            host_unlock_key_value_entry
1749        );
1750        linker_define!(
1751            linker,
1752            KEY_VALUE_STORE_REMOVE_ENTRY_FUNCTION_NAME,
1753            host_key_value_store_remove
1754        );
1755
1756        linker_define!(linker, FIELD_ENTRY_READ_FUNCTION_NAME, host_field_lock_read);
1757        linker_define!(
1758            linker,
1759            FIELD_ENTRY_WRITE_FUNCTION_NAME,
1760            host_field_lock_write
1761        );
1762        linker_define!(
1763            linker,
1764            FIELD_ENTRY_CLOSE_FUNCTION_NAME,
1765            host_field_lock_release
1766        );
1767        linker_define!(
1768            linker,
1769            ACTOR_GET_OBJECT_ID_FUNCTION_NAME,
1770            host_actor_get_node_id
1771        );
1772        linker_define!(
1773            linker,
1774            ACTOR_GET_PACKAGE_ADDRESS_FUNCTION_NAME,
1775            host_get_package_address
1776        );
1777        linker_define!(
1778            linker,
1779            ACTOR_GET_BLUEPRINT_NAME_FUNCTION_NAME,
1780            host_get_blueprint_name
1781        );
1782        linker_define!(
1783            linker,
1784            COSTING_CONSUME_WASM_EXECUTION_UNITS_FUNCTION_NAME,
1785            host_consume_wasm_execution_units
1786        );
1787        linker_define!(linker, ACTOR_EMIT_EVENT_FUNCTION_NAME, host_emit_event);
1788        linker_define!(linker, SYS_LOG_FUNCTION_NAME, host_emit_log);
1789        linker_define!(linker, SYS_PANIC_FUNCTION_NAME, host_panic);
1790        linker_define!(
1791            linker,
1792            SYS_GET_TRANSACTION_HASH_FUNCTION_NAME,
1793            host_get_transaction_hash
1794        );
1795        linker_define!(
1796            linker,
1797            SYS_BECH32_ENCODE_ADDRESS_FUNCTION_NAME,
1798            host_bech32_encode_address
1799        );
1800        linker_define!(linker, SYS_GENERATE_RUID_FUNCTION_NAME, host_generate_ruid);
1801        linker_define!(
1802            linker,
1803            CRYPTO_UTILS_BLS12381_V1_VERIFY_FUNCTION_NAME,
1804            host_bls12381_v1_verify
1805        );
1806        linker_define!(
1807            linker,
1808            CRYPTO_UTILS_BLS12381_V1_AGGREGATE_VERIFY_FUNCTION_NAME,
1809            host_bls12381_v1_aggregate_verify
1810        );
1811        linker_define!(
1812            linker,
1813            CRYPTO_UTILS_BLS12381_V1_FAST_AGGREGATE_VERIFY_FUNCTION_NAME,
1814            host_bls12381_v1_fast_aggregate_verify
1815        );
1816        linker_define!(
1817            linker,
1818            CRYPTO_UTILS_BLS12381_G2_SIGNATURE_AGGREGATE_FUNCTION_NAME,
1819            host_bls12381_g2_signature_aggregate
1820        );
1821        linker_define!(
1822            linker,
1823            CRYPTO_UTILS_KECCAK256_HASH_FUNCTION_NAME,
1824            host_keccak256_hash
1825        );
1826        linker_define!(
1827            linker,
1828            CRYPTO_UTILS_BLAKE2B_256_HASH_FUNCTION_NAME,
1829            host_blake2b_256_hash
1830        );
1831        linker_define!(
1832            linker,
1833            CRYPTO_UTILS_ED25519_VERIFY_FUNCTION_NAME,
1834            host_ed25519_verify
1835        );
1836        linker_define!(
1837            linker,
1838            CRYPTO_UTILS_SECP256K1_ECDSA_VERIFY_FUNCTION_NAME,
1839            host_secp2561k1_ecdsa_verify
1840        );
1841        linker_define!(
1842            linker,
1843            CRYPTO_UTILS_SECP256K1_ECDSA_VERIFY_AND_KEY_RECOVER_FUNCTION_NAME,
1844            host_secp2561k1_ecdsa_verify_and_key_recover
1845        );
1846        linker_define!(
1847            linker,
1848            CRYPTO_UTILS_SECP256K1_ECDSA_VERIFY_AND_KEY_RECOVER_UNCOMPRESSED_FUNCTION_NAME,
1849            host_secp2561k1_ecdsa_verify_and_key_recover_uncompressed
1850        );
1851
1852        #[cfg(feature = "radix_engine_tests")]
1853        {
1854            let host_read_memory = Func::wrap(
1855                store.as_context_mut(),
1856                |caller: Caller<'_, HostState>,
1857                 memory_offs: u32,
1858                 data_len: u32|
1859                 -> Result<(), Error> {
1860                    test_host_read_memory(caller, memory_offs, data_len).map_err(Error::host)
1861                },
1862            );
1863            let host_write_memory = Func::wrap(
1864                store.as_context_mut(),
1865                |caller: Caller<'_, HostState>,
1866                 memory_offs: u32,
1867                 data_len: u32|
1868                 -> Result<(), Error> {
1869                    test_host_write_memory(caller, memory_offs, data_len).map_err(Error::host)
1870                },
1871            );
1872            let host_check_memory_is_clean = Func::wrap(
1873                store.as_context_mut(),
1874                |caller: Caller<'_, HostState>| -> Result<u64, Error> {
1875                    test_host_check_memory_is_clean(caller).map_err(Error::host)
1876                },
1877            );
1878            linker_define!(linker, "test_host_read_memory", host_read_memory);
1879            linker_define!(linker, "test_host_write_memory", host_write_memory);
1880            linker_define!(
1881                linker,
1882                "test_host_check_memory_is_clean",
1883                host_check_memory_is_clean
1884            );
1885        }
1886
1887        linker.instantiate(store.as_context_mut(), module)
1888    }
1889
1890    pub fn instantiate(&self) -> Result<WasmiInstance, WasmiInstantiationError> {
1891        let mut store = Store::new(self.module.engine(), WasmiInstanceEnv::new());
1892
1893        let instance = Self::host_funcs_set(&self.module, &mut store)
1894            .map_err(WasmiInstantiationError::PreInstantiationError)?
1895            .ensure_no_start(store.as_context_mut())
1896            .map_err(WasmiInstantiationError::InstantiationError)?;
1897
1898        let memory = match instance.get_export(store.as_context_mut(), EXPORT_MEMORY) {
1899            Some(Extern::Memory(memory)) => memory,
1900            _ => panic!("Failed to find memory export"),
1901        };
1902
1903        Ok(WasmiInstance {
1904            instance,
1905            store,
1906            memory,
1907        })
1908    }
1909
1910    fn instantiate_unchecked(&self) -> WasmiInstance {
1911        self.instantiate().expect("Failed to instantiate")
1912    }
1913}
1914
1915fn read_memory(
1916    store: impl AsContextMut,
1917    memory: Memory,
1918    ptr: u32,
1919    len: u32,
1920) -> Result<Vec<u8>, InvokeError<WasmRuntimeError>> {
1921    let store_ctx = store.as_context();
1922    let data = memory.data(&store_ctx);
1923    let ptr = ptr as usize;
1924    let len = len as usize;
1925
1926    if ptr > data.len() || ptr + len > data.len() {
1927        return Err(InvokeError::SelfError(WasmRuntimeError::MemoryAccessError));
1928    }
1929    Ok(data[ptr..ptr + len].to_vec())
1930}
1931
1932fn write_memory(
1933    mut store: impl AsContextMut,
1934    memory: Memory,
1935    ptr: u32,
1936    data: &[u8],
1937) -> Result<(), InvokeError<WasmRuntimeError>> {
1938    let mut store_ctx = store.as_context_mut();
1939    let mem_data = memory.data(&mut store_ctx);
1940
1941    if ptr as usize > mem_data.len() || ptr as usize + data.len() > mem_data.len() {
1942        return Err(InvokeError::SelfError(WasmRuntimeError::MemoryAccessError));
1943    }
1944
1945    memory
1946        .write(&mut store.as_context_mut(), ptr as usize, data)
1947        .map_err(|_| InvokeError::SelfError(WasmRuntimeError::MemoryAccessError))
1948}
1949
1950fn read_slice(
1951    store: impl AsContextMut,
1952    memory: Memory,
1953    v: Slice,
1954) -> Result<Vec<u8>, InvokeError<WasmRuntimeError>> {
1955    let ptr = v.ptr();
1956    let len = v.len();
1957
1958    read_memory(store, memory, ptr, len)
1959}
1960
1961impl WasmiInstance {
1962    fn get_export_func(&mut self, name: &str) -> Result<Func, InvokeError<WasmRuntimeError>> {
1963        self.instance
1964            .get_export(self.store.as_context_mut(), name)
1965            .and_then(Extern::into_func)
1966            .ok_or_else(|| {
1967                InvokeError::SelfError(WasmRuntimeError::UnknownExport(name.to_string()))
1968            })
1969    }
1970}
1971
1972impl HostError for InvokeError<WasmRuntimeError> {}
1973
1974impl From<Error> for InvokeError<WasmRuntimeError> {
1975    fn from(err: Error) -> Self {
1976        let e_str = format!("{:?}", err);
1977        if let Some(invoke_err) = err.downcast::<InvokeError<WasmRuntimeError>>() {
1978            invoke_err.clone()
1979        } else {
1980            InvokeError::SelfError(WasmRuntimeError::ExecutionError(e_str))
1981        }
1982    }
1983}
1984
1985impl WasmInstance for WasmiInstance {
1986    fn invoke_export<'r>(
1987        &mut self,
1988        func_name: &str,
1989        args: Vec<Buffer>,
1990        runtime: &mut Box<dyn WasmRuntime + 'r>,
1991    ) -> Result<Vec<u8>, InvokeError<WasmRuntimeError>> {
1992        {
1993            // set up runtime pointer
1994            // Using triple casting is to workaround this error message:
1995            // error[E0521]: borrowed data escapes outside of associated function
1996            //  `runtime` escapes the associated function body here argument requires that `'r` must outlive `'static`
1997            self.store
1998                .data_mut()
1999                .runtime_ptr
2000                .write(runtime as *mut _ as usize as *mut _);
2001        }
2002
2003        let func = self.get_export_func(func_name).unwrap();
2004        let input: Vec<Val> = args
2005            .into_iter()
2006            .map(|buffer| Val::I64(buffer.as_i64()))
2007            .collect();
2008        let mut ret = [Val::I64(0)];
2009
2010        let call_result = func
2011            .call(self.store.as_context_mut(), &input, &mut ret)
2012            .map_err(|e| {
2013                let err: InvokeError<WasmRuntimeError> = e.into();
2014                err
2015            });
2016
2017        let result = match call_result {
2018            Ok(_) => match ret[0] {
2019                Val::I64(ret) => read_slice(
2020                    self.store.as_context_mut(),
2021                    self.memory,
2022                    Slice::transmute_i64(ret),
2023                ),
2024                _ => Err(InvokeError::SelfError(WasmRuntimeError::InvalidWasmPointer)),
2025            },
2026            Err(err) => Err(err),
2027        };
2028
2029        #[cfg(feature = "coverage")]
2030        if let Ok(dump_coverage) = self.get_export_func("dump_coverage") {
2031            if let Ok(blueprint_buffer) = runtime.actor_get_blueprint_name() {
2032                let blueprint_name =
2033                    String::from_utf8(runtime.buffer_consume(blueprint_buffer.id()).unwrap())
2034                        .unwrap();
2035
2036                let mut ret = [Val::I64(0)];
2037                dump_coverage
2038                    .call(self.store.as_context_mut(), &[], &mut ret)
2039                    .unwrap();
2040                let coverage_data = match ret[0] {
2041                    Val::I64(ret) => read_slice(
2042                        self.store.as_context_mut(),
2043                        self.memory,
2044                        Slice::transmute_i64(ret),
2045                    ),
2046                    _ => Err(InvokeError::SelfError(WasmRuntimeError::InvalidWasmPointer)),
2047                }
2048                .unwrap();
2049                save_coverage_data(&blueprint_name, &coverage_data);
2050            }
2051        }
2052
2053        result
2054    }
2055}
2056
2057#[derive(Debug, Clone)]
2058pub struct WasmiEngineOptions {
2059    max_cache_size: usize,
2060}
2061
2062pub struct WasmiEngine {
2063    // This flag disables cache in wasm_instrumenter/wasmi to prevent non-determinism when fuzzing
2064    #[cfg(all(not(feature = "fuzzing"), not(feature = "moka")))]
2065    modules_cache: RefCell<lru::LruCache<CodeHash, Arc<WasmiModule>>>,
2066    #[cfg(all(not(feature = "fuzzing"), feature = "moka"))]
2067    modules_cache: moka::sync::Cache<CodeHash, Arc<WasmiModule>>,
2068    #[cfg(feature = "fuzzing")]
2069    #[allow(dead_code)]
2070    modules_cache: usize,
2071}
2072
2073impl Default for WasmiEngine {
2074    fn default() -> Self {
2075        Self::new(WasmiEngineOptions {
2076            max_cache_size: WASM_ENGINE_CACHE_SIZE,
2077        })
2078    }
2079}
2080
2081impl WasmiEngine {
2082    pub fn new(options: WasmiEngineOptions) -> Self {
2083        #[cfg(all(not(feature = "fuzzing"), not(feature = "moka")))]
2084        let modules_cache = RefCell::new(lru::LruCache::new(
2085            sbor::rust::num::NonZeroUsize::new(options.max_cache_size).unwrap(),
2086        ));
2087        #[cfg(all(not(feature = "fuzzing"), feature = "moka"))]
2088        let modules_cache = moka::sync::Cache::builder()
2089            .weigher(|_key: &CodeHash, _value: &Arc<WasmiModule>| -> u32 {
2090                // No sophisticated weighing mechanism, just keep a fixed size cache
2091                1u32
2092            })
2093            .max_capacity(options.max_cache_size as u64)
2094            .build();
2095        #[cfg(feature = "fuzzing")]
2096        let modules_cache = options.max_cache_size;
2097
2098        Self { modules_cache }
2099    }
2100}
2101
2102impl WasmEngine for WasmiEngine {
2103    type WasmInstance = WasmiInstance;
2104
2105    #[allow(unused_variables)]
2106    fn instantiate(&self, code_hash: CodeHash, instrumented_code: &[u8]) -> WasmiInstance {
2107        #[cfg(not(feature = "fuzzing"))]
2108        {
2109            #[cfg(not(feature = "moka"))]
2110            {
2111                if let Some(cached_module) = self.modules_cache.borrow_mut().get(&code_hash) {
2112                    return cached_module.instantiate_unchecked();
2113                }
2114            }
2115            #[cfg(feature = "moka")]
2116            if let Some(cached_module) = self.modules_cache.get(&code_hash) {
2117                return cached_module.as_ref().instantiate_unchecked();
2118            }
2119        }
2120
2121        let module = WasmiModule::new(instrumented_code).expect("Failed to compile module");
2122        let instance = module.instantiate_unchecked();
2123
2124        #[cfg(not(feature = "fuzzing"))]
2125        {
2126            #[cfg(not(feature = "moka"))]
2127            self.modules_cache
2128                .borrow_mut()
2129                .put(code_hash, Arc::new(module));
2130            #[cfg(feature = "moka")]
2131            self.modules_cache.insert(code_hash, Arc::new(module));
2132        }
2133
2134        instance
2135    }
2136}
2137
2138// Below tests verify WASM "mutable-global" feature, which allows importing/exporting mutable globals.
2139// more details:
2140// - https://github.com/WebAssembly/mutable-global/blob/master/proposals/mutable-global/Overview.md
2141
2142// NOTE!
2143//  We test only WASM code, because Rust currently does not use the WASM "global" construct for globals
2144//  (it places them into the linear memory instead).
2145//  more details:
2146//  - https://github.com/rust-lang/rust/issues/60825
2147//  - https://github.com/rust-lang/rust/issues/65987
2148#[cfg(test)]
2149mod tests {
2150    use super::*;
2151    use wasmi::Global;
2152
2153    static MODULE_MUTABLE_GLOBALS: &str = r#"
2154            (module
2155                ;; below line is invalid if feature 'Import/Export mutable globals' is disabled
2156                ;; see: https://github.com/WebAssembly/mutable-global/blob/master/proposals/mutable-global/Overview.md
2157                (global $g (import "env" "global_mutable_value") (mut i32))
2158
2159                ;; Simple function that always returns `0`
2160                (func $increase_global_value (param $step i32) (result i32)
2161
2162                    (global.set $g
2163                        (i32.add
2164                            (global.get $g)
2165                            (local.get $step)))
2166
2167                    (i32.const 0)
2168                )
2169                (memory $0 1)
2170                (export "memory" (memory $0))
2171                (export "increase_global_value" (func $increase_global_value))
2172            )
2173        "#;
2174
2175    pub fn run_module_with_mutable_global(
2176        module: &Module,
2177        mut store: StoreContextMut<WasmiInstanceEnv>,
2178        func_name: &str,
2179        global_name: &str,
2180        global_value: &Global,
2181        step: i32,
2182    ) {
2183        let mut linker = <Linker<HostState>>::new(module.engine());
2184        linker_define!(linker, global_name, *global_value);
2185
2186        let instance = linker
2187            .instantiate(store.as_context_mut(), module)
2188            .unwrap()
2189            .ensure_no_start(store.as_context_mut())
2190            .unwrap();
2191
2192        let func = instance
2193            .get_export(store.as_context_mut(), func_name)
2194            .and_then(Extern::into_func)
2195            .unwrap();
2196
2197        let input = [Val::I32(step)];
2198        let mut ret = [Val::I32(0)];
2199
2200        let _ = func.call(store.as_context_mut(), &input, &mut ret);
2201    }
2202
2203    #[test]
2204    fn test_wasm_non_mvp_mutable_globals_execute_code() {
2205        // wat2wasm has "mutable-globals" enabled by default
2206        let code = wat::parse_str(MODULE_MUTABLE_GLOBALS).unwrap();
2207
2208        let wasmi_module = WasmiModule::new(&code).unwrap();
2209        let module = wasmi_module.module;
2210
2211        let mut store = Store::new(module.engine(), WasmiInstanceEnv::new());
2212
2213        // Value of this Global shall be updated by the below WASM module calls
2214        let global_value = Global::new(store.as_context_mut(), Val::I32(100), Mutability::Var);
2215
2216        run_module_with_mutable_global(
2217            &module,
2218            store.as_context_mut(),
2219            "increase_global_value",
2220            "global_mutable_value",
2221            &global_value,
2222            1000,
2223        );
2224        let updated_value = global_value.get(store.as_context());
2225        let val = match updated_value {
2226            Val::I32(val) => val,
2227            _ => panic!("Unexpected return value type"),
2228        };
2229        assert_eq!(val, 1100);
2230
2231        run_module_with_mutable_global(
2232            &module,
2233            store.as_context_mut(),
2234            "increase_global_value",
2235            "global_mutable_value",
2236            &global_value,
2237            10000,
2238        );
2239        let updated_value = global_value.get(store.as_context());
2240        let val = match updated_value {
2241            Val::I32(val) => val,
2242            _ => panic!("Unexpected return value type"),
2243        };
2244        assert_eq!(val, 11100);
2245    }
2246}