这个是转账的基本参数。
参考资料
以太坊系列(ETH&ETC
)在发送交易有三个对应的RPC
接口,分别是
- ethsendTransaction
- ethsendRawTransaction
- personal_sendTransaction
这三个接口发送(或构造发送内容时)都需要一个参数nonce
。
官方文档对此参数的解释是:整数类型,允许使用相同随机数覆盖自己发送的处于
pending
状态的交易。
规则
为了防止交易重播,ETH(ETC)节点要求每笔交易必须有一个nonce数值。每一个账户从同一个节点发起交易时,这个nonce值从0开始计数,发送一笔nonce对应加1。当前面的nonce处理完成之后才会处理后面的nonce。注意这里的前提条件是相同的地址在相同的节点发送交易。
以下是nonce
使用的几条规则:
- 当
nonce
太小(小于之前已经有交易使用的nonce值),交易会被直接拒绝。 - 当
nonce
太大,交易会一直处于队列之中。 - 当发送一个比较大的
nonce
值,然后补齐开始nonce
到那个值之间的nonce
,那么交易依旧可以被执行。 - 当交易处于
queue
中时停止geth
客户端,那么交易queue
中的交易会被清除掉。
获取nonce值
在实际应该用中我们如何保障 nonce
值的可靠性呢?这里有两个思路。
第一个思路就是由业务系统维护nonce
值的递增。如果交易发送就出现问题,那么该地址下一笔交易继续使用这个nonce
进行发送交易。
第二个思路就是使用现有的api
查询当前地址已经发送交易的nonce
值,然后对其加1
,再发送交易。对应的API接口为:eth_getTransactionCount
,此方法由两个参数,第一个参数为需要查询nonce
的地址,第二个参数为block
的状态:latest
、earliest
和pending
。一般情况使用pending
就可以查询获得最新已使用的nonce
。
我写的代码,一般来说直接用
eth_getTransactionCount
返回的值作为 nonce
就好了,但是,有的时候交易在 pending
,导致这个交易没有发送成功,然后,继续调用的话,会导致 nonce
的数值一样,出现失败。我的解决方案是这样的
1 | def send_hoo(): |
nonce使用陷阱
热点账户:所谓的热点账户就是频繁被使用的账户,在以太坊中比如交易所的统一出币账户,在短时间内频繁发起交易的账户,均可被称作热点账户。
replacement transaction underpriced异常
如果系统中的热点账户或普通账户发起交易时出现 error: replacement transaction underpriced
异常,那么就需要考虑 nonce
使用是否正确。
引起此异常原因主要是当一个账户发起一笔交易,假设使用nonce
为1
,交易已经发送至节点中,但由于手续费不高或网络拥堵或nonce
值过高,此交易处于queued
中迟迟未被打包。
同时此地址再发起一笔交易,如果通过eth_getTransactionCount
获取的nonce
值与上一个nonce
值相同,用同样的nonce
值再发出交易时,如果手续费高于原来的交易,那么第一笔交易将会被覆盖,如果手续费低于原来的交易就会发生上面的异常。
通常发生此异常意味着:
- 该
nonce
已经用过 - 你的
Ethereum
客户端中已经有一币处于pending
状态的交易。 - 新的一笔交易拥有
pending
状态交易相同的nonce
值。 - 新的交易的
gas price
太小,无法覆盖pending
状态的交易。
通常情况下,覆盖掉一笔处于 pending
状态的交易 gas price
需要高于原交易的110%
。
案例分析
这次以币安智能链作为研究对象。
地址: 0xE8e069C47A45050DBA9D566CEfFA7bc7D453F0c5
此时最新的 nonce 是 20。
web3.js
测试函数 getTransactionCount ,下面分别是 2 种状态下 nonce 的取值。
- latest
- 0x15 「10进制下 nonce 等于 21」
- pending
- 0x15
web3.py
测试函数 getTransactionCount
- latest
- 21
- pending
- 21
然后我故意把 gas 调低一点,让其没办法成交。
ps: 调低一点失败了,因为网络不拥堵,那等一会在说吧。