关于以太坊的nonce值

关于以太坊的nonce值文章目录每笔交易 nonce 值的各个情况总结关于 Nonce 的保管依赖节点自行管理 nonce 参考代码 nonce 在区块链中是一个非常重要的概念 从比特币到以太坊都有 nonce 的身影 在比特币中 nonce 主要用于调整 pow 挖矿的难度 而在以太坊中 除了调整挖矿难度外 在外部账户的每笔交易中也都存在一个 nonce 这个 nonce 是一个连续的整数 在每个账户发送交易时所产生 其主要设计目的是为防止双花 web3 中的 sendTransact 方法 官方文档是这样写的 https web3js readt

nonce在区块链中是一个非常重要的概念,从比特币到以太坊都有nonce的身影。

在比特币中,nonce主要用于调整pow挖矿的难度,而在以太坊中,除了调整挖矿难度外,在外部账户的每笔交易中也都存在一个nonce。这个nonce是一个连续的整数,在每个账户发送交易时所产生,其主要设计目的是为防止双花。

web3中的sendTransaction方法,官方文档是这样写的:

https://web3js.readthedocs.io/en/1.0/web3-eth.html#sendtransaction

sendTransaction web3.eth.sendTransaction(transactionObject [, callback]) Sends a transaction to the network. Parameters Object - The transaction object to send: from - String|Number: The address for the sending account. Uses the web3.eth.defaultAccount property, if not specified. Or an address or index of a local wallet in web3.eth.accounts.wallet. to - String: (optional) The destination address of the message, left undefined for a contract-creation transaction. value - Number|String|BN|BigNumber: (optional) The value transferred for the transaction in wei, also the endowment if it’s a contract-creation transaction. gas - Number: (optional, default: To-Be-Determined) The amount of gas to use for the transaction (unused gas is refunded). gasPrice - Number|String|BN|BigNumber: (optional) The price of gas for this transaction in wei, defaults to web3.eth.gasPrice. data - String: (optional) Either a ABI byte string containing the data of the function call on a contract, or in the case of a contract-creation transaction the initialisation code. nonce - Number: (optional) Integer of a nonce. This allows to overwrite your own pending transactions that use the same nonce. 

每笔交易nonce值的各个情况

可以看到,在构建交易时,有一个可选的nonce参数,可以覆盖在交易池中的,pending列表中相同nonce的交易。

接下来我会在Geth搭建的私有链来进行以下实验,来看看不同情况下nonce对应的交易会怎样:

  • 相同nonce下的两笔交易
  • 不连续nonce下的交易
  • 不具体指定nonce的交易

首先下方命令看到地址0xfa8d4ded7fe1fec96c1b10443beaf233bb的总交易数是2,也就是说,nonce数值已累加到2(nonce值从0开始),新的交易nonce值将是3。

> eth.getTransactionCount("0xac965f9832efd7684bbbd7ceed5891a337bca302") 3 

接下来指定nonce为3,创建一笔交易,如下可看到,交易成功,并被打包到了区块中。

> web3.eth.sendTransaction({from: "0xac965f9832efd7684bbbd7ceed5891a337bca302", to: "0x6e60f5243e1a3f0be3f407b5afe9e5395ee82aa2", value: "00000000", nonce: "3"}) "0x497c21a80dd96ca8f40a70bcb7013b4d11019d75b522fa1b46a82d7" > eth.getTransaction("0x497c21a80dd96ca8f40a70bcb7013b4d11019d75b522fa1b46a82d7") { blockHash: "0xc1aad9012d8bfc34a5003d73f7507bfe562cbad81f0050476ca698a455", blockNumber: , from: "0xac965f9832efd7684bbbd7ceed5891a337bca302", gas: 21000, gasPrice: , hash: "0x497c21a80dd96ca8f40a70bcb7013b4d11019d75b522fa1b46a82d7", input: "0x", nonce: 3, r: "0xddde68ee95d14273b1b45ce6df5a40bd079357cb7eb1281d7edebb88799ed554", s: "0x7584f6cd4e8cad3c3691ca3ec1d671c9096f7acabaaec481e937f8cc", to: "0x6e60f5243e1a3f0be3f407b5afe9e5395ee82aa2", transactionIndex: 0, type: "0x0", v: "0x539bb", value: 00000000 } 

如果此时我在发送一笔交易,并指定nonce还是3,运行结果如下所示。

会看到此时交易报错,提示“nonce too low”

> web3.eth.sendTransaction({from: "0xac965f9832efd7684bbbd7ceed5891a337bca302", to: "0x6e60f5243e1a3f0be3f407b5afe9e5395ee82aa2", value: "00000000", nonce: "3"}) Error: nonce too low at web3.js:6347:37(47) at web3.js:5081:62(37) at 
   
     :1:25(13) 
   

按照nonce的规则,接下来的新交易nonce值应该是4,我现在跳过4,直接指定nonce值为5,会发生什么,如下所示。

> web3.eth.sendTransaction({from: "0xac965f9832efd7684bbbd7ceed5891a337bca302", to: "0x6e60f5243e1a3f0be3f407b5afe9e5395ee82aa2", value: "00000000", nonce: "5"}) "0x8e8967d1cd199f375f96e9100c8810b2c97848a1006b2eba14c54a8d9" 

可以看到,返回了交易hash,我们查看该笔交易,发现blockNumber为null,并没有加入到区块中,如下所示:

> eth.getTransaction("0x8e8967d1cd199f375f96e9100c8810b2c97848a1006b2eba14c54a8d9") { blockHash: null, blockNumber: null, from: "0xac965f9832efd7684bbbd7ceed5891a337bca302", gas: 21000, gasPrice: , hash: "0x8e8967d1cd199f375f96e9100c8810b2c97848a1006b2eba14c54a8d9", input: "0x", nonce: 5, r: "0x6499ec326d5d9f1e5035fc4e7612b1e52c0c1bc60baf6f4068eaf790afe03f70", s: "0x2e66bb3e394dc8f9e6be9ad597c7144aaafdb5894e5ac8ce46a39bb", to: "0x6e60f5243e1a3f0be3f407b5afe9e5395ee82aa2", transactionIndex: null, type: "0x0", v: "0x539bb", value: 00000000 } 

暂未被加入到区块中的交易,会被放入到交易池中(txpool),交易池里会维护两个列表,一个是待被打包的pending列表,一个是当前无法执行的交易queued列表。

从下方请求可看到0x8e8967d1cd199f375f96e9100c8810b2c97848a1006b2eba14c54a8d9交易被放到了queued列表中。这是由于交易池中没有找到地址0xac965f9832efd7684bbbd7ceed5891a337bca302为4的nonce。

当交易处于queue中时停止geth客户端,那么交易queue中的交易会被清除掉。

> web3.txpool.content.queued { 0xaC965f9832eFD7684BBBd7cEED5891a337bCA302: { 5: { blockHash: null, blockNumber: null, from: "0xac965f9832efd7684bbbd7ceed5891a337bca302", gas: "0x5208", gasPrice: "0x3b9aca00", hash: "0x8e8967d1cd199f375f96e9100c8810b2c97848a1006b2eba14c54a8d9", input: "0x", nonce: "0x5", r: "0x6499ec326d5d9f1e5035fc4e7612b1e52c0c1bc60baf6f4068eaf790afe03f70", s: "0x2e66bb3e394dc8f9e6be9ad597c7144aaafdb5894e5ac8ce46a39bb", to: "0x6e60f5243e1a3f0be3f407b5afe9e5395ee82aa2", transactionIndex: null, type: "0x0", v: "0x539bb", value: "0x29a2241af62c0000" } } } 

新建一笔交易,设置nonce为4,如下所示。

会看到提交交易后,queued列表中nonce为5的交易也被移出,同时待打包的pending列表中,有了nonce值为4和5的交易信息。挖矿后,这两笔交易将会被写入到区块中。

> web3.eth.sendTransaction({from: "0xac965f9832efd7684bbbd7ceed5891a337bca302", to: "0x6e60f5243e1a3f0be3f407b5afe9e5395ee82aa2", value: "00000000", nonce: "4"}) "0xd8610ad5962e88f2eaeb8fd7f18da1dfa73b6e180cd34751dc32c1c975" > web3.txpool.content.pending { 0xaC965f9832eFD7684BBBd7cEED5891a337bCA302: { 4: { blockHash: null, blockNumber: null, from: "0xac965f9832efd7684bbbd7ceed5891a337bca302", gas: "0x5208", gasPrice: "0x3b9aca00", hash: "0xd8610ad5962e88f2eaeb8fd7f18da1dfa73b6e180cd34751dc32c1c975", input: "0x", nonce: "0x4", r: "0xef4b52cd0a8ff5d4d119b43f2ebfbca3ed0785a19df2a90e9b9c4a9a39b07ddf", s: "0x191d51ccad9184cd2cf09f2fde7438d71bb6c19ea", to: "0x6e60f5243e1a3f0be3f407b5afe9e5395ee82aa2", transactionIndex: null, type: "0x0", v: "0x539bb", value: "0xec" }, 5: { blockHash: null, blockNumber: null, from: "0xac965f9832efd7684bbbd7ceed5891a337bca302", gas: "0x5208", gasPrice: "0x3b9aca00", hash: "0x8e8967d1cd199f375f96e9100c8810b2c97848a1006b2eba14c54a8d9", input: "0x", nonce: "0x5", r: "0x6499ec326d5d9f1e5035fc4e7612b1e52c0c1bc60baf6f4068eaf790afe03f70", s: "0x2e66bb3e394dc8f9e6be9ad597c7144aaafdb5894e5ac8ce46a39bb", to: "0x6e60f5243e1a3f0be3f407b5afe9e5395ee82aa2", transactionIndex: null, type: "0x0", v: "0x539bb", value: "0x29a2241af62c0000" } } } 

那么如果当我们发起一笔交易,假设当前nonce为11,交易已经发送至节点中,但由于手续费不高或网络拥堵或nonce值过高,此交易处于queued中迟迟未被打包。

同时此地址再发起一笔交易,并且nonce值与上一个nonce值相同,用同样的nonce值再发出交易时,就会有两种情况:

如果手续费低于原来的交易就会发生异常:replacement transaction underpriced。

// 发生一笔nonce为11,gasPrice为78 gwei的交易 web3.eth.sendTransaction({from: "0xac965f9832efd7684bbbd7ceed5891a337bca302", to: "0x6e60f5243e1a3f0be3f407b5afe9e5395ee82aa2", value: "00000000",gas:"21000",gasPrice:"",nonce: "11"}) "0x3aaf3fe591cca759ee72d46461c145d4496bde488bcf59c7c5643dd05d" // 当以上交易还没有上链时,再次发生一笔nonce为11,gasPrice为75 gwei的交易,则会报错 > web3.eth.sendTransaction({from: "0xac965f9832efd7684bbbd7ceed5891a337bca302", to: "0x6e60f5243e1a3f0be3f407b5afe9e5395ee82aa2", value: "00000000",gas:"21000",gasPrice:"",nonce: "11"}) Error: replacement transaction underpriced at web3.js:6347:37(47) at web3.js:5081:62(37) at 
   
     :1:25(17) 
   

如果手续费高于原来的交易,那么第一笔交易将会被覆盖。

// 发生一笔nonce为13,gasPrice为78 gwei的交易 > web3.eth.sendTransaction({from: "0xac965f9832efd7684bbbd7ceed5891a337bca302", to: "0x6e60f5243e1a3f0be3f407b5afe9e5395ee82aa2", value: "00000000",gas:"21000",gasPrice:"",nonce: "13"}) "0x757cccf40ab253a69c3bad6fad71c097d8b0e69ead2dacdb6b75e03c23" // 当以上交易还没有上链时,再次发生一笔nonce为13,gasPrice为88 gwei的交易,发现交易成功了 > web3.eth.sendTransaction({from: "0xac965f9832efd7684bbbd7ceed5891a337bca302", to: "0x6e60f5243e1a3f0be3f407b5afe9e5395ee82aa2", value: "00000000",gas:"21000",gasPrice:"",nonce: "13"}) "0xab538aaded6f1232b2198b3b508bc73af20cfd2d0ad0117faa6b8aadaf" // 最后查询第一笔交易,发现查询为空 > eth.getTransaction("0x757cccf40ab253a69c3bad6fad71c097d8b0e69ead2dacdb6b75e03c23") null // 然后查询第二笔交易,发现交易上链,nonce值为13 > eth.getTransaction("0xab538aaded6f1232b2198b3b508bc73af20cfd2d0ad0117faa6b8aadaf") { blockHash: "0x16ae951ccb6abc63edfed1dcc8292f43f41aa7c6597a92fe4da08de281", blockNumber: , from: "0xac965f9832efd7684bbbd7ceed5891a337bca302", gas: 21000, gasPrice: , hash: "0xab538aaded6f1232b2198b3b508bc73af20cfd2d0ad0117faa6b8aadaf", input: "0x", nonce: 13, r: "0xfe5cd567b5c372a9187fde81bdc85554d0626a64dee00b", s: "0x3642a005f1a2c7801b8ac635fce0c7995c4d41a758cf80fef3dd292afe", to: "0x6e60f5243e1a3f0be3f407b5afe9e5395ee82aa2", transactionIndex: 0, type: "0x0", v: "0x539bb", value: 00000000 } 

总结

总结一下:

  • 1、以太坊中有两种nonce,一种是在区块中的nonce,主要是调整挖矿难度;一种是每笔交易中nonce。
  • 2、每个外部账户(私钥控制的账户)都有一个nonce值,从0开始连续累加,每累加一次,代表一笔交易。
  • 3、某一地址的某一交易的nonce值如果大于当前的nonce,该交易会被放到交易池的queued列表中,直到缺失的nonce被提交到交易池中。
  • 4、地址的nonce值是一个连续的整数,设计的主要目的是防止双花。
  • 5、在发生一笔交易时,如果不指定nonce值时,节点会根据当前交易池的交易自动计算该笔交易的nonce。有可能会出现节点A和节点B计算的nonce值不一样的情况。
  • 6、当交易暂未上链时,可通过提高手续费的方式,覆盖同样nonce值的交易
  • 7、通常情况下,覆盖掉一笔处于pending状态的交易gas price需要高于原交易的110%。

关于Nonce的保管

依赖节点

  • 优点:

如果该热点账户的私钥信息等都存放在Ethereum客户端中,那么在发送交易的时候不传递nonce值,Ethereum客户端会帮你处理好此nonce值的排序。

  • 缺点:

当然,此方案有两个弊端。第一个是安全性无法保障(未进行冷热账户分离),第二,在热点账户下如果想覆盖掉一笔交易,需要先查询一下该交易的信息,从中获取nonce值。

自行管理nonce

  • 优点:

通过数据库进行管理nonce,在每一次发布成功的交易都做一次++操作,并且在数据库保存对当前这笔交易的nonce保管,以方便自己追踪当前交易的nonce。

  • 缺点:

此种方案也有限制条件。第一,由于nonce统一进行维护,那么这个地址必须是内部地址,而且发起交易必须通过统一维护的nonce作为出口,否则在其他地方发起交易,原有维护的nonce将会出现混乱。第二,一旦已经发出的交易发生异常,异常交易的nonce未被使用,那么异常交易的nonce需要重新被使用之后它后面的nonce才会生效。

注:可获取当前地址发起交易的eth_getTransactionCount 参数为地址,以及Pending或者lastest,选用pending就行, 就可以获取你当前地址的最大nonce数。 但是这种情况需要确保你中间的nonce没有中断过。

例如:

# curl -H Content-Type:application/json -X POST --data '{"jsonrpc":"2.0","method":"eth_getTransactionCount","params":["0xac965f9832efd7684bbbd7ceed5891a337bca302","pending"],"id":1}' http://127.0.0.1:8545 {"jsonrpc":"2.0","id":1,"result":"0xe"} 

参考代码

https://github.com/ethereum/go-ethereum/blob/86e77900c53ebcea39cbca38eb4d62fdf/core/tx_pool.go

一笔交易调用add(ctx context.Context, tx *types.Transaction)方法将交易信息加入到交易池的pending列表中,需要对交易信息进行验证,验证方法是validateTx,如下所示:

// validateTx checks whether a transaction is valid according to the consensus // rules and adheres to some heuristic limits of the local node (price and size). func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error { // Heuristic limit, reject transactions over 32KB to prevent DOS attacks if tx.Size() > 32*1024 { return ErrOversizedData } ... // Ensure the transaction adheres to nonce ordering if pool.currentState.GetNonce(from) > tx.Nonce() { return ErrNonceTooLow } ... } 

使用GetNonce方法获取当前地址在交易池中的nonce值,如果当前交易的nonce比交易池中的nonce值小,就会报“nonce too low”的错误。


版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/217254.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月18日 上午10:00
下一篇 2026年3月18日 上午10:00


相关推荐

  • 4.4.2分类模型评判指标(一) – 混淆矩阵(Confusion Matrix)

    4.4.2分类模型评判指标(一) – 混淆矩阵(Confusion Matrix)简介混淆矩阵是ROC曲线绘制的基础,同时它也是衡量分类型模型准确度中最基本,最直观,计算最简单的方法。一句话解释版本:混淆矩阵就是分别统计分类模型归错类,归对类的观测值个数,然后把结果放在一个表里展示出来。这个表就是混淆矩阵。数据分析与挖掘体系位置混淆矩阵是评判模型结果的指标,属于模型评估的一部分。此外,混淆矩阵多用于判断分类器(Classifier)的优劣,适用于…

    2022年5月14日
    57
  • Android 学习路线

    Android 学习路线1 性能 内存调优 2 JNI 和 NDK3 插件化 热修复 组件化 4 算法和数据结构 5 js 与本地交互 6 Socket 通信 TCP IP 和 HTTP7 自定义控件 8 音 视频 9 OKHttp Retrofit RxJava Gson10 服务 线程 aidl 进程的通信机制

    2026年3月17日
    3
  • CoInitialize浅析一

    CoInitialize浅析一大家都知道程序中若要使用COM组件则必需要先调用CoInitialize,该函数主要是用来初始化COM执行环境。但这个函数的作用域是以线程为单位还是以进程为单位呢?或许大家已经通过測试程序摸索出答案,

    2022年7月3日
    26
  • 安装office2016时弹出microsoft setup bootstrapper已停止工作的解决办法

    安装office2016时弹出microsoft setup bootstrapper已停止工作的解决办法安装office2016时安装进度条走到最后又回滚,弹出microsoftsetupbootstrapper已停止工作,最后“安装出错”经过了1天的试尽了各种控制面板卸载、文件夹删除、office注册表删除等方法,最后用了以下方法才终于解决。希望没试过我这个方法的朋友们先试下这个方法。(⊙o⊙)…确认启动WindowsEventLog这个服务项。Windows系统的服务打开方…

    2022年7月20日
    43
  • Amoeba配置读写分离

    Amoeba配置读写分离读写分离配置本想采用 MysqlProxy 来实现读写分离 奈何其使用的 lua 脚本着实让人头痛 最后决定采用国人开发的开源数据库代理中间件 Amoeba 使用 Amoeba 只需要简单的 xml 配置 就可以很容易地实现读写分离 Amoeba 处于应用程序和数据库服务器之间 充当一个中间代理层 其支持负载均衡 高可用性 Query 过滤 读写分离 可路由相关的 query 到目标数据库 可并发请求多

    2026年3月17日
    2
  • 比亚迪 x 火山引擎:豆包大模型融入DiLink系统,覆盖旗下五大品牌车型

    比亚迪 x 火山引擎:豆包大模型融入DiLink系统,覆盖旗下五大品牌车型

    2026年3月12日
    2

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号