深入浅出以太坊的 nonce

1. nonce 是什么?

A scalar value equal to the number of transactions sent from this address or, in the case of accounts with associated code, the number of contract-creations made by this account. -- 以太坊黄皮书

以太坊所有的交易都是基于 account ,不同于基于 utxo 的比特币,因此需要对每次交易都按顺序记录,nonce值就是这个顺序,nonce 是交易原始地址的属性。它不存储在以太坊区块链上,而是通过计算从一个地址发送的交易数量来计。

nonce +1

每发起一笔交易,nonce就会加一。对于发起的解释:
1.外部账户(EOA)每发送一笔交易;
2.合约账户(Contract Wallet) 每创建一个合约

而转入交易、合约调用其他合约等属于内部调用,因此 nonce 值不变。

作用 1:交易顺序

假设您要发送两个值为 1 和 4 ETH 的交易,并希望它们被顺序打包。发送一笔交易后,你继续发送第二笔交易。
现在如果没有随机数,矿工将不可能知道您维护交易顺序的意图。
如果您的第一笔交易(1 ETH)的 nonce 为0(假设是新帐户),那么 4 ETH交易的 nonce 为 1。矿工即可按照 nonce 的顺序打包交易。

作用 2:防止重放攻击

假如转账时,没有 nonce,参数如下

{ 
    "gasPrice":"10000000000", 
    "to":"0xf40629b5F96567270794F0F29E55Ac9daDE14fFd,
    " value":" 10000000000000000000“, // 10 ETH
    " data":"",
    " v,r,s":"您的ECDSA签名的某些字节"
}

交易被序列化后,例如:

25de0d5a1693d4e45ce0305d42774b5bf73cbd9e14230194c35545e0f01ee45ce0305d42774b5bf73cbd9e0d5a1693d4e45ce0305d427

该交易被打包后,对方将收到 10 ETH,但是任何人都可以看到这笔交易,然后复制粘贴,重复提交给以太坊的网络,耗尽你的余额,也就是所谓的重放攻击。

如果有交易中包含 nonce,则同一 nonce 的交易只能被打包一次。

2. 如何使用 nonce?

下图为交易被打包的过程,

深入浅出以太坊的 nonce_第1张图片

以太坊内部有 txpool,即存放交易的池子。钱包或节点发生的交易会被加入到交易池里,在打包区块的时候,就从这个池子里提取,区块产生之后,共识区块,交易上链。所以交易会有 pending 的状态,或者被交易池丢弃。

发起转账或者创建合约的时候,通过 web3 从以太坊网络查询当前的 nonce 值,使用此值作为当前交易的 nonce 值,发送到以太坊网络即可。

发送交易 eth_sendTransaction

Creates new message call transaction or a contract creation, if the data field contains code.

需要传参数 nonce,官方文档对于 nonce 的说明

nonce: QUANTITY - (optional) Integer of a nonce. This allows to overwrite your own pending transactions that use the same nonce.

获取 nonce eth_getTransactionCount

参数:

params: [
   address,
   QUANTITY  // latest, pending
]

demo

curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getTransactionCount","params":["0xf40629b5F96567270794F0F29E55Ac9daDE14fFd","earliest"],"id":1}'  https://ropsten.infura.io/v3/404b78d3e9364b79921c39a8ea909b1c

结果:
深入浅出以太坊的 nonce_第2张图片

{"jsonrpc":"2.0","id":1,"result":"0x5"}%

实际账户有 5 笔转出交易,最后一笔交易的 nonce 是 4。请注意 nonce 计数从 0 开始,所以如果你想继续发送交易,则直接使用 5 作为下一笔交易的 nonce 。

如果有处于 pending 状态的交易,即矿工未打包的交易,此时去读取 nonce,需要更换参数为 pending,否则将不能获得正确计数。没有区块确认数的交易可以被 '取消' 或者被加速。

如果交易被打包,即非 pending 状态,则是不可逆的,就无法取消啦!

3. 加速和取消以太坊的交易

Integer of a nonce. This allows to overwrite your own pending transactions that use the same nonce

基于 nonce 的特性,自增和唯一性,使用相同的 nonce 重新发起交易即可实现加速。

加速以太坊交易案例

  1. 假设有笔交易 A:gas price = 5,nonce = 1 ,由于 gas price 太低,广播后,交易一直处于 pending 状态。
  2. 创建交易 B,调整 gas price 为更合理的水平,例如 10、20 ,nonce = 1 ,再次发布交易。矿工就会选择 price 更高的交易 A 打包。
  3. 此时在矿工的交易池端,B 交易被打包了,矿工会检查 A 交易,发现 nonce 已经存在了,认为 A 是不合理的交易,则会自动丢弃该交易

取消交易

  1. 基于加速交易的案例。
  2. 创建交易 B,设置 value =0 ,收款方=发送方,设置更高的 gas price ,广播交易
  3. 原来的交易被丢弃了,新交易会被矿工打包,不会丢失任何资金。但是你还是需要为 B 交易付出矿工费

4. 异常处理

replacement-transaction-underpriced

原因

  1. 帐户中有待处理的待处理 pending 交易;
  2. 新交易和 pending 的交易 nonce 相同;
  3. 新交易的 gas price 更低,无法替换待处理的交易

深入浅出以太坊的 nonce_第3张图片

5. nonce 使用的几条规则

  1. 当nonce太小(小于当前的nonce值),交易会被直接拒绝,Transactions with too low a nonce get immediately rejected;
  2. 当 nonce 太大,大于当前 nonce,交易会一直处于队列之中,Transactions with too high a nonce get placed in the transaction pool queue;
  3. 当发送一个比较大的nonce值,然后补齐开始 nonce 到那个值之间的nonce,那么交易依旧可以被执行,If transactions with nonces that fill the gap between the last valid nonce and the too high nonce are sent and the nonce sequence is complete, all the transactions in the sequence will get processed and mined.
  4. 交易队列只保存最多64个从同一个账户发出的交易,也就是说,如果要批量转账,同一节点不要发出超过64笔交易。 The transaction pool queue will only hold a maximum of 64 transactions with the same From:address with nonces out of sequence.
  5. 当某节点 queue 中还有交易,但此时停止 geth 客户端,queue 中的交易会被清除掉,When the geth instances are shut down and restarted, transactions in the transaction pool queue disappear.
  6. 当前 nonce 合适,但是账户余额不足时,会被以太坊拒绝;

6. 参考资料

你可能感兴趣的:(以太坊,区块链)