交易池怎样处理相同 Nonce 的交易?
说明同一个 Nonce 的交易如何被替换,以及无效交易为什么不会进入区块状态。
- 区分 Pending 队列与已确认状态
- 解释同一账户的 Nonce 顺序
- 观察替换交易如何保留序号但更新签名内容
- 上一章谁授权了这笔转账?
- 本章交易池怎样处理相同 Nonce 的交易?
说明同一个 Nonce 的交易如何被替换,以及无效交易为什么不会进入区块状态。
- 下一章同一组交易,为什么必须同一个顺序?
先想一想这几个问题
展开答案前,可以先在心里做个判断。与预期不同的内容可以加入复习列表。
Q01钱包显示两笔相同 Nonce 的 Pending,会不会真的支付两次?+
同一账户同一 Nonce 最终只能按顺序执行一次。节点可能暂时看到多个候选,但一笔被纳入状态后,其他同 Nonce 交易就失效。
广播之后,交易不会立刻改变余额。它先进入节点的交易池,等待一个区块生产者决定是否、何时以及按什么顺序执行。本章把交易池当成一间公开的候车室。
Pending 是“已签名”,不是“已生效”
一笔 Pending 交易已经通过钱包侧的签名,但还没有成为所有节点都接受的状态转换。它可以因为余额不足、Nonce 不对、签名失效或竞争同一个序号而被拒绝。
一笔交易如何变成状态?
交易先被签名和广播,再由节点验证并打包进区块。任何一步不满足规则,余额都不会改变。
- Nonce
- 0
- 公钥
- pk_alice_demo
- Nonce
- 0
- 公钥
- pk_bob_demo
- Nonce
- 0
- 公钥
- pk_you_demo
还没有交易。先用正确 Nonce 广播一笔转账。
先广播一笔交易,再用相同 Nonce 替换它。比较替换前后的签名摘要和 Pending 状态。
先看三张账户余额和 Nonce。签名只授权一组具体字段,节点还要在打包时检查 Nonce、余额和状态规则。
还没有区块。交易先在本地 Pending,等节点打包。
- 01
创世状态:三个账户各有 1,000 积分,Nonce 从 0 开始。
拖动滑块可以回到此前的步骤。从那里继续操作时,后续记录会替换为新的操作序列。
观察实验室里的交易队列:广播后,余额和 Nonce 仍然保持不变;只有点击打包,节点才会逐笔执行交易。
同一个 Nonce 可以替换,但不能同时成功两次
如果你发现一笔 Pending 交易的金额或目标不合适,钱包通常会用相同 Nonce 广播一个新版本。节点在执行时只能让这个序号对应一次成功状态转换;旧版本被替换后不会额外扣款。
展开:这一步如何实现
replace(pending, nextAmount):
require pending.status == PENDING
require nextAmount > 0
pending.amount = nextAmount
pending.signature = sign(pending.fields)
mine(queue):
for tx in queue:
if tx.nonce == account[tx.from].nonce and verify(tx):
apply(tx)
else:
reject(tx)
真实链还会用更高费用激励节点接受替换版本。这里先把核心约束显式化:同一个 Nonce 是账户状态机的一个槽位。
同一个 Nonce 的替换交易,为什么不会让账户扣款两次?
从交易池继续问三个问题
- 交易在 Pending 时,哪些状态还没有改变?
- 为什么未来 Nonce 不能绕过当前 Nonce?
- 替换交易和篡改交易的区别是什么?
这些问题会在撮合引擎、AMM 和借贷模块里反复出现:用户动作先进入队列,只有经过规则验证和顺序执行,才会影响共享状态。