MSG Chain 开发排错大全 — 终极调试百科全书
数据来源:MSG Chain 代码库核实
主网状态: No-Go — 当前 MSGChain 主网裁决为 No-Go,以下内容反映代码实际状态,不代表生产可用。
目录
- 排错总览
- 错误码大全
- 环境搭建问题
- 节点运行问题
- 合约编译问题
- 合约部署问题
- 合约交互问题
- 前端集成问题
- Agent API问题
- DAO与治理问题
- Gas与费用问题
- Dilithium-5相关问题
- BadgerDB存储问题
- 常见错误模式与模式修复
- 调试工具与脚本
- 社区求助指南
一、排错总览
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/
预防:
- 始终使用
killall msgd或systemctl stop msgd正常关闭节点 - 使用 UPS 防止突然断电
- 配置 BadgerDB sync-writes = true(降低性能但提高安全性)
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 签名。
已知限制:
- Keplr 不支持 Dilithium-5: Keplr 目前使用 Secp256k1,无法直接签名 MSG Chain 交易
- CosmJS 无原生 Dilithium-5 支持:
@msg-chain/sdk处于 alpha 状态 - 签名大小更大: Dilithium-5 签名 4598 字节(对比 ECDSA 的 64 字节)
- 验证速度较慢: 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 测试网/本地开发环境。
