0xPolygonMiden / compiler

Compiler from MidenIR to Miden Assembly
MIT License
63 stars 20 forks source link

Failed to build a Wasm component from the Wasm core module with "non-component" imports #334

Open greenhat opened 2 hours ago

greenhat commented 2 hours ago

TLDR; Using core Wasm module imports for our intrinsics and Miden SDK functions is not playing well with the Wasm component model.

What

When building a Wasm component from a Wasm core module compiled from the basic-wallet with Rust SDK example, the build fails with the following error:

Caused by:
    0: module was not valid
    1: module requires an import interface named `miden::account`

Why

The reason for this error is that the Wasm core module contains imports that wit-component(used by cargo-component to build the Wasm component) fails to recognize as component imports, i.e. imports that are defined in the WIT file. In this case, it's miden::account::add_asset tx kernel function from the Miden SDK. Effectively, all our intrinsics and Miden SDK functions are triggering this error.

This happens at https://github.com/bytecodealliance/wasm-tools/blob/51ade657f6d6874b1bdfb87a47299dbe7e61d5c2/crates/wit-component/src/validation.rs#L411-L491, where the module name of the core module import is expected to be found in the interface imports in the WIT file.

How to reproduce

In https://github.com/0xPolygonMiden/compiler/pull/329 branch run:

RUST_LOG=debug cargo test rust_sdk_basic

To check out the Wasm core module, use wasm-tools print PATH_TO_CORE_WASM with the path reported in logs at componentizing WebAssembly module ...

How to fix

The most promising approach IMO would be to not use Wasm core module imports for our intrinsics and Miden SDK functions. The reason why wit-component treats them as errors is fair, and I think it'd be difficult if at all possible to alter that behavior in the upstream.

So instead of defining our Miden SDK functions and intrinsics as extern https://github.com/0xPolygonMiden/compiler/blob/a876d8b134bc118e1944b5a72747cf2c13a235a1/sdk/base-sys/src/bindings/tx/externs.rs#L5-L13 we could define them as functions with unreachable!() bodies and recognize them by function names and signatures in the frontend:

#[inline(never)]
#[no_mangle]
fn miden_account_add_asset(_: Felt, _: Felt, _: Felt, _: Felt, ptr: *mut CoreAsset) {
    unreachable!()
}

Although, #[inline(never)] is only a hint to the compiler, with a side effect in the body we should be safe from inlining.

greenhat commented 2 hours ago

@bitwalker That's a blocker for me. Please check it out ASAP.