Debugging Guide
Miden supports interactive DAP debugging.
Use assertions to check values during execution and miden::println! markers to trace paths
when running with a debugger host that renders them.
Printing Debug Markers
Use a literal or string expression to mark the path taken through a contract:
miden::println!("entered withdraw");
if balance == felt!(0) {
miden::println!("balance is empty");
}
miden::println! accepts string literals and expressions. It also supports Rust-style formatting
arguments, such as miden::println!("balance: {}", balance). Formatted output requires
extern crate alloc and a configured global allocator; literal markers don't allocate.
With SDK 0.14.0, miden::println! emits a readonly::miden_debug::println event.
The normal Rust client and MockChain transaction executors ignore that event. Attaching a DAP
client preserves the transaction host's handlers, so the live DAP connection alone does not
make these messages appear.
The miden-debug local execution and replay host handles these events. For a transaction,
record a DAP session and replay it
to inspect the markers in the debugger's output. MASM's
miden::core::debug printers use separate events
that the normal transaction executor prints by default.
Using assert_eq
The assert_eq function compares two Felt values and fails if they differ:
use miden::*;
// Check if a value equals an expected value
assert_eq(actual_value, expected_value);
assert_eq is a function, not a macro. Use assert_eq(a, b) without the exclamation mark.
Narrowing Down Failures
Execution errors include source diagnostics when debug information is available. Combine those diagnostics with markers and assertions to isolate the failing operation:
- Place
miden::println!markers before and after the code you suspect. - Add an
assert_eqfor the value the code expects. - Run with a debugger host that renders Rust markers and inspect the last marker and any assertion failure.
Example
pub fn withdraw(&mut self, depositor: AccountId, amount: Felt) {
let balance = self.get_balance(depositor);
miden::println!("loaded balance");
// Check the assumption used by the code below.
assert_eq(balance, felt!(1000));
let new_balance = balance - amount;
self.balances.set(depositor, new_balance);
miden::println!("updated balance");
}
Move the markers and assertion through the function to narrow down which assumption or operation fails.
Limitations
assert_eqonly works withFeltvaluesmiden::println!emits an event and adds execution work even when the host ignores it; remove debug-only calls from release code- Remove only diagnostic assertions; keep assertions that enforce contract invariants