Felt::new(0) / zero-valued felt in storage generates unsupported f32.const 0.0 WASM instruction
- 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
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