关于nonce-too-high问题的详细分析
关于ethereum 中,nonce问题总结:
- Tx 中 nonce 过低(too low)时,Tx 立即被拒绝
- Tx 中 nonce 过高(too high)时,Tx 被放入交易池队列 transaction pool queue
- 如果 Tx 的 nonce 正好填补了最新的有效的 nonce 和过高的nonce之间的空隙,是的nonce的顺序完整连接时,交易池队列中的交易将被执行
- 当 Geth 被关掉或者重新启动时,交易池中的 Txs 将消失
nonce问题,详细介绍:
- 当 Tx 中 nonce 过低时,
1 | eth.sendTransaction({from: eth.accounts[0], to: eth.accounts[1], value: web3.toWei(1, "ether"), nonce:0}) |
- 当 Tx 中 nonce 过高时,
1 | txpool.status |
- Geth 重启时,
1 | txpool.status |
解决方案
在应用本地保存nonce在数据库中,并且,数据库中的nonce值更新时需要访问锁保护。不建议将nonce保存在内存中,那样的话,在应用死机或者重启时,nonce将丢失。目前思考 Redis DB 是比较好的选择。
如果本地nonce出了问题,可以使用
web3.eth.getTransactionCount(ethAddress)
来恢复。但是web3.eth.getTransactionCount(ethAddress)
是内存中的值,不是实时准确的,不建议实时使用。
另外:
即使交易池(queue)中有交易存在,nonce正确的交易仍然可以继续进行。
当共识停止工作了,nonce正确的交易进入到pending队列中,nonce较高的交易进入到queue队列中。当共识重新正常工作时,pending队列中的交易会被自动处理而清空。
同时节点具有每隔一个小时,重新处理一次本地交易的能力。(handle local transaction journal rotation)
参考链接 ==> https://ethereum.stackexchange.com/questions/2808/what-happens-when-a-transaction-nonce-is-too-high
参考代码 ==>
1 | ethereum/go-ethereum/core/tx_pool.go |
本问题调查过程中,使用到的命令==>
1 | eth.getTransactionCount(eth.accounts[0]) |