Web3 生产联调
受众:开发者 摘要:Web3 生产联调专题:RPC 故障切换 / 私钥安全 / 资金归集 / 监控告警。
本文档说明 Web3 能力接入真实 RPC 节点后的配置、验证和排查方式。
Web3 当前定位是:
- 钱包验签
- Typed Data 验签
- 只读 RPC
- 合约只读调用
- Token / NFT 查询
- 代币价格查询和 Token 元数据缓存
- 事件扫描
- Web3 支付确认、人工复核和受控结算
- 原生币 / Token 写交易、批量转账和资金归集
高风险能力边界:
- 私钥托管
- 签名和广播只在受控 API 内执行,私钥只作为单次请求参数参与签名,不落库、不写日志。
- 批量转账、资金归集和支付结算必须配合权限、审计、限额、脱敏、幂等和失败处理。
- 自动结算需要经过 dry-run 计划、人工复核或明确配置的超时自动处理策略,不允许绕过状态机直接改订单。
生产开启写交易能力前,先完成小额联调和回滚预案,不要直接使用主账户大额资金测试。
配置优先级
Web3 配置遵循 Config starter 统一规则:
数据库配置 / Config provider
-> application.yml / application-*.yml / 环境变量
-> 默认值数据库配置适合生产运行期调整 RPC、超时、默认链和支付收款参数;本地文件适合开发默认值和环境模板。
建议生产配置保留在后台配置或部署平台密钥中,不要把商用 RPC key、私有节点地址或支付收款配置提交到 Git。
基础配置
最小生产配置示例:
spring:
open:
web3:
enabled: true
default-chain: bsc
config:
enabled: true
prefix: spring.open.web3
chains:
bsc:
enabled: true
chain-type: evm
chain-id: 56
rpc-urls:
- https://bsc-dataseed.bnbchain.org
- https://bsc-dataseed1.bnbchain.org
private-rpc-urls:
- https://your-private-bsc-rpc-a.example.com
- https://your-private-bsc-rpc-b.example.com
native-currency: BNB
block-explorer-url: https://bscscan.com
connect-timeout: 5s
read-timeout: 15s
ethereum:
enabled: true
chain-type: evm
chain-id: 1
rpc-urls:
- https://ethereum-rpc.publicnode.com
private-rpc-urls:
- https://your-private-ethereum-rpc-a.example.com
- https://your-private-ethereum-rpc-b.example.com
native-currency: ETH
block-explorer-url: https://etherscan.io
connect-timeout: 5s
read-timeout: 15s
price:
enabled: true
default-provider: pancake-v2
fallback-providers:
- pancake-v2-pool
providers:
pancake-v2:
enabled: true
provider: pancake-v2
chain-name: bsc
router-address: 0x10ED43C718714eb63d5aA57B78B54704E256024E
quote-token-address: 0x55d398326f99059fF775485246999027B3197955
quote-token-symbol: USDT
quote-token-decimals: 18
base-token-decimals: 18
default-amount-raw: 1000000000000000000
pancake-v2-pool:
enabled: true
provider: pancake-v2-pool
chain-name: bsc
factory-address: 0xcA143Ce32Fe78f1f7019d7d551a6402fC5350c73
pair-address:
quote-token-address: 0x55d398326f99059fF775485246999027B3197955
quote-token-symbol: USDT
quote-token-decimals: 18
base-token-decimals: 18
default-amount-raw: 1000000000000000000
metadata-cache:
enabled: true
ttl: 10m
max-size: 2048等价后台配置 key:
spring.open.web3.enabled=true
spring.open.web3.default-chain=bsc
spring.open.web3.chains.bsc.enabled=true
spring.open.web3.chains.bsc.chain-type=evm
spring.open.web3.chains.bsc.chain-id=56
spring.open.web3.chains.bsc.rpc-urls=https://bsc-dataseed.bnbchain.org,https://bsc-dataseed1.bnbchain.org
spring.open.web3.chains.bsc.private-rpc-urls=https://your-private-bsc-rpc-a.example.com,https://your-private-bsc-rpc-b.example.com
spring.open.web3.chains.bsc.native-currency=BNB
spring.open.web3.chains.bsc.block-explorer-url=https://bscscan.com
spring.open.web3.chains.bsc.connect-timeout=5s
spring.open.web3.chains.bsc.read-timeout=15s
spring.open.web3.price.default-provider=pancake-v2
spring.open.web3.price.fallback-providers=pancake-v2-pool
spring.open.web3.price.providers.pancake-v2.chain-name=bsc
spring.open.web3.price.providers.pancake-v2.router-address=0x10ED43C718714eb63d5aA57B78B54704E256024E
spring.open.web3.price.providers.pancake-v2.quote-token-address=0x55d398326f99059fF775485246999027B3197955
spring.open.web3.price.providers.pancake-v2-pool.chain-name=bsc
spring.open.web3.price.providers.pancake-v2-pool.factory-address=0xcA143Ce32Fe78f1f7019d7d551a6402fC5350c73
spring.open.web3.price.providers.pancake-v2-pool.quote-token-address=0x55d398326f99059fF775485246999027B3197955
spring.open.web3.metadata-cache.ttl=10m
spring.open.web3.metadata-cache.max-size=2048RPC 选择
公共 RPC 只适合本地体验和临时调试,不建议作为生产默认节点。
生产建议:
- 使用稳定的服务商 RPC 或自建节点。
- 为 BSC、Ethereum 等主网配置独立的 RPC key 和限流策略。
- 历史事件扫描需要确认节点是否支持目标区块范围;较早历史日志通常需要 archive 能力或服务商历史日志支持。
- 不同链必须配置正确的
chain-id,启动后通过诊断接口校验。 - 对事件扫描和后台页面查询设置合理频率,避免被 RPC 服务商限流。
- 如果启用默认
pancake-v2价格查询,需确保 BSC 链已启用且 RPC 能访问 PancakeSwap V2 Router;pancake-v2-pool降级 Provider 还需要访问 Factory 和 Pair。两者都只读,不会触发 swap 或交易广播。 - Token 元数据缓存只缓存静态信息,生产可按 Token 数量调大
metadata-cache.max-size;余额、授权和交易状态不会被缓存。
当前 Web3 starter 使用 HTTP JSON-RPC 调用模型;如果后续需要 WebSocket 订阅、pending 交易监听或推送式事件流,应作为独立 Provider 能力设计。
启动后自检
先确认链配置是否被应用读取:
GET /api/v1/money/web3/chains再检查健康摘要:
GET /api/v1/money/web3/chains/health/summary查看生产诊断项:
GET /api/v1/money/web3/chains/diagnostics
GET /api/v1/money/web3/chains/{chainName}/diagnostics单链健康检查:
GET /api/v1/money/web3/chains/{chainName}/health常用下钻排查:
GET /api/v1/money/web3/chains/{chainName}/accounts/{address}
GET /api/v1/money/web3/chains/{chainName}/transactions/{hash}
GET /api/v1/money/web3/chains/{chainName}/transactions/{hash}/receipt
GET /api/v1/money/web3/chains/{chainName}/transactions/{hash}/confirmation
POST /api/v1/money/web3/chains/{chainName}/event-logs/search
POST /api/v1/money/web3/chains/{chainName}/calls/raw
POST /api/v1/money/web3/chains/{chainName}/gas-estimates
POST /api/v1/money/web3/chains/{chainName}/contract-callsWeb3 生产联调以 Money Web3 后台只读 API 和正式运维页面为准;当前运维路径仍沿用 /api/v1/money/web3/**,不再通过独立 samples 调试页面验证。
RPC Smoke 手动检查
上线前可以先检查真实 RPC 是否可连、链 ID 是否正确、区块高度是否可读取。检查只调用 eth_chainId 和 eth_blockNumber,不会签名、不会广播交易。
RPC_URL="https://bsc-dataseed.bnbchain.org"
curl -fsS -H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"eth_chainId","params":[]}' \
"$RPC_URL"
curl -fsS -H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"eth_blockNumber","params":[]}' \
"$RPC_URL"示例中的 BSC 公共节点和目标链 ID:
RPC URL: https://bsc-dataseed.bnbchain.org
Expected chainId: 0x38生产建议显式传入多个节点,多个 URL 使用英文半角逗号分隔:
for RPC_URL in https://rpc-a.example.com https://rpc-b.example.com; do
echo "Checking $RPC_URL"
curl -fsS --connect-timeout 10 --max-time 10 \
-H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"eth_chainId","params":[]}' \
"$RPC_URL"
curl -fsS --connect-timeout 10 --max-time 10 \
-H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"eth_blockNumber","params":[]}' \
"$RPC_URL"
done如果只是临时排查,希望至少一个节点可用即可,先分别执行上述只读请求,再按返回结果判断是否切换备用节点。
发版或生产巡检建议确认配置中的每个节点都可用,并核对返回的 chainId 与目标链一致。
生产签名网关
写交易、跨链桥放款 / 退款、批量转账和资金归集统一经过 Web3TransactionSigner。默认 local signer 只用于兼容本地开发和已有部署;生产真实资金流推荐使用 external-http signer,把 KMS、HSM、Vault Transit 或机构托管签名服务封装在部署侧内部签名网关之后。
推荐配置:
spring.open.web3.signer.provider=external-http
spring.open.web3.signer.external-http.endpoint=https://signer.internal.example.com/web3/sign
spring.open.web3.signer.external-http.authorization-header-name=Authorization
spring.open.web3.signer.external-http.authorization-value=Bearer ${WEB3_SIGNER_TOKEN}
spring.open.web3.signer.external-http.timeout=10s签名网关 contract:
- 请求只包含规范化交易签名材料:链名、
chainId、from、to、value、data、nonce、gasPrice、gasLimit。 - 网关返回已签名原始交易
rawTransaction和可选transactionHash/ 元数据。 - 框架会校验返回的
from、to、chainId、value、nonce、gas 等字段与请求一致,避免网关误签其他交易。 - 签名网关凭据只通过环境变量、K8s Secret、Vault Agent 或云 Secret Manager 注入,不进入 Git、配置中心明文、日志或审计扩展 JSON。
- 签名失败、超时或返回字段不一致时,本次放款 / 退款保持失败或留人工处理,不自动切回本地私钥 signer。
仍使用本地私钥 signer 的生产部署必须满足:
- 金库私钥只经环境变量 / 外部 secret 注入;确需配置中心入库时按 Web3 私钥本地加密约定使用
enc:v1:密文信封和环境变量主密钥。 spring.open.money.web3.bridge.auto-payout.enabled=true时,只允许通过金额、风控、访问策略、签名配置和目标链出金钱包余额门控的安全单自动放款。- 需要严格人工审核时,显式设置
spring.open.money.web3.bridge.auto-payout.enabled=false。 - 私钥、签名中间值和 raw signed transaction 不写日志、不写业务表;审计只记录订单、出金钱包、金额、nonce 和交易哈希。
真实 KMS / HSM / Vault signer、真实 RPC 服务商、真实出金钱包和测试链 web3-bridge-testchain-smoke 属于外部 Provider 验收,不应在缺少真实凭据和真实链环境时声明完成。发版前可用 ./scripts/release web3-provider-acceptance --chain <chain> --rpc-provider <provider> 生成只读验收记录模板;记录填写后用 ./scripts/release web3-provider-gate --record <file> 校验真实链、签名、充值 / 提现 / Bridge、nonce / replay 和扫描 checkpoint 证据完整性。脚本不会连接 RPC、签名、广播交易或修改数据库。
curl 示例
TOKEN=your-token
BASE_URL=http://localhost:8000
curl -H "Authorization: Bearer ${TOKEN}" \
"${BASE_URL}/api/v1/money/web3/chains"
curl -H "Authorization: Bearer ${TOKEN}" \
"${BASE_URL}/api/v1/money/web3/chains/bsc/health"
curl -H "Authorization: Bearer ${TOKEN}" \
"${BASE_URL}/api/v1/money/web3/chains/bsc/accounts/0x0000000000000000000000000000000000000000"事件日志搜索:
curl -X POST \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"fromBlock": "latest",
"toBlock": "latest",
"addresses": ["0x0000000000000000000000000000000000000000"],
"topics": []
}' \
"${BASE_URL}/api/v1/money/web3/chains/bsc/event-logs/search"ABI 只读调用:
curl -X POST \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"contractAddress": "0x0000000000000000000000000000000000000000",
"functionName": "balanceOf",
"inputs": [
{
"type": "address",
"value": "0x0000000000000000000000000000000000000000"
}
],
"outputs": ["uint256"]
}' \
"${BASE_URL}/api/v1/money/web3/chains/bsc/contract-calls"事件扫描联调
事件扫描使用检查点模型:
money_web3_scan_checkpoint
money_web3_scan_log联调步骤:
- 确认 RPC 健康和链 ID 匹配。
- 确认业务模块已注册
Web3EventScanner。 - 新增检查点,
scannerName必须与业务扫描器名称一致。 - 设置合理的
fromBlock、toBlock、确认数和区块跨度。 - 手动触发单个检查点扫描。
- 查看扫描日志、失败原因和业务表幂等落库结果。
手动触发:
POST /api/v1/admin/web3/scans/checkpoints/{id}/trigger批量触发:
POST /api/v1/admin/web3/scans/trigger注意:
- 不要直接从创世区块开始扫公共 RPC。
- 历史扫描优先分批推进。
blockRangeSize太大容易被节点拒绝或超时。- 业务 handler 必须靠唯一索引或幂等 key 防重复。
- 扫描任务失败后先看
money_web3_scan_log,不要盲目重试大范围任务。
持续扫描、补偿任务、失败重跑和通知边界见 Web3 链上事件补偿任务。
Web3 支付联调
当前 Web3 支付提供:
- 创建链上收款上下文
- 查询交易确认状态
- ERC-20 Transfer 事件匹配
- 批量只读确认
- 结算 dry-run 计划
- 人工复核指纹
- 复核日志留痕
- 显式结算执行
- 复核超时自动处理
- 自动结算失败通知
- 人工重试入口
结算执行会通过订单状态条件更新保护幂等,不会把已成功、已退款、已关闭等终态订单回退。
联调建议:
- 先用普通 Web3 交易确认接口确认交易可查。
- 再用 Web3 支付只读确认接口读取本地订单和链上状态。
- 使用结算 dry-run 计划生成建议动作。
- 后台人工复核
reviewFingerprint。 - 小额执行显式结算,检查订单、流水、复核日志和通知记录。
- 开启超时自动处理前,确认自动动作、批量数量、失败通知和人工重试入口。
自动结算的状态机、幂等、链重组和人工复核边界见 Web3 支付自动结算设计。
常见问题
| 现象 | 常见原因 | 处理方式 |
|---|---|---|
| 链配置清单为空 | 链未启用、配置前缀错误、数据库配置未生效 | 检查 spring.open.web3.enabled 和 spring.open.web3.chains.*.enabled |
| 健康检查失败 | RPC 不通、DNS 失败、服务商限流、超时过短 | 更换节点,调大 read-timeout,检查网络和服务商面板 |
| 链 ID 不匹配 | RPC 指向了错误网络 | 修改 private-rpc-urls / rpc-urls 或 chain-id,不要忽略该错误 |
| 事件日志查不到 | 区块范围错误、合约地址错误、topic 错误、节点不支持历史日志 | 先查 latest,再缩小范围;历史日志确认 archive 能力 |
| 交易确认数不足 | 交易刚上链或链头落后 | 等待更多区块,或确认 RPC 是否同步落后 |
| Token 余额看起来很大 | 返回的是最小单位原始值 | 使用 Token decimals 做展示换算,不要直接当业务金额 |
| ABI 调用失败 | 方法名、输入类型、输出类型或合约地址错误 | 先用区块浏览器 ABI 对照,再用 raw eth_call 排查 |
| 扫描任务反复失败 | 区块跨度过大、RPC 限流、业务 handler 抛错 | 降低跨度,查看扫描日志,先修业务幂等与异常处理 |
| 页面返回未登录或无权限 | 未填写 Bearer Token 或缺少 money:web3:chain:view | 登录后复制 token,确认 RBAC 权限 |
上线检查清单
- [ ] 生产 RPC 不使用公共默认节点。
- [ ] 每条链都配置了正确的
chain-id。 - [ ]
block-explorer-url已配置,方便后台跳转排查。 - [ ] RPC key 和服务商地址不提交到 Git。
- [ ] 数据库配置覆盖已验证。
- [ ]
/api/v1/money/web3/chains/diagnostics全部必需检查项通过。 - [ ] 生产写交易已选择签名路线:
external-http签名网关、厂商 KMS/HSM/Vault signer,或经风险确认的本地 signer。 - [ ] 金库私钥注入方式已核对:不进 Git、不进
application.yml明文、不进配置中心明文;配置中心入库时只存enc:v1:密文信封。 - [ ] 自动放款门控已核对:金额、风控、访问策略、签名配置和目标链出金钱包余额门控均生效;严格人工审核部署已显式关闭
spring.open.money.web3.bridge.auto-payout.enabled。 - [ ] 签名网关 / KMS / HSM / Vault 的失败、超时和返回字段不一致场景已验证不会切回本地私钥 signer。
- [ ] 测试链
web3-bridge-testchain-smoke已完成签名 → 广播 → 确认的小额端到端记录。 - [ ] 事件扫描检查点使用合理区块跨度。
- [ ] 业务事件落库有唯一索引或幂等 key。
- [ ] Web3 支付自动处理策略、批量数量、失败通知和人工重试入口已确认。
- [ ] 写交易、批量转账和资金归集已完成小额联调,私钥没有落库或进入日志。
- [ ] 生产后台页面不会高频轮询链健康、交易或事件日志接口。