Nonce在以太坊中是一个非常重要的机制,它不仅防止交易重复,还保证了交易的顺序性。让我详细解释一下。
Nonce是"Number used once"的缩写,在以太坊中,每个外部账户(EOA)都维护一个nonce计数器。这个计数
器从0开始,每发送一笔交易,nonce就加1。当前账户的nonce值可以通过eth_getTransactionCount这个RPC方
法查询到。
以太坊网络在处理交易时,会严格检查交易的nonce值。一笔交易要被接受,它的nonce必须等于发送者当前的 nonce值。如果有人试图重放一笔已经执行过的交易,这笔交易的nonce会小于账户当前的nonce,网络会直接拒 绝这笔交易。 举个例子,假设你的账户当前nonce是5,你发送了一笔转账交易,nonce设为5。这笔交易被打包确认后,你的账 户nonce变成6。如果有攻击者截获了这笔交易并试图᯿放,网络会发现交易的nonce是5,但账户当前nonce已经 是6了,所以会拒绝这笔重放交易。
Nonce机制还有一个᯿要作用,就是保证交易按顺序执行。以太坊要求交易必须按nonce顺序被打包和执行。如果 你发送了nonce为5、6、7的三笔交易,即使nonce为7的交易先到达矿工节点,矿工也必须等待nonce为5和6的交 易都确认后,才能打包nonce为7的交易。 这种设计避免了"双花"问题。假设你账户里有10 ETH,你同时发送两笔转账,每笔转10 ETH。如果没有nonce机 制,两笔交易可能都被接受,导致你花费了20 ETH但实际只有10 ETH。有了nonce机制,第一笔交易(假设nonce 为5)会被执行,账户余额变为0,nonce变为6。第二笔交易(nonce为6)在执行时会因为余额不足而失败。
Nonce机制还可以用来加速或取消交易。如果你发送了一笔交易,但设置的Gas价格太低,交易⻓时间pending (待处理),你可以发送一笔相同nonce但Gas价格更高的新交易。矿工会优先打包Gas价格高的交易,一旦新交 易被确认,旧交易就会被自动丢弃。 如果你想取消一笔pending的交易,可以发送一笔nonce相同、接收地址是自己、金额为0但Gas价格更高的交易。 这笔交易被确认后,原交易就被替换掉了,相当于取消了原交易。
在我的NFT交易平台项目中,我们遇到过nonce管理的问题。当用户快速连续发起多笔交易时,如果前端没有正确 管理nonce,可能会导致所有交易都使用相同的nonce,结果只有第一笔交易成功,其他交易都失败。 我们的解决方案是在后端维护一个nonce管理器。当用户发起交易时,我们先查询链上的nonce,然后在本地维护 一个pending nonce队列。每次分配nonce时,使用"链上nonce + pending队列⻓度"来计算下一个可用的nonce。 同时,我们会监听交易确认事件,及时更新nonce状态。这样就保证了即使用户快速发起多笔交易,每笔交易都能 获得正确的nonce值。
需要注意的是,nonce值是包含在交易签名中的。这意味着一笔交易的nonce是不能被修改的,否则签名就会失 效。这进一步保证了交易的不可篡改性和防重放特性。