0xMiden / 0xMiden/miden-vm

Wrong masm file shown on certain kinds of errors (missing import, possibly other)

未关闭
#2,762 3 条评论 1 个 reaction 已指派 1 人 已被 @bitwalker 认领 在 GitHub 查看
assembly
主要语言
Rust
星标
772
派生
352
平均合并
1 天 7 小时
30 天内合并 PR
84

描述

### Packages versions

miden-assembly: 0.20.6

### Bug description

Issue: When compiling library code with missing imports, MASM file name and contents will be replaced with `account_id.masm` and it's contents respectively.

Example: Code missing `miden::protocol::active_account` import while calling `exec.active_account::get_item` will yield:
```
Error: Failed to compile lp_local library: x undefined symbol reference
,-[/Users/mieszkomanijak/Documents/repos/miden/c-prod_pools/target/release/build/miden-protocol-f93a66620a2cffdd/out/asm/shared_modules/account_id.masm:68:11]
67 | #! Inputs: [acct_id_prefix]
68 | #! Outputs: [is_non_fungible_faucet]
: ^^^^^^^^^^^^|^^^^^^^^^^^
: `-- this symbol path could not be resolved
69 | #!
`----
help: maybe you are missing an import?
```

### How can this be reproduced?

Offending code from `asm/accounts/lp_local.masm` trying to call `exec.active_account::get_item` in l 88

```
use miden::core::math::u64
use miden::protocol::native_account
#use miden::protocol::active_account
use miden::core::sys

use zoro::math
use zoro::storage_utils

const MINIMUM_LIQUIDITY = 100

### MEMORY LOCATIONS
const DYNAMIC_PROC_ADDR = 4

const USER_ACCOUNT_ID_WORD = 20
const USER_ACCOUNT_ID_PREFIX = 20
const USER_ACCOUNT_ID_SUFFIX = 21

### ERROR CODES
const ERR_ZERO_ADDRESS = "Zero address"

### STORAGE SLOTS
const USER_DEPOSITS_MAPPING_SLOT = word("zoro::lp_local::user_deposits_mapping")
const RESERVE_SLOT = word("zoro::lp_local::reserve")
const TOTAL_SUPPLY_SLOT = word("zoro::lp_local::total_supply")
#################
#! Computes the LP amount out for a deposit of amount_0 and amount_1.
#! For initial deposit (the total supply is 0), it subracts the minimum liquidity.
#! Inputs: [total_supply, amount_0, amount_1, reserve_0, reserve_1]
#! Outputs: [lp_amount_out]
@locals(5)
pub proc get_lp_amount_out(total_supply: felt, amount_0: felt, amount_1: felt, reserve_0: felt, reserve_1: felt) -> felt
# loc.0: total_supply
# loc.1: amount_0
# loc.2: amount_1
# loc.3: reserve_0
# loc.4: reserve_1
loc_store.0 loc_store.1 loc_store.2 loc_store.3 loc_store.4
# => []
### if total_supply == 0
loc_load.0 eq.0
if.true
### initial deposit: - MINIMUM_LIQUIDITY
loc_load.1 loc_load.2 mul exec.math::sqrt
# => [lp_amount]
push.MINIMUM_LIQUIDITY exec.math::safe_sub
# => [lp_amount_out]
### return lp_amount_out
else
### subsequent deposits: min(lp_amount_0, lp_amount_1)
### lp_amount_0 = amount_0 * total_supply / reserve_0
loc_load.1 u32split loc_load.0 u32split exec.u64::wrapping_mul loc_load.3 u32split exec.u64::div
# => [lp_amount_0_high, lp_amount_0_low]
loc_load.2 u32split loc_load.0 u32split exec.u64::wrapping_mul loc_load.4 u32split exec.u64::div
# => [lp_amount_1_high, lp_amount_1_low, lp_amount_0_high, lp_amount_0_low]
exec.u64::min
# => [lp_amount_out_high, lp_amount_out_low]
exec.math::safe_cast_u64_into_felt
# => [lp_amount_out]
### return lp_amount_out
end

exec.sys::truncate_stack
end

proc assert_non_zero_address#(suffix: felt, prefix: felt)
neq.0 swap.1 neq.0
# => [is_suffix_non_zero, is_prefix_non_zero]
or assert.err=ERR_ZERO_ADDRESS
end
proc get_current_user_deposit_key#() -> Word
mem_load.USER_ACCOUNT_ID_SUFFIX mem_load.USER_ACCOUNT_ID_PREFIX
exec.assert_non_zero_address
mem_load.USER_ACCOUNT_ID_SUFFIX mem_load.USER_ACCOUNT_ID_PREFIX
# => [USER_DEPOSIT_KEY]
exec.get_user_deposit_key
exec.sys::truncate_stack
end

proc get_user_deposit_key#(prefix: felt, suffix: felt) -> Word
push.0.0 movup.3 movup.2
# => [prefix, suffix, 0 , 0 ] == [KEY]
end

pub proc total_supply#() -> felt
push.TOTAL_SUPPLY_SLOT[0..2] exec.active_account::get_item
end

pub proc get_reserve#() -> (felt, felt)
push.RESERVE_SLOT[0..2] exec.active_account::get_item
end

proc set_reserve#(reserve_0: felt, reserve_1: felt)
### amount validation vs vault
push.RESERVE_SLOT[0..2] exec.native_account::set_item
dropw
end

@locals(2)
proc add_to_reserve#(amount_0: felt, amount_1: felt)
# loc.0: amount_0
# loc.1: amount_1
loc_store.0 loc_store.1
# => []
exec.get_reserve
# => [reserve_0, reserve_1]
loc_load.0 exec.math::safe_add
# => [new_reserve_0, reserve_1]
swap
loc_load.1 exec.math::safe_add
# => [new_reserve_1, new_reserve_0]
swap
# => [new_reserve_0, new_reserve_1]
exec.set_reserve
end

@locals(2)
proc sub_from_reserve#(amount_0: felt, amount_1: felt)
# loc.0: amount_0
# loc.1: amount_1
loc_store.0 loc_store.1
# => []
exec.get_reserve
# => [reserve_0, reserve_1]
loc_load.0 exec.math::safe_sub
# => [new_reserve_0, reserve_1]
swap
loc_load.1 exec.math::safe_sub
# => [new_reserve_1, new_reserve_0]
swap
# => [new_reserve_0, new_reserve_1]
exec.set_reserve
end

@locals(3)
proc mint#(amount: felt, beneficiary_prefix: felt, beneficiary_suffix: felt)
# loc.0: amount
# loc.1: beneficiary_prefix
# loc.2: beneficiary_suffix
loc_store.0 loc_store.1 loc_store.2
# => []
### add to mapping USER_DEPOSITS_MAPPING_SLOT
loc_load.0
loc_load.2 loc_load.1 exec.get_user_deposit_key
# => [USER_DEPOSIT_KEY, amount]
push.USER_DEPOSITS_MAPPING_SLOT[0..2]
# => [slot_id_prefix, slot_id_suffix, USER_DEPOSIT_KEY, amount]
exec.storage_utils::add_to_map_item
drop
### updating total supply
loc_load.0 push.TOTAL_SUPPLY_SLOT[0..2] exec.storage_utils::add_to_storage_item
drop
end

#! add new deposit: receive asset, update deposit mapping
#!
#! Inputs: [ASSET0, ASSET1, user_id_prefix, user_id_suffix]
#! Outputs: [share_amount_out]
#!
@locals(9)
pub proc deposit
# loc.0: ASSET0
# loc.4: ASSET1
# loc.5: lp_amount_out
loc_storew_be.0 dropw loc_storew_be.4 dropw mem_store.USER_ACCOUNT_ID_PREFIX mem_store.USER_ACCOUNT_ID_SUFFIX

### get_lp_amount_out (total_supply: felt, amount_0: felt, amount_1: felt, reserve_0: felt, reserve_1: felt)
exec.get_reserve
# => [reserve_0, reserve_1]
loc_load.7 loc_load.3
# => [amount_0, amount_1, reserve_0, reserve_1]
exec.total_supply
# => [total_supply, amount_0, amount_1, reserve_0, reserve_1]

exec.get_lp_amount_out
# => [lp_amount_out]
loc_store.5
### check if initial deposit
exec.total_supply eq.0
if.true
### burn minimum liquidity
push.0.0 push.MINIMUM_LIQUIDITY
exec.mint
end

### mint to user
loc_load.5
mem_load.USER_ACCOUNT_ID_SUFFIX mem_load.USER_ACCOUNT_ID_PREFIX
# => [user_id_prefix, user_id_suffix, lp_amount_out]
exec.mint

### receive assets
### reserve needs to be updated
#padw padw padw loc_loadw_be.0 exec.receive_asset
#padw padw padw loc_loadw_be.4 exec.receive_asset
padw loc_loadw_be.0 exec.native_account::add_asset dropw
padw loc_loadw_be.4 exec.native_account::add_asset dropw
## make sure asset order correct
loc_load.7 loc_load.3
# => [amount_0, amount_1]
exec.add_to_reserve

end
```
Compiled with
```
pub fn get_lp_local_library() -> Result {
let math_library = get_math_library()?;
let storage_utils_library = get_storage_utils_library()?;
let manifest_dir = env!("CARGO_MANIFEST_DIR");
let path: PathBuf = [manifest_dir, "asm", "accounts", "lp_local.masm"]
.iter()
.collect();
let source = fs::read_to_string(&path)?;
let assembler = TransactionKernel::assembler()
.with_warnings_as_errors(true)
.with_static_library(math_library)
.map_err(|e| anyhow!("Failed to add math library to assembler: {e:?}"))?
.with_static_library(storage_utils_library)
.map_err(|e| anyhow!("Failed to add storage_utils library to assembler: {e:?}"))?;
create_library(assembler, "zoro::lp_local", &source)
.map_err(|e| anyhow!("Failed to compile lp_local library: {e:?}"))
}

pub fn get_math_library() -> Result {
let manifest_dir = env!("CARGO_MANIFEST_DIR");
let path: PathBuf = [manifest_dir, "asm", "accounts", "math.masm"]
.iter()
.collect();
let source = fs::read_to_string(&path)?;
let assembler = TransactionKernel::assembler().with_warnings_as_errors(true);
create_library(assembler, "zoro::math", &source)
.map_err(|e| anyhow!("Failed to compile math library: {e:?}"))
}

pub fn get_storage_utils_library() -> Result {
let math_library = get_math_library()?;
let manifest_dir = env!("CARGO_MANIFEST_DIR");
let path: PathBuf = [manifest_dir, "asm", "accounts", "storage_utils.masm"]
.iter()
.collect();
let source = fs::read_to_string(&path)?;
let assembler = TransactionKernel::assembler()
.with_warnings_as_errors(true)
.with_static_library(math_library)
.unwrap_or_else(|e| panic!("Failed to add math library to assembler: {e:?}"));
create_library(assembler, "zoro::storage_utils", &source)
.map_err(|e| anyhow!("Failed to compile storage_utils library: {e:?}"))
}

pub fn create_library(
assembler: Assembler,
library_path: &str,
source_code: &str,
) -> Result> {
let source_manager = Arc::new(DefaultSourceManager::default());
// println!("parsing library: {:?}", library_path);
let module = Module::parser(ModuleKind::Library).parse_str(
AssemblyPath::new(library_path),
source_code,
source_manager.clone(),
)?;
// println!("Module: {:?}", module);
let library = assembler.clone().assemble_library([module])?;
Ok(library)
}

```

### Relevant log output

```shell
Error: Failed to compile lp_local library: x undefined symbol reference
,-[/Users/mieszkomanijak/Documents/repos/miden/c-prod_pools/target/release/build/miden-protocol-f93a66620a2cffdd/out/asm/shared_modules/account_id.masm:68:11]
67 | #! Inputs: [acct_id_prefix]
68 | #! Outputs: [is_non_fungible_faucet]
: ^^^^^^^^^^^^|^^^^^^^^^^^
: `-- this symbol path could not be resolved
69 | #!
`----
help: maybe you are missing an import?
```

贡献指南

打开贡献指南

调研方向

The error occurs in the assembler when a missing import leads to a wrong file being shown in the error message. Look at the error reporting code in the assembler module, likely in miden-assembly crate. Find where file names are resolved and substituted. The test case is in the issue body: compile a library with a missing import (like active_account) and see how the error path is generated. The fix should ensure the correct source file name is displayed.

由索引模型根据 Issue 内容生成。

评估

技术栈
rust
领域
compilers
Issue 类型
缺陷
难度
3/5
预计耗时
1-2 天
活跃度
停滞
描述清晰度
描述清楚
新手友好度
45/100

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。