题目
用户连续发送两笔交易,第一笔长时间 pending,第二笔也迟迟不确认。钱包提供“加速”和“取消”按钮。请解释 nonce 在这里起什么作用,以及前端应该如何跟踪被替换的交易。
考察目标
- 是否理解外部账户的交易按 nonce 顺序执行。
- 是否知道加速和取消本质上都是发送同 nonce、费用更高的替代交易。
- 是否能在 UI 中处理原 hash 被替换、替代交易失败和竞争打包。
考察账户交易顺序、pending nonce、同 nonce 替换以及前端交易状态更新。
用户连续发送两笔交易,第一笔长时间 pending,第二笔也迟迟不确认。钱包提供“加速”和“取消”按钮。请解释 nonce 在这里起什么作用,以及前端应该如何跟踪被替换的交易。
nonce 是发送账户的顺序号。同一账户的较高 nonce 交易通常要等待前面的 nonce 被处理,所以第一笔卡住会阻塞后续交易。加速是用相同 nonce、相同意图或等价交易提高费用;取消通常是用同 nonce 给自己发送零金额交易并提高费用。它们都只是竞争替换,不能保证原交易不会先被打包。前端要把原 hash 与替代 hash 关联,并继续追踪最终进入 canonical chain 的那一笔。
外部账户每发送一笔有效交易都会消费一个 nonce。节点和钱包常同时关注:
latest:已进入最新链上状态的交易计数。pending:节点已知 pending 交易也计算在内的下一个 nonce。如果 nonce 10 仍在 pending,nonce 11 即使费用很高,也通常不能先让账户状态越过 nonce 10。因此 DApp 不应只看到第二笔 pending 就建议继续发送更多交易。
多数浏览器钱包会替 DApp 管理 nonce。普通前端不应随意手动指定,否则多个标签页、其他 DApp 和钱包自身都可能同时发送交易,导致 nonce 冲突。
交易替换要求同一发送者使用相同 nonce,并提供足以被节点接受的更高费用。
“取消”不是协议级撤销。原交易和取消交易在网络中竞争,如果原交易先被打包,原业务仍会执行。前端文案应写成“尝试取消”,而不是“保证撤销”。
替换交易还必须重新检查当前链、余额和费用。原交易的 maxFeePerGas 在 base fee 上涨后可能已不足,简单只提高 priority fee 也未必能被快速打包。
前端不能永远只轮询原 hash。交易追踪层应处理:
viem 的 waitForTransactionReceipt 支持替换检测和 onReplaced 回调。产品状态中应保留原 hash、当前有效 hash、替换原因和完整时间线,区块浏览器链接也要更新到当前交易。
const receipt = await publicClient.waitForTransactionReceipt({
hash: originalHash,
confirmations: 2,
onReplaced(replacement) {
updateTransaction({
originalHash,
currentHash: replacement.transaction.hash,
reason: replacement.reason,
});
},
});
具体回调对象字段应以当前 viem 类型定义为准;业务重点是保存替换关系,而不是只覆盖原 hash。
latest 和 pending 的 transaction count 有什么区别?发现这道题有问题? 反馈此题