模拟像在某个节点的状态快照上做一次彩排:程序能否执行、日志说什么、预计消耗多少计算单元。它不会占用链上账户,也无法冻结blockhash、余额或价格。正式交易抵达领导者前,任何依赖状态都可能变化,所以模拟成功只是排除一部分确定性错误。
模拟参数会改变结论
sigVerify=true会校验交易签名;replaceRecentBlockhash=true让节点替换过期blockhash便于调试,两者不能同时开启。commitment决定模拟读取的状态层级,accounts参数可返回指定账户变化。记录这些参数,否则团队难以复现“我的模拟是成功的”。
| 阶段 | 产生什么 | 不保证什么 |
|---|---|---|
| simulateTransaction | err、logs、unitsConsumed、账户快照 | 不写账本、不保留状态 |
| sendTransaction | 交易签名 | 不保证已打包或成功 |
| signature status | processed/confirmed/finalized与err | 需继续处理过期和重组 |
状态竞争是主要差异来源
模拟后到正式执行前,PDA可能已初始化、订单可能成交、账户余额可能变化、ALT可能失效,或同一nonce被其他交易消费。RPC节点与领导者也可能处在不同fork。对价格、序号和唯一账户敏感的指令,应在程序内再次检查条件并让不满足时安全revert。
模拟能证明和不能证明的事
- simulateTransaction在节点上模拟执行并可返回err、logs、unitsConsumed及指定账户状态,不会把交易写入账本。
- sigVerify和replaceRecentBlockhash不能同时为true;后者允许用节点替换blockhash以便模拟过期消息。
- sendTransaction返回签名只表示节点接受提交;blockhash过期、状态竞争、领导者切换或后续执行错误仍可能导致交易未确认。
从模拟到确认的流水线
- 记录RPC端点、commitment和模拟参数
- 检查err、logs与unitsConsumed而非只看HTTP 200
- 发送前刷新blockhash并核对全部账户
- 提交后持续查询signature status
- 业务端使用幂等键防止重复处理
发送返回签名后还没结束
sendTransaction的成功响应意味着节点接受了序列化交易并返回首个签名,不等于账本确认。客户端要轮询签名状态,区分执行err、blockhash过期、节点丢弃和持续未打包;必要时用相同消息策略重新构建,而不是盲目重复签名造成双重业务操作。
skipPreflight不能修复交易
提高skipPreflight不会让失败交易变正确,它只跳过发送节点的预检;模拟时替换blockhash也不会自动修改原签名交易。调试应保留原始message、账户快照和日志,而不是只截一张“simulation succeeded”界面。
大量账户的v0交易先按ALT地址查找表还原;离线签名和过期问题可看Durable Nonce,链上结果再结合交易回执核验。
发表评论
还没有评论,来说两句吧。
评论区为展示样式,提交不会被处理。