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