区块链(27):响应丢失时不能凭交易哈希重做订单
00 篇的数据库基线把重复请求压成同一笔结算。接上区块链(26):代理升级把信任转移给了谁的教学托管后,服务可能已经广播交易但 RPC 响应丢失;重新生成一笔、抢用同一账户 nonce,可能替换旧交易,也可能在旧交易已入块后因 nonce 过期被拒。业务订单 ID、发起意图、nonce 与多个候选交易哈希不能放进同一个“交易完成”字段。
stateDiagram-v2
[*] --> Prepared: 原子保存订单意图
Prepared --> Signed: 保存可恢复的待发送字节标识
Signed --> Submitted: 向节点发送
Submitted --> Unknown: 响应丢失
Unknown --> Submitted: 按原字节或可验证策略重试
Submitted --> Included: 核对回执/区块
Included --> Reconciled: 执行、终局、业务对账
待发送账本应先持久化可验证的订单意图、发起账户、nonce、目标合约、chain ID、数据摘要与发送状态,再发 RPC;进程重启先查询链和待发送记录,不能简单把 HTTP 200 当结算。替换交易可以改变费用但应保证业务目标一致;若取消/加速使用另一目标,必须核对新旧候选对同一业务承诺的影响。nonce 冲突也可能来自另一个进程或钱包,共享地址须有单一分配者或原子协调。
先把意图变成可重开的记录
examples/blockchain/models/recovery.py 只模拟这一层:reserve(order_id, amount, request_key, nonce) 在 SQLite 的 BEGIN IMMEDIATE 事务中保存订单与 nonce;同键重试返回原意图,更换金额或订单则拒绝,另一个订单占用同 nonce 因唯一约束失败。record_candidate 容许同一意图关联两条候选标识;候选标识并不代表节点接纳。测试让第一次事务成功后关闭数据库,按“客户端完全没有收到响应”重开,再调用同一个请求键;记录仍只有一份。
模型没有签名、广播或链上 nonce,也未证明候选交易具备相同 calldata。接入真实客户端时须把签名前意图、签名后字节摘要与替换交易解析结果分别保存;候选哈希与 nonce 的对应关系仍要向规范链核对发起者、chain ID 和执行状态。这些工作尚未运行。
练习一:首次广播超时,第二次产生新交易 ID,如何判断是否支付了两次?答案:按发起地址/nonce 及规范链上的实际调用和订单状态复查,不能只数本地哈希。练习二:模拟数据库记录持久成功但进程在广播前退出,重启应如何恢复?答案:找到 Prepared/Signed 待处理项、核对余额/nonce 与有效期再发送,保持订单幂等。SQLite 预备模型三项测试已运行,原始结果与代码 SHA 见 examples/blockchain/evidence/27-28-38/;真实链下 API、RPC 丢响应与链上替换 NOT_RUN。
可迁移原则:未知结果需要状态持久化和后验查询,而非盲重试。参考:Ethereum JSON-RPC、EIP-155(冻结链与客户端未核);导航:区块链(26):代理升级把信任转移给了谁 · 27 · 区块链(28):索引器怎样在断线与重组后重算订单。






