dApp Docs/开发排错大全
Development reference. Not independently verified for production.

MSG Chain 开发排错大全 — 终极调试百科全书

数据来源:MSG Chain 代码库核实

主网状态: No-Go — 当前 MSGChain 主网裁决为 No-Go,以下内容反映代码实际状态,不代表生产可用。


目录

  1. 排错总览
  2. 错误码大全
  3. 环境搭建问题
  4. 节点运行问题
  5. 合约编译问题
  6. 合约部署问题
  7. 合约交互问题
  8. 前端集成问题
  9. Agent API问题
  10. DAO与治理问题
  11. Gas与费用问题
  12. Dilithium-5相关问题
  13. BadgerDB存储问题
  14. 常见错误模式与模式修复
  15. 调试工具与脚本
  16. 社区求助指南

一、排错总览

1.1 排错哲学

MSG Chain 基于 Cosmos SDK + CosmWasm + Dilithium-5 技术栈,不同于 Ethereum (Solidity + EVM) 或标准 Cosmos (IAVL + Secp256k1)。排错时需要理解以下核心差异:

维度 Ethereum 标准 Cosmos MSG Chain
智能合约 Solidity → EVM CosmWasm → WASM CosmWasm → WASM
签名算法 ECDSA (secp256k1) Ed25519 / secp256k1 Dilithium-5 (后量子)
状态存储 Patricia Trie + LevelDB IAVL + LevelDB BadgerDB (LSM-Tree)
共识 PoS (Gasper) Tendermint BFT Round-Robin + DAR
Gas模型 EIP-1559 (动态) 固定费率 固定费率三档

排错优先级金字塔:

1. 检查链配置 (Chain ID, Bech32, Gas价格)
2. 检查网络连通性 (RPC/REST端口)
3. 检查账户余额 (umsg足够吗?)
4. 检查交易日志 (raw_log是金矿)
5. 检查合约消息格式 (JSON大小写敏感)
6. 检查链状态 (节点是否同步)
7. 检查版本兼容性 (Go/Rust/CosmWasm版本)

1.2 如何解读错误信息

MSG Chain 的错误分为三层:

第一层: HTTP/RPC 层
  Example: curl http://localhost:26657/status
  错误: connection refused → 节点未启动
  解决: ./build/msgd start

第二层: 交易广播层
  Example: ./build/msgd tx wasm store contract.wasm
  错误: code: 4, "insufficient funds" → 余额不足
  解决: 检查账户余额并充值

第三层: 合约执行层
  Example: 合约 execute 失败
  错误: "ContractError::Unauthorized" → 调用者无权
  解决: 检查谁是合约 admin/owner

1.3 快速诊断命令

# 诊断脚本 — 快速定位问题
#!/bin/bash
echo "=== MSG Chain 快速诊断 ==="

# 1. 检查节点是否运行
if curl -s http://localhost:26657/status > /dev/null 2>&1; then
  HEIGHT=$(curl -s http://localhost:26657/status | jq -r '.result.sync_info.latest_block_height')
  CATCHING_UP=$(curl -s http://localhost:26657/status | jq -r '.result.sync_info.catching_up')
  echo "✅ 节点运行中 | 高度: $HEIGHT | 同步: $CATCHING_UP"
else
  echo "❌ 节点未运行 — 执行: ./build/msgd start"
fi

# 2. 检查REST API
if curl -s http://localhost:1317/cosmos/base/tendermint/v1beta1/node_info > /dev/null 2>&1; then
  echo "✅ REST API 正常"
else
  echo "❌ REST API 不可达 — 检查 app.toml [api] 配置"
fi

# 3. 检查chain-id
CHAIN_ID=$(curl -s http://localhost:26657/status | jq -r '.result.node_info.network' 2>/dev/null)
if [ "$CHAIN_ID" = "msg-chain-1" ]; then
  echo "✅ Chain ID 正确: $CHAIN_ID"
else
  echo "❌ Chain ID: $CHAIN_ID (应为 msg-chain-1)"
fi

# 4. 检查账户余额
if [ -n "$1" ]; then
  BALANCE=$(./build/msgd query bank balances "$1" --node tcp://localhost:26657 -o json 2>/dev/null | jq -r '.balances[] | select(.denom=="umsg") | .amount')
  echo "📊 账户 $1 余额: $BALANCE umsg"
fi

1.4 知道何时需要重启

重启往往不是答案,但以下情况确实需要:
  ☐ 修改了 config.toml / app.toml
  ☐ 链在 upgrade height 卡住
  ☐ 出现 BadgerDB "manifest corrupted" 错误
  ☐ 节点 OOM (内存溢出) 后
  ☐ 端口冲突解决后

不需要重启的情况:
  ☒ 单笔交易失败
  ☒ 合约执行报错
  ☒ 查询超时
  ☒ Keplr 连接问题

二、错误码大全

2.1 全局错误码表

代码 名称 描述 中文解释 常见原因 解决方案
0 SUCCESS_OK Success 成功 — —
1 AGENT_STUB_SUCCESS Success (stub) 成功(Stub响应) 调用了未完全实现的端点 检查响应头 X-MSG-Stub=true,功能可能受限
2 STUB_NOT_YET_IMPLEMENTED Feature not yet implemented 功能尚未实现 端点处于规划态 查阅文档确认该功能是否已发布;等待未来版本
3 UNAUTHORIZED Unauthorized 未授权 API Key 缺失/无效;签名者不是合约 owner;缺少权限 检查 API Key;确认使用的账户有权限
4 INSUFFICIENT_FUNDS Insufficient funds 余额不足 账户 umsg 不足以支付交易费 + 转账金额 查询余额 msgd query bank balances <addr>;向账户转账
5 CONTRACT_EXECUTION_FAILED Contract execution failed 合约执行失败 合约代码 panicked;消息格式错误;Gas 不足 查看 raw_log 定位具体错误;模拟执行 debug
6 QUERY_TIMEOUT_OR_EMPTY Query timeout or empty 查询超时或返回空 节点不同步;查询键不存在;合约无此查询方法 检查节点同步状态;确认查询消息格式正确
7 INVALID_PARAMETER Invalid parameter 参数无效 JSON 格式错误;字段类型不对;缺少必填字段 对照合约 Schema 检查消息格式
8 DAO_TIMELOCK_NOT_FINISHED DAO timelock period not finished DAO 时间锁未结束 提案通过但未到执行时间 等待 timelock 结束后再执行;查询 get_config 查看 timelock_duration
9 HIGH_VALUE_THRESHOLD_NOT_MET High-value transaction threshold not met 高价值交易门槛未满足 交易金额超过阈值但未满足额外条件 检查宪章中的 max_amount 设置;需要多签或人工审批
10 AGENT_NOT_FOUND Agent not found Agent 未找到 agent_id 未注册;已注销 确认 agent_id 正确;使用 get_agent 查询
11 AGENT_ALREADY_REGISTERED Agent already registered Agent 已注册 agent_id 已被占用 使用不同的 agent_id;先注销旧 Agent
12 CONSTITUTION_VIOLATION Action violates agent constitution 违反 Agent 宪章 动作被宪章策略禁止 查询宪章规则 get_rule;更新宪章或选择其他动作
13 SESSION_EXPIRED Payment session expired 支付会话过期 会话超过 expiry_unix 创建新会话;增加 expiry_unix 值
14 SESSION_LIMIT_EXCEEDED Payment session limit exceeded 支付会话超限 同时活跃会话过多 关闭不用的会话;增加会话限额
15 INVALID_SIGNATURE Invalid Dilithium-5 signature Dilithium-5 签名无效 签名算法错误;密钥不匹配;消息哈希错误 确认使用 Dilithium-5 签名;验证公钥正确性
16 DUPLICATE_NONCE Duplicate nonce detected 重复 Nonce sequence 号重复;重放攻击检测 等待前一笔交易确认;使用 --sequence 手动指定
17 RATE_LIMIT_EXCEEDED Rate limit exceeded 请求频率超限 短时间内请求过多 降低请求频率;使用指数退避重试

2.2 常见原始错误消息映射

原始错误消息 (英文) 错误码 中文解释 解决方案
out of gas in location: ... — Gas 耗尽 --gas-adjustment 2.0 或指定 --gas 5000000
insufficient funds 4 余额不足 msgd query bank balances <addr> 充值
unauthorized 3 未授权 检查 sender 是否为合约 admin 或 owner
contract not found — 合约地址不存在 确认合约地址以 msg1 开头且正确
wasm binary too large — WASM 文件过大 使用 wasm-opt -Os 优化;最大 800KB
Unknown request 6 查询消息不存在 检查 QueryMsg 枚举名和字段
Error parsing into type 7 JSON 解析失败 对照 Schema 检查 JSON 字段类型和命名
sequence mismatch 16 Nonce 不匹配 账户 sequence 号不同步;等待前一笔交易
account sequence mismatch 16 账户序列号不匹配 msgd query auth account <addr> 查看 sequence
connection refused — 端口未监听 确认节点已启动;检查端口配置
No such host — DNS 解析失败 检查网络连接和 DNS 配置
io timeout — 网络超时 检查防火墙和网络延迟
signature verification failed 15 签名验证失败 Dilithium-5 签名问题;确认使用 --algo dilithium5
validator set is empty — 验证者集为空 创世文件配置错误;重新执行 collect-gentxs
dial tcp ... connect: connection refused — 对端无法连接 检查 P2P 端口 (26656) 可达性

2.3 Cosmos SDK 标准错误码

gRPC 错误码 HTTP 状态码 含义 MSG Chain 常见场景
0 (OK) 200 成功 交易成功执行
2 (NotFound) 404 未找到 合约地址无效;查询键不存在
3 (InvalidArgument) 400 参数无效 JSON 消息格式错误
5 (Unauthenticated) 401 未认证 API Key 缺失
7 (PermissionDenied) 403 权限不足 非合约 admin 执行管理操作
8 (ResourceExhausted) 429 资源耗尽 Gas 不足;速率限制
13 (Internal) 500 内部错误 合约 panic;节点状态异常

三、环境搭建问题

3.1 Go 版本不匹配

错误信息:

go: go.mod requires go 1.21.4 but go version go1.18.10 linux/amd64

根因分析:
MSG Chain 需要 Go 1.24.6+。系统默认 Go 版本过低。

解决方案:

# 查看当前版本
go version

# 安装 Go 1.24.6+
wget https://go.dev/dl/go1.21.13.linux-amd64.tar.gz
sudo rm -rf /usr/local/go
sudo tar -C /usr/local -xzf go1.21.13.linux-amd64.tar.gz

# 确保 PATH 正确
echo 'export PATH=$PATH:/usr/local/go/bin' >> ~/.bashrc
echo 'export GOPATH=$HOME/go' >> ~/.bashrc
source ~/.bashrc

# 验证
go version
# 预期: go version go1.21.13 linux/amd64

预防: 在系统安装文档中明确 Go 版本要求;使用 goenv 管理多版本。

3.2 Rust wasm32 目标未安装

错误信息:

error[E0463]: can't find crate for `core`
  |
  = note: the `wasm32-unknown-unknown` target may not be installed

根因分析:
Rust 编译器没有 wasm32 编译目标,无法编译 CosmWasm 合约。

解决方案:

# 安装 wasm32 target
rustup target add wasm32-unknown-unknown

# 验证安装
rustup target list --installed | grep wasm32
# 预期: wasm32-unknown-unknown

# 如果仍然失败,更新 Rust
rustup update

预防: 在项目 README 中明确要求 rustup target add wasm32-unknown-unknown。

3.3 wasm-opt 未找到

错误信息:

wasm-opt: command not found
# 或在优化脚本中:
make optimize: wasm-opt: not found

根因分析:
wasm-opt (Binaryen 工具集) 未安装。

解决方案:

# 方法 1: cargo 安装
cargo install wasm-opt

# 方法 2: 通过系统包管理器
sudo apt install binaryen  # Ubuntu/Debian
brew install binaryen       # macOS

# 方法 3: 下载预编译二进制
wget https://github.com/WebAssembly/binaryen/releases/download/version_116/binaryen-version_116-x86_64-linux.tar.gz
tar -xzf binaryen-version_116-x86_64-linux.tar.gz
sudo cp binaryen-version_116/bin/wasm-opt /usr/local/bin/

# 验证
wasm-opt --version

预防: 将 wasm-opt 安装加入 CI/CD 初始化脚本。

3.4 Docker 未安装或权限不足

错误信息:

docker: command not found
# 或
permission denied while trying to connect to the Docker daemon socket

根因分析:
Docker 未安装,或当前用户不在 docker 组。

解决方案:

# 安装 Docker
sudo apt-get update && sudo apt-get install -y docker.io

# 将用户添加到 docker 组
sudo usermod -aG docker $USER
newgrp docker  # 或重新登录

# 验证
docker --version
docker run hello-world

3.5 Node.js 版本冲突

错误信息:

node: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.28' not found
# 或
SyntaxError: Unexpected token '??=' (在较旧 Node 版本)

根因分析:
Node.js 版本过低(< 18)或过高导致兼容性问题。

解决方案:

# 使用 nvm 安装指定版本
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
source ~/.bashrc
nvm install 18
nvm use 18

# 验证
node --version  # v18.20.x

3.6 make 命令未找到

错误信息:

make: command not found

根因分析:
编译工具链 (build-essential) 未安装。

解决方案:

sudo apt-get install -y build-essential

3.7 jq 未安装

错误信息:

jq: command not found

根因分析:
JSON 命令行处理器未安装。

解决方案:

sudo apt-get install -y jq

3.8 libwasmvm 编译失败

错误信息:

# github.com/CosmWasm/wasmvm
wasmvm/types.go:XX: undefined: ...
# 或
ld: cannot find -lwasmvm: No such file or directory

根因分析:
wasmvm 是 CosmWasm 虚拟机的 Go 绑定,需要 Rust 编译或预编译库。

解决方案:

# 方法 1: 确保 Rust 已安装,让 make deps 自动编译
make deps

# 方法 2: 手动安装 wasmvm(在 go.mod 中指定版本)
# 检查 go.mod 中的 wasmvm 版本
grep wasmvm go.mod
# 下载对应版本
go get github.com/CosmWasm/wasmvm@v1.5.0

# 方法 3: 如果 Rust 环境有问题,使用预编译库
# 在 Makefile 中设置:
# WASMVM_LIBS = /path/to/libwasmvm.so

预防: 先运行 make deps,而非直接 make build-linux。

3.9 Git 克隆失败

错误信息:

fatal: unable to access 'https://github.com/msgchain/msgchain.git/': Could not resolve host
# 或
fatal: Authentication failed for 'https://github.com/msgchain/msgchain.git/'

根因分析:
网络不通或认证失败(如果仓库为私有)。

解决方案:

# 检查网络
ping github.com

# 使用 SSH 方式
git clone git@github.com:msgchain/msgchain.git

# 配置 Git 代理(如需要)
git config --global http.proxy http://proxy:8080
git config --global https.proxy http://proxy:8080

3.10 cargo build 内存不足

错误信息:

memory allocation of 12345678 bytes failed
# 或
signal: 9 (SIGKILL) — 进程被 OOM Killer 杀死

根因分析:
Rust 编译(特别是 LTO 优化)需要大量内存。低内存机器(< 4GB)可能失败。

解决方案:

# 方法 1: 关闭 LTO(增加编译产物大小,减少内存需求)
# 在 Cargo.toml 中设置:
# [profile.release]
# lto = false

# 方法 2: 限制并行编译任务数
CARGO_BUILD_JOBS=2 cargo build --release --target wasm32-unknown-unknown

# 方法 3: 增加交换空间
sudo fallocate -l 4G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile

# 方法 4: 使用 Docker 编译(推荐)
docker run --rm -v $(pwd):/code cosmwasm/rust-optimizer:0.12.13

3.11 Go module 下载超时

错误信息:

go: module github.com/cosmos/cosmos-sdk: Get "https://proxy.golang.org/...": dial tcp ... i/o timeout

根因分析:
Go module 代理在大陆或其他网络受限地区访问慢。

解决方案:

# 使用国内 Go 代理
go env -w GOPROXY=https://goproxy.cn,direct
go env -w GOPRIVATE=github.com/msgchain

# 或使用其他代理
go env -w GOPROXY=https://goproxy.io,direct

# 设置超时
go env -w GOFLAGS=-mod=mod

3.12 Rust crate 下载失败

错误信息:

error: failed to download from `https://crates.io/api/v1/crates/...`

根因分析:
crates.io 访问受限。

解决方案:

# 使用国内镜像(如 ustc)
mkdir -p ~/.cargo
cat >> ~/.cargo/config.toml << 'EOF'
[source.crates-io]
replace-with = 'ustc'

[source.ustc]
registry = "sparse+https://mirrors.ustc.edu.cn/crates.io-index/"
EOF

3.13 端口被占用

错误信息:

ERROR: failed to start node: listen tcp 0.0.0.0:26657: bind: address already in use

根因分析:
节点/其他进程已经占用了端口。

解决方案:

# 查找占用端口的进程
lsof -i :26657
lsof -i :1317
lsof -i :9090

# 杀死进程
kill -9 <PID>
# 或
killall msgd

# 或者修改配置文件端口
sed -i 's/tc[未公开路径]' ~/.msgd/config/config.toml

3.14 curl 请求被拒绝(CORS)

错误信息:

Access to XMLHttpRequest at 'http://localhost:26657/...' from origin 'http://localhost:3000' has been blocked by CORS policy

根因分析:
config.toml 中 CORS 配置未允许前端域名。

解决方案:

sed -i 's/cors_allowed_origins = \[\]/cors_allowed_origins = ["*"]/' ~/.msgd/config/config.toml
# 然后重启节点
killall msgd && ./build/msgd start

四、节点运行问题

4.1 节点无法启动

错误信息:

panic: Failed to start node: ...
# 或
ERROR: failed to start node: ...

根因分析:
配置文件损坏、数据目录不完整、端口冲突、创世文件无效。

解决方案:

# 1. 检查是否已有节点运行
ps aux | grep msgd

# 2. 检查配置文件完整性
ls -la ~/.msgd/config/
# 应该存在: genesis.json, config.toml, app.toml, node_key.json, priv_validator_key.json

# 3. 验证创世文件
./build/msgd validate-genesis

# 4. 查看详细日志
./build/msgd start --log_level="debug" 2>&1 | head -100

# 5. 重置数据(保留密钥)
./build/msgd unsafe-reset-all

# 6. 使用 --trace 获取堆栈
./build/msgd start --trace

4.2 节点启动后立即崩溃

错误信息:

panic: interface conversion: interface is nil, not ...
panic: runtime error: invalid memory address or nil pointer dereference

根因分析:
创世文件与应用状态不匹配;模块初始化顺序错误。

解决方案:

# 1. 重新初始化
rm -rf ~/.msgd/data/
./build/msgd init --chain-id=msg-chain-1

# 2. 重新添加创世账户
./build/msgd add-genesis-account <addr> 1000000000000000000umsg

# 3. 重新生成创世交易
./build/msgd gentx validator 500000000000000000umsg --chain-id=msg-chain-1 --keyring-backend test
./build/msgd collect-gentxs
./build/msgd validate-genesis

# 4. 重新启动
./build/msgd start

4.3 节点同步卡住

错误信息:

INFO [2026-07-05|12:00:00] Executed block       module=state height=12345
INFO [2026-07-05|12:00:05] Executed block       module=state height=12345
# 高度不再增加

根因分析:
共识卡住;验证者集问题;BadgerDB 损坏。

解决方案:

# 1. 检查节点是否孤块
curl -s http://localhost:26657/consensus_state | jq '.result.round_state.height'

# 2. 检查对等节点
curl -s http://localhost:26657/net_info | jq '.result.n_peers'
# 如果 n_peers = 0,网络断开

# 3. 检查 BadgerDB
ls -la ~/.msgd/data/state.db/

# 4. 重置数据并重新同步
./build/msgd unsafe-reset-all
./build/msgd start

# 5. 检查创世文件是否包含正确的验证者
cat ~/.msgd/config/genesis.json | jq '.validators'

4.4 节点无法连接对等节点

错误信息:

ERROR failed to connect to peer: dial tcp <ip>:26656: connect: connection refused
# 或
INFO No addresses to dial. Falling back to seeds module=p2p server=node

根因分析:
P2P 网络配置不正确;防火墙阻止了 P2P 端口;种子节点不可达。

解决方案:

# 1. 检查 P2P 端口是否开放
curl -s http://localhost:26657/net_info | jq '.result.peers | length'

# 2. 检查种子节点配置
grep -E "seeds|persistent_peers" ~/.msgd/config/config.toml

# 3. 手动添加持久节点
sed -i 's/seeds = ""/seeds = "seed1.msgchain.org:26656,seed2.msgchain.org:26656"/' ~/.msgd/config/config.toml

# 4. 检查节点 ID
./build/msgd tendermint show-node-id

# 5. 检查防火墙
sudo ufw status
sudo ufw allow 26656/tcp

# 6. 下载 addrbook
curl -o ~/.msgd/config/addrbook.json https://raw.githubusercontent.com/msgchain/mainnet/main/addrbook.json

4.5 状态同步失败

错误信息:

ERROR failed to state sync: ...
# 或
WARN snapshot not found at height ...

根因分析:
状态同步配置错误;可信高度和哈希不匹配;RPC 服务器不可达。

解决方案:

# 1. 检查状态同步配置
grep -A 10 "\[statesync\]" ~/.msgd/config/config.toml

# 2. 手动获取可信高度和哈希
TRUST_HEIGHT=$(curl -s https://rpc.msgchain.org/status | jq -r '.result.sync_info.latest_block_height')
TRUST_HASH=$(curl -s https://rpc.msgchain.org/status | jq -r '.result.sync_info.latest_block_hash')

# 3. 更新配置
sed -i "s|enable = false|enable = true|" ~/.msgd/config/config.toml
sed -i "s|trust_height = .*|trust_height = $TRUST_HEIGHT|" ~/.msgd/config/config.toml
sed -i "s|trust_hash = .*|trust_hash = \"$TRUST_HASH\"|" ~/.msgd/config/config.toml

# 4. 重置并重启
./build/msgd tendermint unsafe-reset-all --keep-addr-book
./build/msgd start

4.6 BadgerDB 损坏

错误信息:

ERROR badger: Manifest corrupted. Manifest file: /home/user/.msgd/data/state.db/MANIFEST
# 或
panic: badger: value log corruption: ... checksum mismatch

根因分析:
突然断电、磁盘故障、不安全的关闭导致 BadgerDB 数据损坏。

解决方案:

# 方法 1: 使用 BadgerDB 内置恢复工具
# BadgerDB 会在启动时自动尝试恢复 — 重启节点
killall msgd
./build/msgd start --log_level="debug"
# 观察日志中是否有 "badger: Replaying file" 字样

# 方法 2: 手动修复(如果自动恢复失败)
# 删除损坏的 value log 文件(危险操作!)
cd ~/.msgd/data/state.db/
# 查找损坏的文件
ls -la *.vlog
# 如果确认损坏,可以删除特定 vlog 文件(会丢失该文件中的状态)
# rm 000001.vlog  # 示例 — 具体文件名看错误信息

# 方法 3: 完全重置数据
./build/msgd unsafe-reset-all
# 从快照或状态同步重新开始

# 方法 4: 从备份恢复
cp -r /backup/msgd/state.db/* ~/.msgd/data/state.db/

预防:

4.7 Dilithium-5 密钥错误

错误信息:

ERROR failed to create validator: validator key type mismatch
# 或
ERROR invalid pubkey type: expected /cosmos.crypto.dilithium.PubKey, got /cosmos.crypto.secp256k1.PubKey

根因分析:
创建验证者时使用了错误的密钥类型(MSG Chain 必须使用 Dilithium-5)。

解决方案:

# 1. 检查当前密钥类型
./build/msgd keys show validator -p --keyring-backend test | jq '.@type'
# 应该输出: "/cosmos.crypto.dilithium.PubKey"

# 2. 如果密钥类型错误,重新创建
./build/msgd keys delete validator --keyring-backend test -y
./build/msgd keys add validator --algo dilithium5 --keyring-backend test

# 3. 或者指定 --algo dilithium5 参数在恢复时
./build/msgd keys add validator --recover --algo dilithium5 --keyring-backend test

4.8 节点 OOM(内存溢出)

错误信息:

Killed  — 进程被系统杀死
# 查看系统日志
dmesg | grep -i oom

根因分析:
内存不足。MSG Chain 节点需要至少 4GB 内存(推荐 8GB+)。

解决方案:

# 1. 查看当前内存使用
free -h

# 2. 增加交换空间
sudo fallocate -l 8G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile

# 3. 在 app.toml 中降低内存使用
# 设置 pruning 为 "everything" 减少状态存储
sed -i 's/pruning = "default"/pruning = "everything"/' ~/.msgd/config/app.toml

# 4. 限制 BadgerDB 缓存大小
# 在 app.toml 中设置:
# [store]
# memtable-size = 33554432  # 32MB (默认 64MB)
# value-log-file-size = 524288000  # 500MB (默认 1GB)

4.9 genesis.json 校验失败

错误信息:

Error: invalid genesis file: error unmarshalling: ...
# 或
Error: validator set is empty in genesis

根因分析:
创世文件 JSON 格式错误、缺少验证者、chain-id 不匹配。

解决方案:

# 1. 验证 JSON 格式
cat ~/.msgd/config/genesis.json | jq '.'
# 如果 jq 报错,说明 JSON 格式有问题

# 2. 检查 chain_id
cat ~/.msgd/config/genesis.json | jq '.chain_id'
# 应该: "msg-chain-1"

# 3. 检查验证者集
cat ~/.msgd/config/genesis.json | jq '.validators | length'
# 应该 > 0

# 4. 重新生成创世文件
./build/msgd init --chain-id=msg-chain-1
./build/msgd add-genesis-account <addr> 1000000000000000000umsg
./build/msgd gentx validator 500000000000000000umsg --chain-id=msg-chain-1 --keyring-backend test
./build/msgd collect-gentxs

4.10 创世应用状态哈希不匹配

错误信息:

Error: app_hash in genesis file is not correct. Expected ABC..., got XYZ...

根因分析:
多个节点使用了不同的 genesis.json 或不同的应用版本。

解决方案:

# 1. 确保所有节点使用相同的 genesis.json
sha256sum ~/.msgd/config/genesis.json

# 2. 确保节点版本相同
./build/msgd version

# 3. 重新启动时使用 --x-crisis-skip-assert-invariants 跳过不变性检查
./build/msgd start --x-crisis-skip-assert-invariants

4.11 DAR 共识未启用

错误信息:

WARN DAR is not enabled, using standard Tendermint consensus

根因分析:
config.toml 中 DAR 配置未启用。

解决方案:

# 1. 检查配置
grep -E "dar_enabled|round_robin_proposer" ~/.msgd/config/config.toml

# 2. 启用 DAR
sed -i 's/dar_enabled = false/dar_enabled = true/' ~/.msgd/config/config.toml
sed -i 's/round_robin_proposer = false/round_robin_proposer = true/' ~/.msgd/config/config.toml

# 3. 重启节点
killall msgd && ./build/msgd start

4.12 RPC 返回 502 Bad Gateway

错误信息:

HTTP 502 Bad Gateway — 通过 Nginx 反向代理访问 RPC

根因分析:
Nginx 配置错误或后端 RPC 未运行。

解决方案:

# 1. 检查后端节点是否运行
curl -s http://localhost:26657/status > /dev/null && echo "OK" || echo "Node not running"

# 2. 检查 Nginx 配置
cat /etc/nginx/sites-available/msgd-rpc | grep proxy_pass

# 3. 查看 Nginx 错误日志
tail -100 /var/log/nginx/error.log

# 4. 检查 WebSocket 支持(如果使用)
# Nginx 需要:
# proxy_http_version 1.1;
# proxy_set_header Upgrade $http_upgrade;
# proxy_set_header Connection "upgrade";

4.13 无法广播交易 — 节点不同步

错误信息:

broadcast_tx_sync: Response error: RPC error -32603 - Internal error: height must be less than or equal to the current blockchain height

根因分析:
节点正在同步(catching_up = true),尚未追到最新区块。

解决方案:

# 1. 检查同步状态
curl -s http://localhost:26657/status | jq '.result.sync_info.catching_up'
# 如果为 true,节点正在同步

# 2. 等待同步完成
watch -n 10 'curl -s http://localhost:26657/status | jq "{height: .result.sync_info.latest_block_height, catching_up: .result.sync_info.catching_up}"'

# 3. 使用 --broadcast-mode sync 而不是 block
./build/msgd tx wasm store contract.wasm --from validator --gas auto --gas-prices 1000000000umsg --chain-id msg-chain-1 --broadcast-mode sync -y

4.14 Cosmovisor 自动升级失败

错误信息:

UPGRADE "upgrade-v2" NEEDED at height: 1000000
# 但节点卡在 upgrade height 不再前进

根因分析:
Cosmovisor 未找到升级二进制或升级脚本失败。

解决方案:

# 1. 检查 Cosmovisor 目录结构
ls -la ~/.msgd/cosmovisor/
ls -la ~/.msgd/cosmovisor/upgrades/upgrade-v2/bin/

# 2. 手动放置新的二进制
mkdir -p ~/.msgd/cosmovisor/upgrades/upgrade-v2/bin/
cp build/msgd ~/.msgd/cosmovisor/upgrades/upgrade-v2/bin/

# 3. 手动重启
killall msgd
./build/msgd start

# 4. 检查升级是否成功
./build/msgd version

4.15 验证者 jailed(被监禁)

错误信息:

ERROR validator is jailed, cannot sign
# 或查询显示:
./build/msgd query staking validator <valoper> | jq '.validator.jailed'
# true

根因分析:
验证者因长期离线、双签或其他违规被监禁。

解决方案:

# 1. 确认被监禁
VALOPER=$(./build/msgd keys show validator --bech val -a --keyring-backend test)
./build/msgd query staking validator "$VALOPER" -o json | jq '.validator.jailed'

# 2. 解禁
./build/msgd tx slashing unjail \
  --from validator \
  --gas auto \
  --gas-prices 1000000000umsg \
  --chain-id msg-chain-1 \
  --keyring-backend test \
  --node tcp://localhost:26657 \
  -y

# 3. 自动解禁脚本(用于 crontab)
cat > ~/auto_unjail.sh << 'EOF'
#!/bin/bash
VALOPER=$(msgd keys show validator --bech val -a --keyring-backend os)
JAILED=$(msgd query staking validator "$VALOPER" --node tcp://localhost:26657 -o json | jq -r '.validator.jailed')
if [ "$JAILED" = "true" ]; then
  msgd tx slashing unjail --from validator --gas auto --gas-prices 1000000000umsg --chain-id msg-chain-1 --keyring-backend os -y
  echo "[$(date)] Unjailed"
fi
EOF
chmod +x ~/auto_unjail.sh

五、合约编译问题

5.1 Rust 编译错误: 缺少 cosmwasm_std

错误信息:

error[E0432]: unresolved import `cosmwasm_std::entry_point`

根因分析:
Cargo.toml 中缺少 cosmwasm-std 依赖或版本不正确。

解决方案:

[dependencies]
cosmwasm-std = "1.5"
# 或使用特定版本
cosmwasm-std = { version = "1.5", features = ["staking"] }
# 检查已安装版本
cargo metadata --format-version 1 | jq '.packages[] | select(.name == "cosmwasm-std") | .version'

5.2 wasm32 编译目标不支持某些 Rust 特性

错误信息:

error: use of unstable library feature '...
# 或
error: the wasm32-unknown-unknown target does not support std

根因分析:
WASM 环境是 no_std 的。使用了标准库特有的功能(如文件 IO、网络、线程)。

解决方案:

// 错误示例: 使用 std::fs 在合约中
// use std::fs;  // ❌ WASM 中不可用

// 正确: 仅使用 cosmwasm_std
use cosmwasm_std::{DepsMut, Env, MessageInfo, Response, StdResult};
use cw_storage_plus::Item;
# 检查合约是否使用了 std-only 功能
grep -rn "use std::" src/

5.3 lto 链接错误

错误信息:

error: LTO can only be run for executables, not cdylibs
# 或
error: could not copy ... to ...: Invalid argument

根因分析:
LTO 和 cdylib crate 类型冲突。

解决方案:

# Cargo.toml 中正确的配置
[lib]
crate-type = ["cdylib", "rlib"]

[profile.release]
lto = true   # 这是正确的,如果报错请尝试:
# lto = "thin"  # 使用 thin LTO 替代完整 LTO

5.4 WASM 二进制体积过大

错误信息:

Error: rpc error: code = InvalidArgument desc = wasm binary size (1048576 bytes) exceeds maximum (819200 bytes)

根因分析:
编译出的 WASM 文件超过 800KB 上限。

解决方案:

# 1. 检查当前大小
ls -lh target/wasm32-unknown-unknown/release/my_contract.wasm

# 2. 使用 wasm-opt 优化
wasm-opt -Os -o optimized.wasm target/wasm32-unknown-unknown/release/my_contract.wasm
# -Os: 体积优化  -Oz: 激进体积优化

# 3. 检查优化效果
ls -lh optimized.wasm

# 4. 在 Cargo.toml 中启用更多优化
[profile.release]
opt-level = "z"  # 体积优化 (替代 3)
lto = true
codegen-units = 1
panic = "abort"
strip = true     # 移除符号(需要 Rust 1.59+)

# 5. 删除不必要的依赖
cargo tree  # 查看依赖树
# 移除未使用的依赖

5.5 Rust 编译时泛型膨胀

错误信息:

note: the wasm32-unknown-unknown target may not support `dylib` crates

根因分析:
过度使用泛型导致编译产物膨胀。

解决方案:

// 不要过度泛型化
// 避免:
pub fn process<T: Serialize>(data: T) -> ...  // ❌

// 使用具体类型:
pub fn process(data: MyStruct) -> ...  // ✅

5.6 Schema 生成失败

错误信息:

Error: cannot find `ExecuteMsg` or `QueryMsg` or `InstantiateMsg` in the crate
# 或
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value'

根因分析:
Schema 生成器找不到消息类型定义。

解决方案:

# 1. 检查 examples/schema.rs 是否正确
cat examples/schema.rs

# 2. 确保消息类型是公开的 (pub)
# 在 src/msg.rs 中:
#[cw_serde]
pub struct InstantiateMsg { ... }  // ✅ 需要 pub

#[cw_serde]
pub enum ExecuteMsg { ... }  // ✅ 需要 pub

# 3. 运行 schema 生成
cargo run --example schema

5.7 条件编译错误

错误信息:

error[E0432]: unresolved import `cosmwasm_crypto`

根因分析:
cosmwasm-crypto 仅在非 WASM 目标下可用。

解决方案:

# Cargo.toml
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
cosmwasm-crypto = "1.5"

[target.'cfg(target_arch = "wasm32")'.dependencies]
# WASM 目标不需要 cosmwasm-crypto
// 代码中条件引入
#[cfg(not(target_arch = "wasm32"))]
use cosmwasm_crypto::secp256k1_verify;

5.8 cargo test 失败的 mock 问题

错误信息:

error[E0432]: unresolved import `cosmwasm_std::testing`

根因分析:
testing 模块需要在测试环境中正确引入。

解决方案:

// 正确导入
#[cfg(test)]
mod tests {
    use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info};
    use cosmwasm_std::{from_binary, Addr};
    // ...
}
# Cargo.toml — 确保 dev-dependencies 正确
[dev-dependencies]
cosmwasm-vm = "1.5"
cw-multi-test = "0.18"

5.9 编译时缺少 feature flags

错误信息:

error: the feature `staking` is required for this crate

根因分析:
cosmwasm-std 的 staking 特性未启用,但合约中使用了 staking 相关功能。

解决方案:

[dependencies]
cosmwasm-std = { version = "1.5", features = ["staking"] }

5.10 contract.rs 中的 entry_point 问题

错误信息:

error: the `#[entry_point]` attribute macro requires `cosmwasm-std` in dependencies

根因分析:
缺少 #[entry_point] 宏或导入不正确。

解决方案:

use cosmwasm_std::entry_point;  // ✅ 正确导入
// use cosmwasm_std::EntryPoint;  // ❌ 错误:这是 trait 不是宏

#[entry_point]
pub fn instantiate(deps: DepsMut, _env: Env, info: MessageInfo, msg: InstantiateMsg) -> StdResult<Response> {
    // ...
}

5.11 缺失必要的导出类型

错误信息:

error[E0603]: module `contract` is private

根因分析:
lib.rs 中模块声明缺少 pub。

解决方案:

// src/lib.rs
pub mod contract;  // ✅ 需要 pub
pub mod msg;       // ✅
pub mod state;     // ✅

5.12 wasm-opt 优化后合约不工作

错误信息:

Contract execution failed: Error calling the VM: RuntimeError: unreachable

根因分析:
wasm-opt 使用了激进的优化级别导致代码被错误优化。

解决方案:

# 使用较温和的优化级别
wasm-opt -O1 -o optimized.wasm input.wasm  # 最安全
wasm-opt -O2 -o optimized.wasm input.wasm  # 平衡
wasm-opt -Os -o optimized.wasm input.wasm  # 体积优化(通常安全)

# 避免 -O4(可能会出问题)
# 避免额外的 --enable-signext 等实验性 flag

# 比较优化前后的行为差异

5.13 合约测试中使用 from_binary 失败

错误信息:

thread 'tests::test_name' panicked at 'called `Result::unwrap()` on an `Err` value: ParseErr { ... }'

根因分析:
查询响应 JSON 反序列化失败,响应结构不匹配。

解决方案:

// 确保查询响应类型正确
#[cw_serde]
pub struct CountResponse {
    pub count: i32,  // 字段名与合约中定义的完全一致
}

// 使用 from_binary 正确反序列化
let query_res = query(deps.as_ref(), env, QueryMsg::GetCount {}).unwrap();
let count_res: CountResponse = from_binary(&query_res).unwrap();
assert_eq!(count_res.count, 0);

// 调试: 打印原始响应
println!("Raw response: {:?}", query_res);

六、合约部署问题

6.1 StoreCode 失败 — WASM 文件无效

错误信息:

Error: rpc error: code = InvalidArgument desc = failed to execute message; message index: 0: Error calling the VM: Error during static validation: unknown import: ...

根因分析:
WASM 文件不完整或包含 CosmWasm 不支持的导入。

解决方案:

# 1. 验证 WASM 文件格式
file contract.wasm
# 应输出: WebAssembly (wasm) binary module version 0x1 (MVP)

# 2. 检查是否包含 cosmwasm 入口点
wasm2wat contract.wasm 2>/dev/null | grep "entry_point" || echo "No entry points found"

# 3. 使用 cosmwasm-check 工具
cargo install cosmwasm-check
cosmwasm-check contract.wasm
# 应输出: "PASS" 或列出缺少的入口点

# 4. 重新编译并确保生成正确的 WASM
RUSTFLAGS='-C link-arg=-s' cargo build --release --target wasm32-unknown-unknown

6.2 Gas 估算失败

错误信息:

Error: rpc error: code = InvalidArgument desc = gas estimate error: ...
# 或
gas estimate failed: query: error paginating: ...

根因分析:
Gas 自动估算时模拟执行失败,通常是消息格式问题。

解决方案:

# 方法 1: 手动指定 Gas(绕过估算)
./build/msgd tx wasm store contract.wasm \
  --from validator \
  --gas 5000000 \      # 直接指定,不自动估算
  --gas-prices 1000000000umsg \
  --chain-id msg-chain-1 \
  -y

# 方法 2: 增加 gas-adjustment
./build/msgd tx wasm store contract.wasm \
  --from validator \
  --gas auto \
  --gas-prices 1000000000umsg \
  --gas-adjustment 2.0 \  # 提高调整因子
  --chain-id msg-chain-1 \
  -y

# 方法 3: 先模拟再提交
./build/msgd tx wasm store contract.wasm \
  --from validator \
  --gas auto \
  --gas-prices 1000000000umsg \
  --dry-run \
  --chain-id msg-chain-1

6.3 Code ID 未找到

错误信息:

Error: rpc error: code = NotFound desc = code not found: code_id: 1

根因分析:
引用的 Code ID 不存在。StoreCode 未成功,或使用了错误的 Chain ID。

解决方案:

# 1. 列出所有已上传的代码
./build/msgd query wasm list-code --node tcp://localhost:26657

# 2. 如果列表为空,说明 StoreCode 未成功
# 重新上传
./build/msgd tx wasm store contract.wasm \
  --from validator \
  --gas auto \
  --gas-prices 1000000000umsg \
  --gas-adjustment 1.3 \
  --chain-id msg-chain-1 \
  -y

# 3. 确认 StoreCode 交易成功
# 从输出中获取 txhash
./build/msgd query tx <txhash> | jq '.code'
# 应返回: 0

# 4. 验证 chain ID 匹配
echo "chain-id: msg-chain-1"

6.4 Instantiate 被拒绝

错误信息:

Error: rpc error: code = InvalidArgument desc = failed to execute message; message index: 0: Error parsing into type my_contract::msg::InstantiateMsg: missing field `count`

根因分析:
实例化消息缺少必填字段。

解决方案:

# 1. 检查合约 Schema
cat schema/instantiate_msg.json | jq '.'

# 2. 确保 JSON 包含所有必填字段(无 optional 标记)
# ❌ 错误:
INIT_MSG='{"count": 0}'  # 如果合约需要 count 和 owner

# ✅ 正确:
INIT_MSG='{"count": 0, "owner": "msg1..."}'

# 3. 使用 cargo schema 生成最新 Schema
cargo schema
cat schema/instantiate_msg.json

6.5 合约地址推导失败

错误信息:

Error: error calculating contract address: ...
# 或前端查询合约时报错

根因分析:
合约地址由 Creator + CodeID + Label + Nonce 推导生成。如果参数不一致,前端可能推导错误。

解决方案:

// 正确获取合约地址
// 方法 1: 从 Instantiate 交易事件中获取
const result = await client.execute(sender, codeId, msg, "auto");
const contractAddress = result.events
  .find(e => e.type === "instantiate")
  ?.attributes
  ?.find(a => a.key === "_contract_address")
  ?.value;

// 方法 2: 查询 by Code ID
const contracts = await client.getContracts(codeId);
// contracts[0] 是最新实例化的合约

// 方法 3: (客户端推导 — CosmJS 内部)
// import { ContractAddress } from "@cosmjs/cosmwasm-stargate";
// const addr = ContractAddress.fromCodeId(codeId);

6.6 部署时余额不足

错误信息:

Error: rpc error: code = InvalidArgument desc = insufficient funds: insufficient account funds; ... required: 5000000umsg

根因分析:
账户余额不足以支付交易费 + 合约部署费。

解决方案:

# 1. 查询当前余额
./build/msgd query bank balances $(./build/msgd keys show validator -a --keyring-backend test)

# 2. 如果余额不足,从其他账户转账
./build/msgd tx bank send <from> <to> 1000000000000000000000umsg \
  --from <from_key> \
  --gas auto \
  --gas-prices 1000000000umsg \
  --chain-id msg-chain-1

# 3. 或者使用更低 gas 价格的交易
./build/msgd tx wasm store contract.wasm \
  --from validator \
  --gas auto \
  --gas-prices 1000000000umsg \    # 标准 Gas 价格
  --gas-adjustment 1.3 \
  --chain-id msg-chain-1 \
  -y

6.7 合约部署后无法查询

错误信息:

Error: rpc error: code = NotFound desc = contract not found: msg1...

根因分析:
合约地址拼写错误、chain-id 不匹配、节点不同步、合约未实例化。

解决方案:

# 1. 确认合约地址格式
echo $CONTRACT_ADDR | grep "^msg1"
# 地址必须以 msg1 开头

# 2. 确认合约已部署
./build/msgd query wasm list-contract-by-code <CODE_ID>

# 3. 检查节点同步状态
curl -s http://localhost:26657/status | jq '.result.sync_info.catching_up'
# 如果为 true,等待同步完成

# 4. 尝试通过 REST API 查询
curl http://localhost:1317/cosmwasm/wasm/v1/contract/$CONTRACT_ADDR

6.8 合约迁移失败

错误信息:

Error: rpc error: code = InvalidArgument desc = migrate: failed to execute message; message index: 0: Error calling the VM: Error during static validation: contract state is incompatible

根因分析:
新合约版本的状态数据结构与旧版本不兼容。

解决方案:

// 迁移时处理状态迁移
#[entry_point]
pub fn migrate(deps: DepsMut, _env: Env, _msg: MigrateMsg) -> StdResult<Response> {
    // 1. 读取旧状态
    let old_state = STATE.may_load(deps.storage)?;

    // 2. 转换为新状态
    let new_state = match old_state {
        Some(s) => NewState {
            count: s.count,
            // 添加新字段的默认值
            new_field: "default".to_string(),
        },
        None => NewState::default(),
    };

    // 3. 保存新状态
    NEW_STATE.save(deps.storage, &new_state)?;

    // 4. 更新合约版本
    cw2::set_contract_version(deps.storage, "my-contract", "2.0.0")?;

    Ok(Response::new().add_attribute("method", "migrate"))
}

6.9 实例化时 Funds 参数错误

错误信息:

Error: rpc error: code = InvalidArgument desc = failed to execute message; message index: 0: funds transfer failed

根因分析:
实例化时传递的资金(funds)格式不正确。

解决方案:

# ❌ 错误格式
--amount="1000000"

# ✅ 正确格式
--amount="1000000umsg"

# ❌ 多个金额格式
--amount="1000000umsg,500000umsg"  # 旧格式

# ✅ 正确格式
--funds="1000000umsg"

6.10 未指定管理员导致无法迁移

错误信息:

Error: rpc error: code = InvalidArgument desc = contract does not have admin set; cannot migrate

根因分析:
实例化时未指定 --admin 参数,导致合约没有管理员。

解决方案:

# 实例化时指定管理员
./build/msgd tx wasm instantiate 1 '{"count":0}' \
  --from validator \
  --label "my-contract" \
  --admin $(./build/msgd keys show validator -a --keyring-backend test) \  # ✅ 必须
  --gas auto \
  --gas-prices 1000000000umsg \
  --chain-id msg-chain-1 \
  -y

# 如果合约已部署且没有管理员,无法添加
# 只能通过 UpdateAdmin 消息(需要合约原管理员签名)
# 但如果没有管理员,合约永不可迁移

七、合约交互问题

7.1 Execute 消息解析错误

错误信息:

Error: rpc error: code = InvalidArgument desc = failed to execute message; message index: 0: Error parsing into type my_contract::msg::ExecuteMsg: unknown variant `increment`, expected `Increment`

根因分析:
JSON 中枚举的变体名大小写不匹配。Rust 枚举变体名是驼峰式,但 JSON 中字段名默认也使用驼峰式(serde 默认)。

解决方案:

# ❌ 错误(小写)
'{"increment": {}}'

# ✅ 正确(与 Rust 枚举变体名一致)
'{"increment": {}}'  # serde 默认将 Increment 序列化为 "increment"
# 或者如果使用 #[serde(rename_all = "snake_case")]
'{"increment": {}}'
// 在合约中指定命名规则
#[cw_serde]  // 默认使用驼峰式
pub enum ExecuteMsg {
    Increment {},
    Reset { count: i32 },
}

// 或使用 snake_case
#[serde(rename_all = "snake_case")]
pub enum ExecuteMsg {
    Increment {},
    Reset { count: i32 },
}
// JSON 中使用: {"increment": {}}, {"reset": {"count": 10}}

7.2 Unauthorized 执行

错误信息:

Error: rpc error: code = InvalidArgument desc = failed to execute message; message index: 0: Unauthorized: only owner can reset

根因分析:
调用者不是合约的 owner/admin,没有执行该操作的权限。

解决方案:

# 1. 查询合约 owner
./build/msgd query wasm contract-state smart $CONTRACT_ADDR '{"get_owner": {}}'

# 2. 确认当前使用的账户
echo "My address: $(./build/msgd keys show validator -a --keyring-backend test)"

# 3. 如果是合约 admin 问题,查询合约信息
./build/msgd query wasm contract $CONTRACT_ADDR | jq '.contract_info.admin'
# 如果 admin 是另一地址,需要使用该地址执行

# 4. 使用正确的账户执行
./build/msgd tx wasm execute $CONTRACT_ADDR '{"reset": {"count": 0}}' \
  --from <owner_or_admin> \  # 使用正确的账户
  --gas auto \
  --gas-prices 1000000000umsg \
  --chain-id msg-chain-1 \
  -y

7.3 合约 Panicked

错误信息:

Error: rpc error: code = InvalidArgument desc = failed to execute message; message index: 0: Generic error: contract panicked

根因分析:
合约代码中调用了 .unwrap() 或 panic!() 导致崩溃。

解决方案:

// 不要在合约中使用 unwrap() 或 expect()
// ❌ 错误
let state = STATE.load(deps.storage).unwrap();

// ✅ 正确 — 使用 ? 传播错误
let state = STATE.load(deps.storage)?;

// ✅ 或者使用 match
match STATE.load(deps.storage) {
    Ok(state) => { /* 处理 */ },
    Err(e) => return Err(StdError::generic_err("State not found")),
}
# 调试: 启用 debug 日志
./build/msgd start --log_level="debug" 2>&1 | grep -i "contract\|panic\|error"

# 在合约中添加错误处理
#[derive(Error, Debug, PartialEq)]
pub enum ContractError {
    #[error("{0}")]
    Std(#[from] StdError),
    #[error("Count overflow")]
    Overflow {},
}

7.4 Out of Gas 中执行

错误信息:

Error: rpc error: code = InvalidArgument desc = out of gas in location: WriteFlat; gasWanted: 200000, gasUsed: 200000: out of gas

根因分析:
交易 Gas 上限不足以完成合约执行。

解决方案:

# 方法 1: 增加 Gas 上限
./build/msgd tx wasm execute $CONTRACT_ADDR '{"complex_op": {}}' \
  --gas 5000000 \       # 直接指定较高的 gas
  --gas-prices 1000000000umsg \
  --chain-id msg-chain-1 \
  -y

# 方法 2: 增加调整因子
  --gas auto \
  --gas-adjustment 2.0 \  # 从 1.3 提高到 2.0

# 方法 3: 前端中设置
const result = await client.execute(
  sender,
  contractAddress,
  msg,
  { amount: [{ denom: "umsg", amount: "5000" }], gas: "5000000" },  // 手动指定 fee
);

7.5 事件未发出

错误信息:
交易成功 (code=0) 但预期的事件未出现在交易日志中。

根因分析:
合约中未添加事件属性,或者事件类型/键名拼写错误。

解决方案:

// 确保在 Response 中添加事件属性
#[entry_point]
pub fn execute(deps: DepsMut, _env: Env, info: MessageInfo, msg: ExecuteMsg) -> Result<Response, ContractError> {
    match msg {
        ExecuteMsg::Increment {} => {
            STATE.update(deps.storage, |mut s| { s.count += 1; Ok(s) })?;

            Ok(Response::new()
                .add_attribute("method", "increment")        // ✅ 事件属性
                .add_attribute("new_count", "1")
                .add_attribute("sender", info.sender))
        }
    }
}
# 查询合约事件
./build/msgd query tx <txhash> | jq '.logs[0].events[] | select(.type == "wasm")'

7.6 合约状态未更新

错误信息:
交易成功但查询时状态未变化。

根因分析:
查询的节点不同步;状态被其他交易覆盖;使用错误的查询高度。

解决方案:

# 1. 等待交易确认(5秒出块)
sleep 6

# 2. 检查节点是否已同步最新区块
curl -s http://localhost:26657/status | jq '.result.sync_info'

# 3. 指定查询高度(可选)
./build/msgd query wasm contract-state smart $CONTRACT_ADDR '{"get_count": {}}' \
  --height $(curl -s http://localhost:26657/status | jq '.result.sync_info.latest_block_height')

# 4. 检查交易是否真的成功
./build/msgd query tx <txhash> | jq '.code'
# 应该为 0

# 5. 检查交易日志是否有错误
./build/msgd query tx <txhash> | jq '.raw_log'

7.7 查询返回空

错误信息:

Error: rpc error: code = InvalidArgument desc = Generic error: Querier contract error: ...: not found
# 或查询返回空数据

根因分析:
查询的键不存在;查询消息格式错误;合约尚未初始化该状态。

解决方案:

# 1. 检查查询消息格式 — 对照 Schema
cat schema/query_msg.json | jq '.'
./build/msgd query wasm contract-state smart $CONTRACT_ADDR '{"get_count": {}}'

# 2. 检查合约是否已正确实例化
./build/msgd query wasm contract $CONTRACT_ADDR

# 3. 检查原始存储
./build/msgd query wasm contract-state all $CONTRACT_ADDR
# 查看所有存储的键值对

# 4. 如果使用 Map,检查 key 是否正确
# Rust 中: pub const ITEMS: Map<&str, Data> = Map::new("items");
# 查询: {"get_item": {"key": "some_key"}}

7.8 合约调用深度超过限制

错误信息:

Error: rpc error: code = InvalidArgument desc = Generic error: contract call depth exceeded

根因分析:
合约 A 调用合约 B,合约 B 又回调合约 A,形成循环调用。CosmWasm 有调用深度限制(默认 20 层)。

解决方案:

// 1. 避免递归调用
// ❌ 错误: 合约 A 调用合约 B,B 又调用回 A
// A -> B -> A -> B -> ...

// 2. 重构架构,使用异步模式
// ✅ 正确: A 调用 B,B 直接返回结果
// 使用 Reply 来处理回调

// 3. 减少链式调用
// 如果确实需要多次调用,分批处理而不是一次性全部调用

7.9 Reply ID 冲突

错误信息:

Error: rpc error: code = InvalidArgument desc = reply: no reply handler for submessage id X

根因分析:
合约发送了 SubMsg 但没有对应的 reply 处理函数。

解决方案:

// 1. 定义 Reply ID 常量
const REPLY_ID_INCREMENT: u64 = 1;

// 2. 在 execute 中发送 SubMsg
pub fn execute(deps: DepsMut, env: Env, info: MessageInfo, msg: ExecuteMsg) -> Result<Response, ContractError> {
    let exec_msg = WasmMsg::Execute {
        contract_addr: "msg1...".to_string(),
        msg: to_binary(&IncrementMsg {})?,
        funds: vec![],
    };

    Ok(Response::new()
        .add_submessage(SubMsg::reply_on_success(exec_msg, REPLY_ID_INCREMENT)))
}

// 3. 添加 reply 入口点
#[entry_point]
pub fn reply(deps: DepsMut, _env: Env, msg: Reply) -> Result<Response, ContractError> {
    match msg.id {
        REPLY_ID_INCREMENT => {
            // 处理回复
            Ok(Response::new().add_attribute("reply", "increment_done"))
        },
        _ => Err(ContractError::UnknownReplyId {}),
    }
}

7.10 IBC 数据包超时

错误信息:

Error: rpc error: code = InvalidArgument desc = IBC packet timeout: packet sequence X has timed out

根因分析:
IBC 数据包未在超时高度和超时时间戳之前到达目标链。

解决方案:

// 设置合理的超时时间
use cosmwasm_std::{IbcTimeout, IbcTimeoutBlock};

// 基于高度的超时(推荐)
let timeout = IbcTimeout::with_block(IbcTimeoutBlock {
    revision: 0,
    height: env.block.height + 100,  // 500 秒后超时(100 blocks × 5s)
});

// 基于时间戳的超时
let timeout = IbcTimeout::with_timestamp(env.block.time.plus_seconds(600));  // 10 分钟

7.11 CosmWasm 标准查询失败

错误信息:

Error: rpc error: code = InvalidArgument desc = query wasm contract failed: not found: ...

根因分析:
通过 /cosmwasm.wasm.v1.Query/SmartContractState 查询时,base64 编码的 query_data 格式有误。

解决方案:

# 正确编码查询数据
QUERY_MSG='{"get_count": {}}'
QUERY_BASE64=$(echo -n "$QUERY_MSG" | base64 -w0)

curl -X POST http://localhost:26657/cosmwasm.wasm.v1.Query/SmartContractState \
  -H "Content-Type: application/json" \
  -d "{
    \"address\": \"$CONTRACT_ADDR\",
    \"query_data\": \"$QUERY_BASE64\"
  }"

7.12 Contract 间调用传递 Funds 失败

错误信息:

Error: rpc error: code = InvalidArgument desc = failed to execute message; message index: 0: insufficient funds

根因分析:
合约调用另一个合约时,未正确传递 funds 或 funds 不足。

解决方案:

// 在合约 A 中调用合约 B 并传递资金
use cosmwasm_std::{WasmMsg, Coin, to_binary};

let exec_msg = WasmMsg::Execute {
    contract_addr: "msg1...contract_b".to_string(),
    msg: to_binary(&ExecuteBMsg::Deposit {})?,
    funds: vec![Coin {
        denom: "umsg".to_string(),
        amount: Uint128::from(1000u128),
    }],
};

Ok(Response::new().add_message(exec_msg))

7.13 使用 Native BankMsg/BankMsg 失败

错误信息:

Error: rpc error: code = InvalidArgument desc = failed to execute message; message index: 0: bank module is not enabled for wasm

根因分析:
MSG Chain 在合约中禁用了原生 BankMsg(已知问题 — fail-closed 设计)。

解决方案:

// ❌ 错误: 使用原生 BankMsg
// use cosmwasm_std::BankMsg;
// let msg = BankMsg::Send { to_address, amount };
// 这会在 MSG Chain 上失败!

// ✅ 正确: 使用合约等效实现
// 通过 agent_payment_v1 或自定义合约处理转账
// 或者使用 WasmMsg::Execute 调用专门处理转账的合约

八、前端集成问题

8.1 Keplr 未检测到链

现象:
调用 window.keplr.experimentalSuggestChain(config) 无响应或报错。

根因分析:
链配置不正确;Keplr 版本过旧;RPC/REST 端点不可达。

解决方案:

// 确保链配置完全正确
const chainConfig = {
  chainId: "msg-chain-1",
  chainName: "MSG Chain",
  rpc: "http://localhost:26657",
  rest: "http://localhost:1317",
  bip44: { coinType: 118 },
  bech32Config: {
    bech32PrefixAccAddr: "msg",
    bech32PrefixAccPub: "msgpub",
    bech32PrefixValAddr: "msgvaloper",
    bech32PrefixValPub: "msgvaloperpub",
    bech32PrefixConsAddr: "msgvalcons",
    bech32PrefixConsPub: "msgvalconspub",
  },
  currencies: [{ coinDenom: "MSG", coinMinimalDenom: "umsg", coinDecimals: 18 }],
  feeCurrencies: [{ coinDenom: "MSG", coinMinimalDenom: "umsg", coinDecimals: 18, gasPriceStep: { low: 1e9, average: 1e9, high: 1e9 } }],
  stakeCurrency: { coinDenom: "MSG", coinMinimalDenom: "umsg", coinDecimals: 18 },
};

// 调试: 在浏览器控制台手动执行
console.log("Keplr installed:", !!window.keplr);
try {
  await window.keplr.experimentalSuggestChain(chainConfig);
  console.log("Chain suggested successfully");
} catch (e) {
  console.error("SuggestChain error:", e);
}

8.2 Keplr 钱包拒绝连接

错误信息:

Error: Request rejected

根因分析:
用户在 Keplr 弹窗中点击了"拒绝"。

解决方案:

// 捕获用户拒绝并显示友好提示
try {
  await window.keplr.enable("msg-chain-1");
} catch (error) {
  if (error instanceof Error && error.message.includes("rejected")) {
    // 用户主动拒绝,不要视为程序错误
    console.warn("用户取消了钱包连接");
    showToast("请授权连接钱包以继续");
    return;
  }
  throw error;
}

8.3 CosmJS 客户端连接失败

错误信息:

Error: Failed to connect to http://localhost:26657: connect ECONNREFUSED ::1:26657

根因分析:
节点未运行;RPC 地址错误;CORS 限制。

解决方案:

// 1. 确保节点已启动
// 2. 检查 RPC 地址
const RPC_URL = "http://localhost:26657";

// 3. 添加重试逻辑
async function connectWithRetry(maxRetries = 3): Promise<CosmWasmClient> {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await CosmWasmClient.connect(RPC_URL);
    } catch (err) {
      if (i === maxRetries - 1) throw err;
      console.warn(`连接失败,第 ${i + 1} 次重试...`);
      await new Promise(r => setTimeout(r, 1000 * (i + 1)));
    }
  }
  throw new Error("无法连接到 MSG Chain RPC");
}

8.4 交易广播超时

错误信息:

Error: transaction broadcast timed out

根因分析:
网络原因导致交易在超时时间内未被打包。

解决方案:

// 1. 使用 pollForTx 轮询确认
export async function pollForTx(
  client: SigningCosmWasmClient,
  txHash: string,
  maxAttempts: number = 30,
  intervalMs: number = 2000
): Promise<{ height: number; gasUsed: number; code: number }> {
  for (let i = 0; i < maxAttempts; i++) {
    try {
      const tx = await client.getTx(txHash);
      if (tx) {
        return {
          height: tx.height,
          gasUsed: tx.gasUsed,
          code: tx.code,
        };
      }
    } catch {
      // 交易尚未索引
    }
    await new Promise(resolve => setTimeout(resolve, intervalMs));
  }
  throw new Error(`交易 ${txHash} 在 ${maxAttempts * intervalMs}ms 内未确认`);
}

// 2. 使用 BROADCAST_MODE_SYNC 替代 BLOCK
const result = await client.execute(sender, contract, msg, "auto");
// 不要等待区块打包
console.log("交易已广播,哈希:", result.transactionHash);
// 后续调用 pollForTx 等待确认

8.5 错误的 Bech32 前缀

错误信息:

Error: Invalid address: invalid checksum
# 或地址以 cosmos1 开头而不是 msg1

根因分析:
创建钱包时使用了错误的地址前缀。

解决方案:

// ✅ 正确: 指定 msg 前缀
const wallet = await DirectSecp256k1HdWallet.fromMnemonic(mnemonic, {
  prefix: "msg",  // ✅ 必须为 "msg"
});

// ❌ 错误: 默认前缀可能是 "cosmos"
const wallet = await DirectSecp256k1HdWallet.fromMnemonic(mnemonic);
// 地址将错误地使用 cosmos1 前缀

8.6 umsg 与 MSG 转换错误

错误信息:

显示格式: 1000000000000000000 umsg (很难阅读)
# 或误以为 1 MSG 是 1 umsg

根因分析:
前端未正确地进行单位转换(18 位小数)。

解决方案:

const DECIMALS = 18;
const ONE_MSG = BigInt(10) ** BigInt(DECIMALS);  // 10^18

// umsg → MSG (显示用)
export function umsgToMsg(umsg: string | bigint, decimals: number = 4): string {
  const value = typeof umsg === "string" ? BigInt(umsg) : umsg;
  const divisor = BigInt(10) ** BigInt(DECIMALS - decimals);
  const display = value / divisor;
  const whole = display / BigInt(10 ** decimals);
  const frac = display % BigInt(10 ** decimals);
  return `${whole}.${frac.toString().padStart(decimals, "0")}`;
}

// MSG → umsg (链上格式)
export function msgToUmsg(msg: string): string {
  const [whole, frac = ""] = msg.split(".");
  const padded = frac.padEnd(DECIMALS, "0").slice(0, DECIMALS);
  return (BigInt(whole || "0") * ONE_MSG + BigInt(padded)).toString();
}

// 使用示例
console.log(umsgToMsg("1000000000000000000"));  // "1.0000"
console.log(msgToUmsg("1.5"));                   // "1500000000000000000"

8.7 Hex/Base64 编码错误

错误信息:

Error: Invalid hex string
# 或交易签名时编码错误

根因分析:
交易数据和签名使用了错误的编码格式。

解决方案:

import { fromHex, toHex, fromBase64, toBase64 } from "@cosmjs/encoding";

// Cosmos SDK 使用 Base64 编码交易数据
// 正确示例:
const txBytes = fromBase64(base64String);
const base64 = toBase64(txBytes);

// 哈希使用 Hex
const hashHex = toHex(txHashBytes);
const bytes = fromHex(hexString);

// 不要混淆 hex 和 base64:
// ❌ 错误
const base64FromHex = toBase64(fromHex(hexData));  // 双重转换

// ✅ 正确
// 根据 API 文档要求使用正确的编码

8.8 Keplr 签名客户端获取失败

错误信息:

Error: Cannot read properties of undefined (reading 'getOfflineSigner')

根因分析:
Keplr 未注入到 window 中(未安装或未启用)。

解决方案:

export async function getKeplrSigner(): Promise<OfflineSigner> {
  // 1. 检查 Keplr 是否存在
  if (!window.keplr) {
    throw new Error("请安装 Keplr 钱包浏览器扩展");
  }

  // 2. 启用链
  await window.keplr.enable("msg-chain-1");

  // 3. 获取签名者
  const signer = window.keplr.getOfflineSigner("msg-chain-1");

  // 4. 获取账户信息
  const accounts = await signer.getAccounts();
  if (accounts.length === 0) {
    throw new Error("Keplr 未返回账户信息");
  }

  return signer;
}

8.9 前端显示的交易 Gas 费不符

错误信息:
前端显示 Gas 费为 0.0000000000000025 MSG,用户认为太贵或太便宜。

根因分析:
单位转换错误;Gas 价格显示逻辑不正确。

解决方案:

export function formatTxFee(gasUsed: number, gasPrice: string): string {
  // gasPrice like "1000000000umsg"
  const price = parseFloat(gasPrice.replace("umsg", ""));
  const feeUmsg = BigInt(Math.ceil(gasUsed * price));
  return umsgToMsg(feeUmsg, 10) + " MSG";
}

// 显示示例
console.log(formatTxFee(100000, "1000000000umsg"));  // "0.0001 MSG" (= 1000000000 umsg)

8.10 WebSocket 连接断开

错误信息:

WebSocket is disconnected: code 1006

根因分析:
WebSocket 连接因网络问题或节点重启断开。

解决方案:

export function createReconnectingWebSocket(
  url: string,
  onMessage: (data: any) => void,
  maxRetries = 10
): WebSocket {
  let retries = 0;

  function connect() {
    const ws = new WebSocket(url);

    ws.onopen = () => {
      console.log("WebSocket 已连接");
      retries = 0;
    };

    ws.onmessage = (event) => {
      try {
        onMessage(JSON.parse(event.data));
      } catch {
        onMessage(event.data);
      }
    };

    ws.onclose = (event) => {
      if (retries < maxRetries) {
        const delay = Math.min(1000 * Math.pow(2, retries), 30000);
        console.log(`WebSocket 断开,${delay}ms 后重试...`);
        retries++;
        setTimeout(connect, delay);
      }
    };

    ws.onerror = (error) => {
      console.error("WebSocket 错误:", error);
      ws.close();
    };

    return ws;
  }

  return connect();
}

九、Agent API 问题

9.1 Agent 注册失败

错误信息:

Error: agent_id already exists
# 错误码: 11

根因分析:
指定的 agent_id 已被其他 Agent 使用。

解决方案:

// 1. 检查 agent_id 是否已存在
async function checkAgentExists(client: CosmWasmClient, registryAddress: string, agentId: string): Promise<boolean> {
  try {
    await client.queryContractSmart(registryAddress, {
      get_agent: { agent_id: agentId },
    });
    return true;
  } catch {
    return false;
  }
}

// 2. 使用唯一的 agent_id
const agentId = `agent-${Date.now()}-${Math.random().toString(36).substr(2, 6)}`;

9.2 Agent 查询超时

错误信息:

Error: query timeout
# 错误码: 6

根因分析:
节点不同步、Agent 未注册、合约地址错误。

解决方案:

// 1. 检查节点同步状态
const status = await client.queryClient.getHeight();

// 2. 设置查询超时
async function queryAgentWithTimeout(
  client: CosmWasmClient,
  registryAddress: string,
  agentId: string,
  timeoutMs: number = 5000
) {
  const timeoutPromise = new Promise((_, reject) =>
    setTimeout(() => reject(new Error("查询超时")), timeoutMs)
  );

  const queryPromise = client.queryContractSmart(registryAddress, {
    get_agent: { agent_id: agentId },
  });

  return Promise.race([queryPromise, timeoutPromise]);
}

9.3 宪章违反错误

错误信息:

Error: action violates agent constitution
# 错误码: 12

根因分析:
Agent 试图执行超出宪章允许范围的操作。

解决方案:

// 1. 先预检动作
async function preflightAction(
  client: CosmWasmClient,
  constitutionAddress: string,
  agentId: string,
  action: string,
  riskTier: string,
  amount?: string
): Promise<CheckActionResponse> {
  return client.queryContractSmart(constitutionAddress, {
    check_action: {
      agent_id: agentId,
      action,
      risk_tier: riskTier,
      amount: amount || undefined,
    },
  });
}

// 2. 根据决策结果处理
const check = await preflightAction(client, constitutionAddress, agentId, "transfer", "medium");
if (!check.allowed) {
  console.error(`动作被拒绝: ${check.reasons.join(", ")}`);
  // 需要更新宪章或选择其他动作
} else if (check.required_controls.length > 0) {
  console.log(`需要额外控制: ${check.required_controls.join(", ")}`);
  // 如 human_approval, multisig, timelock
} else {
  // 允许执行
}

9.4 支付会话过期

错误信息:

Error: payment session expired
# 错误码: 13

根因分析:
支付会话的 expiry_unix 已经过去。

解决方案:

// 创建会话时设置合理的过期时间
const expiryUnix = Math.floor(Date.now() / 1000) + 86400;  // 24小时后

// 检查会话是否即将过期
async function checkSessionExpiry(client: CosmWasmClient, paymentAddress: string, sessionId: string): Promise<boolean> {
  const session = await client.queryContractSmart(paymentAddress, {
    get_session: { session_id: sessionId },
  });
  const now = Math.floor(Date.now() / 1000);
  return session.expires_at < now;
}

9.5 会话限制超出

错误信息:

Error: payment session limit exceeded
# 错误码: 14

根因分析:
单个 Agent 或账户的并发会话数超过限制。

解决方案:

// 关闭不再使用的会话
async function closeAllExpiredSessions(
  client: SigningCosmWasmClient,
  paymentAddress: string,
  agentId: string,
  sender: string
) {
  const sessions = await client.queryContractSmart(paymentAddress, {
    get_agent_sessions: { agent_id: agentId },
  });

  for (const session of sessions.sessions) {
    if (session.status !== "active") continue;
    const now = Math.floor(Date.now() / 1000);
    if (session.expires_at < now) {
      // 关闭过期会话
      await client.execute(sender, paymentAddress, {
        close_session: {
          session_id: session.session_id,
          close_receipt_hash: crypto.createHash("sha256").update(`close:${session.session_id}:${now}`).digest("hex"),
        },
      }, "auto");
    }
  }
}

9.6 MPC 签名失败

错误信息:

Error: MPC signing failed

根因分析:
MPC 签名会话中参与方未正确提交部分签名或阈值不足。

解决方案:

// 1. 检查 MPC 会话状态
const sessionStatus = await agentApi.mpcGetSessionStatus(sessionId);
console.log(`已提交: ${sessionStatus.participants_submitted}/${sessionStatus.threshold}`);

// 2. 确保提交足够数量的部分签名
if (sessionStatus.participants_submitted < sessionStatus.threshold) {
  console.log("阈值未满足,等待更多参与方提交");
}

// 3. 聚合签名
const aggregated = await agentApi.mpcAggregateSignatures(sessionId);

9.7 Stub 端点响应

错误信息:

Response includes header X-MSG-Stub: true
# 或返回 stub 数据

根因分析:
调用了尚未完全实现的 API 端点(规划态功能)。

解决方案:

// 检测 Stub 响应
async function detectStubResponse(response: Response): Promise<boolean> {
  return response.headers.get("X-MSG-Stub") === "true";
}

// 处理 Stub 响应
async function safeApiCall<T>(apiCall: () => Promise<T>): Promise<{ data: T; isStub: boolean }> {
  try {
    const response = await apiCall();
    return { data: response, isStub: false };
  } catch (error: any) {
    if (error.isStub || error.message.includes("stub")) {
      console.warn("API 端点仅返回 stub 数据,功能尚未完全实现");
      return { data: error.response?.data, isStub: true };
    }
    throw error;
  }
}

// 已知的 Stub 端点:
// - /api/v1/agent/wallet/create
// - /api/v1/agent/wallet/transfer
// - /api/v1/agent/mpc/sign
// - /api/v1/agent/mpc/submit
// - /api/v1/agent/mpc/aggregate
// - /api/v1/agent/payment/create-session (部分)
// - /api/v1/agent/events/unsubscribe
// - /api/v1/registry/discover
// - /api/v1/registry/list
// - /api/v1/registry/register

十、DAO 与治理问题

10.1 提案提交失败 — 保证金不足

错误信息:

Error: rpc error: code = InvalidArgument desc = failed to execute message; insufficient deposit

根因分析:
提交提案时未附带足够的保证金或保证金不足。

解决方案:

# 查询最低保证金
./build/msgd query gov params --chain-id=msg-chain-1 -o json | jq '.deposit_params.min_deposit'

# 提交提案时指定足够的保证金
./build/msgd tx gov submit-proposal \
  --title "Test Proposal" \
  --description "Test" \
  --type="text" \
  --deposit "10000000000000000000umsg" \  # 10 MSG 或更多
  --from validator \
  --chain-id msg-chain-1 \
  --gas auto --gas-prices 1000000000umsg \
  -y

10.2 投票未计入

错误信息:
交易成功 (code=0) 但查询投票记录时未显示。

根因分析:
投票使用的是 DAO 合约(第二层治理)而非 Cosmos SDK gov 模块(第一层治理)。

解决方案:

// 确认使用正确的治理层

// 第一层: Cosmos SDK gov
// 使用: msgd tx gov vote <proposal-id> yes
// 或 RPC: /cosmos.gov.v1beta1.MsgVote

// 第二层: dao_governance_v1 合约
// 使用: msgd tx wasm execute <dao_address> '{"vote":{"proposal_id":1,"vote":"yes"}}'

// 检查投票记录
// 第一层:
const vote = await client.queryContractSmart("", {
  vote: { proposal_id: 1, voter: address },
}); // 通过 gov REST API

// 第二层:
const vote = await client.queryContractSmart(daoAddress, {
  get_vote: { proposal_id: 1, voter: address },
});

10.3 时间锁未到期

错误信息:

Error: DAO timelock period not finished
# 错误码: 8

根因分析:
提案通过后,DAO 合约的时间锁期间未结束。

解决方案:

// 1. 查询时间锁配置
const config = await client.queryContractSmart(daoAddress, {
  get_config: {},
});
console.log("时间锁时长:", config.timelock_duration, "秒");

// 2. 查询提案详情
const proposal = await client.queryContractSmart(daoAddress, {
  get_proposal: { proposal_id: 1 },
});
const now = Math.floor(Date.now() / 1000);
const timelockEnd = proposal.voting_end + config.timelock_duration;
console.log("时间锁到期时间:", new Date(timelockEnd * 1000).toISOString());

// 3. 等待时间锁到期后再执行
if (now < timelockEnd) {
  console.log(`还需等待 ${Math.ceil((timelockEnd - now) / 60)} 分钟`);
}

10.4 高价值交易门槛未满足

错误信息:

Error: high-value transaction threshold not met
# 错误码: 9

根因分析:
交易金额超过阈值但未满足额外审批条件。

解决方案:

// 1. 查询高价值交易阈值
const constitutionConfig = await client.queryContractSmart(constitutionAddress, {
  get_config: {},
});

// 2. 对于高价值交易,需要额外的控制措施
// 如 multi-signature、human approval、timelock

// 3. 执行前确保满足所有条件
async function executeHighValueTransfer(
  client: SigningCosmWasmClient,
  sender: string,
  amount: string,
  requiredControls: string[]
) {
  const approvals: string[] = [];
  for (const control of requiredControls) {
    if (control === "human_approval") {
      // 请求人工审批
      approvals.push(await requestHumanApproval(amount));
    }
    if (control === "multisig") {
      // 收集多签
      approvals.push(await collectMultisig(sender, amount));
    }
  }
  // 所有条件满足后执行
}

10.5 金库支出被拒

错误信息:

Error: execute spend: not enough approvals

根因分析:
金库多签支出提案未获得足够的批准签名。

解决方案:

# 1. 查询所需的签名阈值
./build/msgd query wasm contract-state smart <treasury_address> '{"get_config":{}}'

# 2. 查询当前批准情况
./build/msgd query wasm contract-state smart <treasury_address> \
  '{"get_proposal":{"proposal_id":1}}'

# 3. 让更多签名人批准
# 签名人 B:
./build/msgd tx wasm execute <treasury_address> \
  '{"approve_spend":{"proposal_id":1}}' \
  --from signer_b --chain-id msg-chain-1 --gas auto --gas-prices 1000000000umsg -y

# 签名人 C:
./build/msgd tx wasm execute <treasury_address> \
  '{"approve_spend":{"proposal_id":1}}' \
  --from signer_c --chain-id msg-chain-1 --gas auto --gas-prices 1000000000umsg -y

# 4. 达到阈值后执行
./build/msgd tx wasm execute <treasury_address> \
  '{"execute_spend":{"proposal_id":1}}' \
  --from any_signer --chain-id msg-chain-1 --gas auto --gas-prices 1000000000umsg -y

10.6 Cosmos SDK Gov 提案未通过

错误信息:

Error: proposal <id> did not meet the minimum deposit
# 或
Error: proposal <id> status is PROPOSAL_STATUS_REJECTED

根因分析:
保证金不足导致提案进入存款期后无人追加;或投票未达标。

解决方案:

# 1. 查询提案状态
./build/msgd query gov proposal <id> --chain-id msg-chain-1 -o json

# 2. 如果提案仍处于存款期,可以追加保证金
./build/msgd tx gov deposit <id> 1000000000000000000umsg \
  --from validator \
  --chain-id msg-chain-1 \
  --gas auto --gas-prices 1000000000umsg \
  -y

# 3. 查询投票结果
./build/msgd query gov tally <id> --chain-id msg-chain-1 -o json

# 4. 如果提案被拒绝,分析原因
# - 未达法定人数 (quorum: 33.4%)
# - 未达通过阈值 (threshold: 50%)
# - 否决票超过阈值 (veto: 33.4%)

十一、Gas 与费用问题

11.1 Out of Gas 错误

错误信息:

out of gas in location: WriteFlat; gasWanted: 200000, gasUsed: 200000
# 或
gas estimate error: out of gas

根因分析:
交易消耗的 Gas 超过了指定的 Gas 上限。

解决方案:

# 方法 1: 提高 Gas 上限
--gas 5000000           # 手动指定
--gas auto --gas-adjustment 2.0  # 自动估算 + 高调整因子

# 方法 2: 分步执行复杂操作(而不是一个交易做所有事)
# 将合约部署 → 实例化 → 初次调用拆为三个交易

# 方法 3: 优化合约减少 Gas 消耗
# - 减少状态写入次数
# - 使用更紧凑的数据结构
# - 避免重复读取状态

# 方法 4: 前端设置更高的默认 Gas
const fee = {
  amount: [{ denom: "umsg", amount: "3000000000000000000" }],  // 3,000,000 gas × 1e9 attoMSG
  gas: "3000000",
};

11.2 Gas 估算策略对照表

操作类型 推荐 Gas 推荐调整因子 说明
Bank Send 100,000 1.3 简单转账
Delegate 200,000 1.3 委托质押
Unbond 200,000 1.3 解委托
Withdraw Rewards 250,000 1.3 领取奖励
Store Code (小合约) 2,000,000 1.5 < 200KB WASM
Store Code (大合约) 5,000,000 1.5 > 500KB WASM
Instantiate 300,000 1.3 实例化简单合约
Execute (简单) 300,000 1.3 如 increment
Execute (复杂) 1,000,000 1.5 多步骤操作
Agent Payment 500,000 1.3 支付相关
Gov Vote 200,000 1.3 治理投票
IBC Transfer 300,000 1.3 IBC 转账

11.3 费用市场波动

现象:
交易迟迟不被打包。

根因分析:
MSG Chain 使用固定费率三档制而非 EIP-1559 动态费用机制。交易不被打包通常不是因为费用市场波动,而是节点问题。

解决方案:

# 1. 使用 high 优先级 gas 价格
--gas-prices 1000000000umsg

# 2. 检查节点的 mempool
curl -s http://localhost:26657/unconfirmed_txs | jq '.result.n_txs'
# 如果 mempool 积压过多,可能需要等待

# 3. 检查节点是否正常出块
curl -s http://localhost:26657/status | jq '.result.sync_info.latest_block_height'

11.4 余额不足但显示有余额

错误信息:

insufficient funds: insufficient account funds; 1000000umsg is required but account only has 999999umsg

根因分析:
账户余额不足(可能仅差少量 umsg);或者需要为 Gas 费用留出空间。

解决方案:

# 1. 确保账户有足够的余额支付转账金额 + Gas 费
# 假设转账 1000umsg,Gas 费 2500umsg
# 账户至少需要有 3500umsg

# 2. 查询实际余额
./build/msgd query bank balances <address>

# 3. 查询可花费余额(扣除质押中部分)
./build/msgd query bank spendable-balances <address>

# 4. 如果余额不足,从其他账户转账
./build/msgd tx bank send <from> <to> 5000000000000000000umsg \
  --from <from> --gas auto --gas-prices 1000000000umsg --chain-id msg-chain-1 -y

11.5 错误配置 minimum-gas-prices

错误信息:

Error: rpc error: code = InvalidArgument desc = insufficient fees; got: 2500umsg required: 5000umsg

根因分析:
交易指定的 Gas 价格低于节点的 minimum-gas-prices 配置。

解决方案:

# 1. 查询节点的 minimum-gas-prices
cat ~/.msgd/config/app.toml | grep minimum-gas-prices
# 应该: minimum-gas-prices = "1000000000umsg"

# 2. 交易时指定足够的 gas-prices
--gas-prices 1000000000umsg  # 等于或高于最小值

# 3. 如果节点配置了更高的最小值
sed -i 's/minimum-gas-prices = ".*"/minimum-gas-prices = "1000000000umsg"/' ~/.msgd/config/app.toml
killall msgd && ./build/msgd start

十二、Dilithium-5 相关问题

12.1 无效签名错误

错误信息:

Error: rpc error: code = InvalidArgument desc = signature verification failed: expected Dilithium-5 signature
# 错误码: 15

根因分析:
交易使用了非 Dilithium-5 的签名算法(如 Secp256k1)。MSG Chain 默认使用 Dilithium-5。

解决方案:

# 1. 检查密钥类型
./build/msgd keys show <keyname> -p --keyring-backend test | jq '.@type'
# 预期: "/cosmos.crypto.dilithium.PubKey"

# 2. 如果密钥类型错误,重新创建
./build/msgd keys add <keyname> --algo dilithium5 --keyring-backend test

# 3. 或者在 CosmJS 中指定签名算法
// @cosmjs/proto-signing 默认使用 Secp256k1
// 对于 Dilithium-5,需要使用自定义签名适配器
// 目前 Dilithium-5 的 CosmJS 支持处于 alpha 阶段
// 使用 CLI 签名替代:

12.2 密钥生成失败

错误信息:

Error: failed to generate key: unsupported key algorithm

根因分析:
未指定 --algo dilithium5 或二进制不支持 Dilithium-5。

解决方案:

# 1. 使用正确的算法参数
./build/msgd keys add mykey --algo dilithium5 --keyring-backend test

# 2. 检查 msgd 版本是否支持 Dilithium-5
./build/msgd version
grep -r "dilithium" ~/msgchain/app/  # 检查源代码

# 3. 如果二进制不支持,重新编译
make build-linux

12.3 密钥导入/导出错误

错误信息:

Error: failed to import key: invalid key format

根因分析:
导出的密钥格式与导入时预期格式不兼容。

解决方案:

# 1. 正确导出密钥(加密 ASCII 格式)
./build/msgd keys export mykey --keyring-backend test 2> mykey.asc

# 2. 正确导入密钥
./build/msgd keys import mykey-restored mykey.asc --keyring-backend test

# 3. 注意: 私钥文件 (priv_validator_key.json) 的格式与 keys export 格式不同
# priv_validator_key.json 是 Tendermint 共识密钥

12.4 签名验证失败

错误信息:

Error: rpc error: code = InvalidArgument desc = verify signature failed

根因分析:
通过 /msgchain.dilithium.v1.Query/VerifySignature 查询时参数不正确。

解决方案:

# 正确调用签名验证 API
curl -X POST http://localhost:26657 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "/msgchain.dilithium.v1.Query/VerifySignature",
    "params": {
      "public_key": "base64-encoded-pk",
      "signature": "base64-encoded-signature",
      "message": "base64-encoded-message",
      "algorithm": "Dilithium5"
    }
  }' | jq '.result'

12.5 Nonce 重复

错误信息:

Error: rpc error: code = InvalidArgument desc = duplicate nonce detected
# 错误码: 16

根因分析:
账户的 sequence number(nonce)被重复使用。通常是因为前一笔交易未确认就发送了下一笔。

解决方案:

# 1. 查询当前 sequence
./build/msgd query auth account <address> | jq '.account.sequence'

# 2. 等待前一笔交易确认后再发送
# 或使用 --sequence 手动指定正确的 nonce

# 3. 如果使用前后台并发交易,添加互斥锁
# 确保一次只发一笔交易

# 4. 使用 --broadcast-mode block 确保顺序执行
--broadcast-mode block

12.6 Dilithium-5 工具链限制

现象:
Dilithium-5 签名不可与 ECDSA 互操作;部分工具不支持 PQ 签名。

已知限制:

  1. Keplr 不支持 Dilithium-5: Keplr 目前使用 Secp256k1,无法直接签名 MSG Chain 交易
  2. CosmJS 无原生 Dilithium-5 支持: @msg-chain/sdk 处于 alpha 状态
  3. 签名大小更大: Dilithium-5 签名 4598 字节(对比 ECDSA 的 64 字节)
  4. 验证速度较慢: Dilithium-5 验证比 Ed25519 慢约 2 倍

解决方案:

// 临时方案: 通过 CLI 签名,然后通过 REST API 广播
// 1. 在 CLI 中构建并签名交易
// 2. 导出签名后的交易字节
// 3. 通过 REST API 广播

// 长期方案: 等待 @msg-chain/sdk 成熟或使用自定义签名适配器

十三、BadgerDB 存储问题

13.1 数据库损坏

错误信息:

ERROR badger: Manifest corrupted
ERROR badger: Value log corruption detected

根因分析:
非正常关机、磁盘故障、操作系统崩溃导致 BadgerDB LSM 树损坏。

解决方案:

# 1. 尝试自动恢复(重启节点)
killall msgd && ./build/msgd start 2>&1 | grep -i badger

# 2. 如果自动恢复失败,使用 BadgerDB 工具
# 安装 badger 命令行工具
go install github.com/dgraph-io/badger/v4/badger@latest

# 检查数据库状态
badger info --dir ~/.msgd/data/state.db/

# 尝试重建
badger rebuild --dir ~/.msgd/data/state.db/

# 3. 最后的方案:删除并重新同步
./build/msgd unsafe-reset-all
# 重新启动节点开始同步

13.2 磁盘空间不足

错误信息:

ERROR badger: Unable to write to value log: no space left on device

根因分析:
BadgerDB 数据目录所在磁盘已满。

解决方案:

# 1. 查看磁盘使用
df -h

# 2. 查看 MSG Chain 数据大小
du -sh ~/.msgd/data/

# 3. 启用更激进的修剪策略
sed -i 's/pruning = "default"/pruning = "everything"/' ~/.msgd/config/app.toml
# 或
sed -i 's/pruning = "default"/pruning = "custom"/' ~/.msgd/config/app.toml
echo 'pruning-keep-recent = "100"' >> ~/.msgd/config/app.toml
echo 'pruning-keep-every = "0"' >> ~/.msgd/config/app.toml
echo 'pruning-interval = "10"' >> ~/.msgd/config/app.toml

# 4. 调整 BadgerDB 日志文件大小(减少空间使用)
# 在 app.toml 中
# [store]
# value-log-file-size = 268435456  # 256MB (默认 1GB)

# 5. 设置日志轮转
sudo logrotate -f /etc/logrotate.d/msgd

13.3 数据库性能下降

现象:
节点出块变慢、交易处理延迟增加。

根因分析:
BadgerDB LSM 树层级过多需要压缩;磁盘 IO 瓶颈;内存不够。

解决方案:

# 1. 增加 BadgerDB 缓存大小
# 在 app.toml 中设置:
# [store]
# memtable-size = 134217728  # 128MB (默认 64MB)

# 2. 使用 SSD (不要使用 HDD 运行节点)

# 3. 监控 IO 性能
iostat -x 1
iotop

# 4. 定期手动触发 BadgerDB 压缩
# 通过节点日志监控压缩进度
grep -i "compaction\|LSM" ~/.msgd/log/msgd.log

# 5. 如果持续性能问题,考虑硬件升级

13.4 数据库文件碎片

现象:
数据目录占用磁盘空间远大于实际状态数据。

根因分析:
BadgerDB 的 value log 文件会随着写入操作增长,需要定期进行 value log GC。

解决方案:

# BadgerDB 会自动进行 value log GC,但可以手动触发
# 通过节点日志监控:
grep -i "vlog\|value log\|garbage" ~/.msgd/log/msgd.log

# 如果碎片严重,可以考虑重建数据库:
# 1. 停止节点
# 2. 备份数据
# 3. 使用 state-sync 重新同步
# 4. 或从快照恢复

十四、常见错误模式与模式修复

14.1 错误模式速查表 (30+ 常见错误)

错误模式 根因分类 快速修复 参见章节
节点启动 crash 配置文件/数据库 unsafe-reset-all 后重试 4.1
交易 code != 0 合约/参数 查看 raw_log 2.2
合约存储失败 WASM 体积 wasm-opt -Os 优化 5.4
实例化失败 JSON 格式 对照 Schema 检查 6.4
out of gas Gas 不足 --gas-adjustment 2.0 11.1
insufficient funds 余额不足 查询余额并充值 11.4
unauthorized 权限不足 检查 sender 7.2
not found 地址/ID 错误 确认地址正确 6.7
connection refused 节点离线 启动节点 4.1
IO timeout 网络问题 检查防火墙 3.13
wasm binary too large WASM > 800KB wasm-opt -Oz 5.4
genesis validation error 创世文件 重新 init+collect-gentxs 4.9
keplr not detecting 链配置 检查 bech32/gas 配置 8.1
wrong bech32 prefix 钱包前缀 使用 msg 前缀 8.5
sequence mismatch Nonce 冲突 等待前一笔交易 12.5
signature verification failed 算法错误 使用 --algo dilithium5 12.1
dilithium key type mismatch 密钥类型 重新创建 dilithium5 密钥 12.2
contract panicked 合约代码 检查 unwrap() 7.3
stub response API 未实现 检查 X-MSG-Stub 头 9.7
DAO timelock 时间锁 等待到期 10.3
constitution violation 宪章限制 预检动作 9.3
session expired 支付过期 重新创建会话 9.4
session limit exceeded 会话数超限 关闭旧会话 9.5
validator jailed 验证者被禁 tx slashing unjail 4.15
state sync failed 同步配置 更新 trust_height/hash 4.5
badgerdb corrupted 数据库损坏 自动恢复或重置 13.1
disk space full 磁盘不足 清理日志/修剪状态 13.2
cargo build OOM 内存不足 CARGO_BUILD_JOBS=2 3.10
wasm-opt not found 工具缺失 cargo install wasm-opt 3.3
CORS blocked 跨域限制 cors_allowed_origins = ["*"] 3.14
Agent already registered 重复注册 使用不同的 agent_id 9.1
duplicate nonce 重放检测 使用正确的 sequence 12.5

14.2 快速诊断决策树

问题: 交易失败
│
├─ 广播阶段失败?
│   ├─ connection refused → 节点是否运行? → 启动节点
│   ├─ timeout → 检查网络+节点同步状态 → 等待同步完成
│   └─ insufficient fees → 检查 gas-prices ≥ minimum-gas-prices
│
├─ 执行阶段失败 (code != 0)?
│   ├─ code=4 → INSUFFICIENT_FUNDS → 查询余额,充值
│   ├─ code=3 → UNAUTHORIZED → 检查 sender 身份
│   ├─ code=5 → CONTRACT_EXECUTION_FAILED → 查看 raw_log
│   ├─ code=7 → INVALID_PARAMETER → 检查消息格式
│   ├─ code=12 → CONSTITUTION_VIOLATION → 查询宪章规则
│   ├─ code=15 → INVALID_SIGNATURE → 检查 Dilithium-5 密钥
│   └─ out of gas → 增加 gas / gas-adjustment
│
└─ 查询结果不对?
    ├─ 返回空 → 节点同步? 查询键正确? 合约已初始化?
    ├─ 格式错误 → 对照 Schema 检查 JSON
    └─ 数据不对 → 交易是否真的成功? (tx code==0?)

14.3 调试核对清单

每次遇到问题时,先确认以下项目:

☐ 1. 链配置
    ☐ Chain ID = "msg-chain-1"?
    ☐ Bech32 前缀 = "msg"?
    ☐ Gas 价格 = 1000000000umsg (或 >= minimum-gas-prices)?

☐ 2. 节点状态
    ☐ 节点运行中? (curl localhost:26657/status)
    ☐ 节点已同步? (catching_up = false)
    ☐ 区块高度在增长? (5 秒一个块)

☐ 3. 账户状态
    ☐ 账户地址以 msg1 开头?
    ☐ 余额足够? (余额 > 交易金额 + 费用)
    ☐ 密钥类型是 Dilithium-5? (@type = /cosmos.crypto.dilithium.PubKey)

☐ 4. 合约
    ☐ Code ID 存在? (query wasm list-code)
    ☐ 合约地址正确? (以 msg1 开头)
    ☐ JSON 消息符合 Schema? (cargo schema)

☐ 5. 交易日志
    ☐ 查看 raw_log 中的具体错误
    ☐ 检查 events 是否包含预期事件
    ☐ 检查 gas_used 是否接近 gas_wanted

☐ 6. 前端
    ☐ Keplr 已安装并连接?
    ☐ RPC/REST 端点可访问?
    ☐ 单位转换正确? (18 位小数)

十五、调试工具与脚本

15.1 日志级别配置

# 启动时设置日志级别
./build/msgd start --log_level="debug"                    # 详细调试
./build/msgd start --log_level="info"                     # 普通信息(默认)
./build/msgd start --log_level="error"                    # 仅错误

# 模块级别日志过滤
./build/msgd start --log_level="state:info,p2p:debug,rpc:warn,*:error"

# 持久化日志到文件
./build/msgd start 2>&1 | tee -a ~/.msgd/logs/msgd-$(date +%Y%m%d).log

15.2 事件监听调试

# 通过 WebSocket 订阅事件
# 使用 wscat 工具
npm install -g wscat
wscat -c ws://localhost:26657/websocket

# 成功后发送订阅消息
> {"jsonrpc":"2.0","method":"subscribe","id":1,"params":{"query":"tm.event='Tx'"}}

# 监控特定合约的事件
> {"jsonrpc":"2.0","method":"subscribe","id":2,"params":{"query":"wasm.contract_address='msg1...' AND wasm.action='increment'"}}

# 通过 REST API 查询交易事件
./build/msgd query txs --events 'wasm.action=increment' --chain-id msg-chain-1

15.3 状态转储与分析

# 导出合约全部状态
./build/msgd query wasm contract-state all <contract_addr> -o json > contract_state.json

# 导出特定键的原始状态
./build/msgd query wasm contract-state raw <contract_addr> <hex-key>

# 导出区块链状态快照(用于分析)
# 注意: 需要停止节点
killall msgd
cp -r ~/.msgd/data/state.db /tmp/state_snapshot/

# 使用 BadgerDB 工具读取状态
go install github.com/dgraph-io/badger/v4/badger@latest
badger dump --dir /tmp/state_snapshot/

15.4 交易模拟

# 使用 --dry-run 模拟执行(不广播)
./build/msgd tx wasm execute <contract> '{"increment": {}}' \
  --from validator \
  --gas auto \
  --gas-prices 1000000000umsg \
  --chain-id msg-chain-1 \
  --dry-run \
  --node tcp://localhost:26657

# 使用 --generate-only 生成未签名的交易体
./build/msgd tx wasm execute <contract> '{"increment": {}}' \
  --from validator \
  --gas auto \
  --gas-prices 1000000000umsg \
  --chain-id msg-chain-1 \
  --generate-only \
  > unsigned_tx.json

15.5 完整调试脚本

#!/bin/bash
# debug.sh — MSG Chain 全能调试脚本
# 使用方法: bash debug.sh [contract_address]

set -e

RPC="http://localhost:26657"
CHAIN_ID="msg-chain-1"
CONTRACT_ADDR=${1:-""}

echo "═══════════════════════════════════════════"
echo "  MSG Chain 全面调试脚本"
echo "═══════════════════════════════════════════"

# 1. 节点基础状态
echo ""
echo "── 1. 节点状态 ──"
if curl -s "$RPC/status" > /dev/null 2>&1; then
  STATUS=$(curl -s "$RPC/status" | jq '.result.sync_info')
  HEIGHT=$(echo "$STATUS" | jq -r '.latest_block_height')
  CATCHING_UP=$(echo "$STATUS" | jq -r '.catching_up')
  echo "  区块高度: $HEIGHT"
  echo "  同步状态: $([ "$CATCHING_UP" = "true" ] && echo "同步中" || echo "已同步")"
  echo "  Chain ID: $(curl -s "$RPC/status" | jq -r '.result.node_info.network')"
else
  echo "  ❌ 节点未运行!"
  echo "  请执行: ./build/msgd start"
  exit 1
fi

# 2. 网络状态
echo ""
echo "── 2. 网络状态 ──"
PEERS=$(curl -s "$RPC/net_info" | jq -r '.result.n_peers' 2>/dev/null)
echo "  连接对等节点数: ${PEERS:-0}"

# 3. REST API
echo ""
echo "── 3. REST API ──"
if curl -s "http://localhost:1317/cosmos/base/tendermint/v1beta1/node_info" > /dev/null 2>&1; then
  echo "  REST API: ✅"
else
  echo "  REST API: ❌ (检查 app.toml [api] 配置)"
fi

# 4. 合约状态(如果指定了合约地址)
if [ -n "$CONTRACT_ADDR" ]; then
  echo ""
  echo "── 4. 合约信息 ──"
  CONTRACT_INFO=$(curl -s "http://localhost:1317/cosmwasm/wasm/v1/contract/$CONTRACT_ADDR" 2>/dev/null)
  echo "  合约信息: $(echo "$CONTRACT_INFO" | jq -c '.contract_info | {code_id, creator, label}' 2>/dev/null || echo '无法获取')"

  # 尝试智能查询
  echo ""
  echo "── 5. 合约状态查询 ──"
  TRY_QUERIES='{"get_count":{}} {"get_config":{}} {"info":{}}'
  for Q in $TRY_QUERIES; do
    RESULT=$(./build/msgd query wasm contract-state smart "$CONTRACT_ADDR" "$Q" --node "$RPC" -o json 2>/dev/null)
    if [ $? -eq 0 ] && [ -n "$RESULT" ]; then
      echo "  Query $Q → $(echo "$RESULT" | jq -c '.data' 2>/dev/null)"
    fi
  done
fi

# 5. 密钥检查
echo ""
echo "── 6. 密钥检查 ──"
if command -v msgd &> /dev/null; then
  for KEY in $(msgd keys list --keyring-backend test -o json 2>/dev/null | jq -r '.[].name' 2>/dev/null); do
    KEY_TYPE=$(msgd keys show "$KEY" -p --keyring-backend test 2>/dev/null | jq -r '.["@type"]' 2>/dev/null)
    KEY_ADDR=$(msgd keys show "$KEY" -a --keyring-backend test 2>/dev/null)
    echo "  $KEY: $KEY_ADDR ($KEY_TYPE)"
  done
fi

echo ""
echo "═══════════════════════════════════════════"
echo "  调试完成"
echo "═══════════════════════════════════════════"

15.6 自定义调试端点

# 检查 BadgerDB 状态
curl -s http://localhost:26657/status | jq '.result'

# 获取节点详细信息
curl -s http://localhost:26657/abci_info | jq '.result'

# 查询共识参数
./build/msgd query consensus params --node tcp://localhost:26657 -o json

# 查询账户详情(含 sequence/account_number)
./build/msgd query auth account <address> --node tcp://localhost:26657 -o json

十六、社区求助指南

16.1 求助前准备清单

在向社区提问之前,请确保已完成以下检查:

❏ 已阅读本文档相关章节
❏ 已运行 debug.sh 脚本收集信息
❏ 已查看交易 raw_log (如果是交易问题)
❏ 已检查节点同步状态 (catching_up)
❏ 已确认账户余额充足
❏ 已在测试环境复现问题
❏ 已搜索 GitHub Issues 中是否有类似问题

16.2 Bug 报告模板

## 环境信息
- MSG Chain 版本: [msgd version 输出]
- Go 版本: [go version]
- Rust 版本: [rustc --version]
- CosmWasm 版本: [Cargo.toml 中的 cosmwasm-std 版本]
- 操作系统: [Ubuntu 22.04 / macOS 14.x / 其他]
- 部署方式: [本地开发 / Docker / 云服务器]

## 问题描述
[清晰简洁地描述问题]

## 复现步骤
1. [第一步]
2. [第二步]
3. [第三步]

## 实际行为
[实际发生的结果]

## 预期行为
[期望发生的结果]

## 错误日志

[粘贴完整的错误日志或 raw_log]


## 配置信息

[粘贴相关配置,注意隐藏私钥和助记词]


## 已尝试的解决方案
- [尝试过的方法 1]
- [尝试过的方法 2]

## 附件
[如有必要,附上截图或测试合约代码]

16.3 错误日志模板

{
  "timestamp": "2026-07-05T12:00:00Z",
  "node_info": {
    "version": "msg-chain-1",
    "block_height": 12345,
    "catching_up": false
  },
  "error": {
    "code": 4,
    "name": "INSUFFICIENT_FUNDS",
    "message": "insufficient funds"
  },
  "tx_info": {
    "hash": "0xABCDEF1234567890",
    "sender": "msg1...",
    "contract": "msg1...",
    "gas_wanted": 200000,
    "gas_used": 0
  },
  "raw_log": "failed to execute message; insufficient funds: insufficient account funds; 1000000umsg is required but account only has 500000umsg",
  "chain_config": {
    "chain_id": "msg-chain-1",
    "bech32_prefix": "msg",
    "gas_price": "1000000000umsg"
  }
}

16.4 最小可复现示例指南

当需要社区帮助调试合约问题时,提供最小可复现示例:

// 最小可复现示例 contract.rs
// 去掉所有业务逻辑,保留触发问题的代码

use cosmwasm_std::{
    entry_point, to_binary, Binary, Deps, DepsMut, Env,
    MessageInfo, Response, StdResult,
};

#[entry_point]
pub fn execute(
    deps: DepsMut,
    _env: Env,
    info: MessageInfo,
    msg: ExecuteMsg,
) -> StdResult<Response> {
    match msg {
        ExecuteMsg::ProblematicOp {} => {
            // 这里是有问题的代码
            // 请社区帮助调试
            Ok(Response::new())
        }
    }
}
# 部署最小合约并提供完整的复现命令
CONTRACT=msg1...
./build/msgd tx wasm execute $CONTRACT '{"problematic_op": {}}' \
  --from validator \
  --gas auto --gas-prices 1000000000umsg \
  --chain-id msg-chain-1 -y

16.5 社区资源

资源 链接 用途
MSG Chain 官网 https://msgchain.org 文档和公告
GitHub 仓库 https://github.com/msgchain 源代码和 Issues
CosmWasm 文档 https://docs.cosmwasm.com 合约开发参考
CosmJS 文档 https://cosmwasm.github.io/cosmjs 前端 SDK 参考
Cosmos SDK 文档 https://docs.cosmos.network 链底层概念
Keplr 文档 https://docs.keplr.app 钱包集成参考
Rust 文档 https://doc.rust-lang.org Rust 语言参考

本文档持续更新中。发现新的错误模式或解决方案,请提交 PR 或 Issue 到 GitHub。
所有代码示例基于 MSG Chain 实际配置,适用于 msg-chain-1 测试网/本地开发环境。