这个是转账的基本参数。
参考资料
以太坊系列(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: 调低一点失败了,因为网络不拥堵,那等一会在说吧。