0xMiden / 0xMiden/compiler

Felt::new(0) / zero-valued felt in storage generates unsupported f32.const 0.0 WASM instruction

Open
#1,240 3 comments 0 reactions 1 assignee Claimed by @mooori View on GitHub
Dominant language
Rust
Stars
115
Forks
84
Avg merge
1d 8h
Merged PRs (30d)
15

Description

### Packages versions

miden-client: 0.15.2
miden-protocol: 0.14.4
miden-vm: 0.25.x (via miden-stateful-hasher 0.25.1)
0xMiden/compiler: commit 6d01a0a (next branch)

### Bug description

### Environment
- Compiler: `0xMiden/compiler`, commit `6d01a0a105f2fd7643236ea1b846b9add6b9611f` (`next` branch ancestor)
- miden-client: v0.15.2
- Contract: weather prediction market ([pplmaverick/miden-weather-market](https://github.com/pplmaverick/miden-weather-market))

### Bug description

When a storage field can hold a zero-valued felt — either as a default/unset
state or as an explicit `Felt::new(0)` — the Miden compiler backend emits an
`f32.const 0.0` WASM instruction, which the Miden VM does not support. There
is no compile-time error; the failure surfaces only at runtime.

The root cause appears to be a type-inference path where the integer literal
`0` (or any expression reducing to zero) is lowered through the WASM codegen
as a float `f32.const 0.0` rather than a felt/u64 constant.

### Affected code pattern

```rust
// #![no_std] contract using miden SDK

const STATUS_OPEN: u64 = 1; // ← must be non-zero
const STATUS_SETTLED: u64 = 2; // ← must be non-zero
// Starting from 0 (STATUS_UNSET: u64 = 0) would trigger f32.const 0.0

#[component_storage]
struct WeatherMarketStorage {
// Fields that may naturally hold zero-felt as "unset" are affected:
#[storage(description = "non-zero once initialize() has been called")]
initialized: StorageValue, // zero-as-false pattern broken

#[storage(description = "bet_commitment => non-zero if winnings claimed")]
claimed: StorageMap, // zero-as-absent pattern broken
}

// Helper used throughout to construct felts:
fn felt(v: u64) -> Felt {
Felt::new(v).expect("value is a valid field element")
}
// Calling felt(0) anywhere in storage logic reproduces the issue.
```

### Workaround

Avoid zero entirely in storage-facing code. Use non-zero sentinel values for
all flags, enums, and map presence markers:

```rust
const STATUS_OPEN: u64 = 1; // not 0
const STATUS_SETTLED: u64 = 2; // not 1/0
// For claimed map: write felt(1) to mark "claimed"; treat absence-of-key as unclaimed.
```

Reference in our project:
[`README.md` lines 228–229](https://github.com/pplmaverick/miden-weather-market/blob/main/README.md#L228) |
[`ARCHITECTURE.md` line 50](https://github.com/pplmaverick/miden-weather-market/blob/main/ARCHITECTURE.md#L50)

### Why this matters

Zero-as-default is idiomatic in both Rust and EVM/Solidity. Contract developers
migrating patterns from other ecosystems will naturally reach for zero as an
unset/false sentinel, hit this at runtime with no actionable error message, and
have no path to diagnose it without knowing the WASM codegen detail. A
compile-time warning or error when a zero felt is used in storage context would
eliminate this class of bug entirely.

### How can this be reproduced?

1. Create a Miden account component contract with a storage field that may hold a zero-valued felt (e.g. a boolean flag or a map presence marker):

```rust
#[component_storage]
struct Storage {
#[storage(description = "non-zero once initialized")]
initialized: StorageValue, // zero as "unset" state
}
```

2. In any component method, write or read a zero felt value using `Felt::new(0)` or the equivalent zero literal.

3. Compile the contract with the Miden compiler (`next` branch).

4. Deploy and invoke the method via miden-client.

**Expected:** Normal execution.
**Actual:** Runtime failure — the compiler emits an `f32.const 0.0` WASM instruction for the zero felt value, which the Miden VM does not support.

### Relevant log output

```shell
No terminal log captured at the time — the issue was identified through
runtime failure and documented in project README/ARCHITECTURE as a workaround
pattern. See linked references in Bug description above.
```

Contributor guide

Open the contributing guide

Research direction

The issue is in the compiler's WASM codegen where integer literal 0 is lowered to f32.const 0.0. Start by examining the type-inference and lowering logic for felt/u64 constants, particularly around storage fields. Look for the code that handles Felt::new(0) or zero literals. The fix likely involves ensuring zero-valued felts are emitted as u64/i64 constants, not floats. Test by compiling a contract with a zero-felt storage field and checking the generated WASM instructions.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust, wasm
Domain
compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.