目录
前言
用户事务nonce
从一个集群的AB节点试验说起。
总结
区块nonce
参考
前言
以太坊中的主要有2类nonce,一类是和矿工比较密切的区块nonce,即挖矿时使用;另一类和普通使用提交提交的关系比较密切的用户事务nonce。
用户事务nonce
- 为了防⽌交易重播,ETH节点要求每笔交易必须有⼀个nonce数值。每⼀个账户从同⼀个节点发起交易时,这个nonce值从0开始计数,发送⼀笔nonce对应加1。当前⾯的nonce处理完成之后才会处理后⾯的nonce。集群环境下,不同节点共同维护同⼀个⽤户的nonce值。
- txpool中由两部分构成pending和queued组成,⼀个为待打包状态,⼀个为队列中。如果传⼊的nonce就是某⽤户下笔交易应该传⼊的nonce,那么该笔交易就会放置在pending中,等待节点打包。其次,如果传⼊的nonce值过⼤,在进⼊txpool中检查到它之前的nonce并没有使⽤过,那么此笔交易不会发送到pending中,⽽且放置在queued中。只有当前⾯的nonce补齐之后,才会进⼊到pending中。
从一个集群的AB节点试验说起。
环境
节点A:192.168.45.9
节点B:192.168.45.10
节点A和节点B集群(节点B连接到节点A)
- 集群环境下,写⼊节点A的pending交易会⼴播到节点B中,因nonce问题写⼊节点A的queued交易,不会被⼴播。
- 集群环境下,节点B连上节点A(admin.addPeer(节点A)),节点A停掉的情况下再次启动,会很快恢复集群,但是如果是节点B停掉的情况下,却不会再次恢复集群,只能重新连接节点,才能恢复集群B。
1、发送⼀笔nonce为0的交易给节点A,会返回交易hash,并能在节点A的txpool中pending看到,因为⼴播⾜够快,节点B中也能看到。
2、再次发送nonce为0的交易(交易⾦额和gas price等全部保持不变)给节点A,响应code=-32000,表明并没有提交成功。
3、继续测试,再次发送nonce为0的交易给节点A,并且把gas price价格提⾼(必须超过10%),
在txpool中可以看到该笔交易会把之前的交易替换掉。也就是说,针对pending⾥的交易相同nonce再次提交,并且提⾼gas price,后⾯的交易可以覆盖之前的交易。
4、如果碰到提交给节点A的pending交易,并没有及时同步到节点B,但此时同样的nonce的交易再次提交到节点B中,是可以提交进去的,但是提交的交易的hash和节点A的hash都是⼀样的(可以认为两次发送的交易就是同⼀笔交易)。
如果我们重复上⾯的情况,依然是在节点A的交易没有及时同步到节点B中,但是我们往节点B中提交同样nonce的交易,只是去改变提交的⾦额,同理我们也可以提交进去,但两个节点都维护了同样nonce,gas price相同,交易⾦额不同的交易,它们的交易hash肯定也是不⼀样的,最终只会只有⼀笔会被打包,也就是哪个节点在挖矿,优先选择⾃⼰pending中的交易。
(测试⽅法:节点A和集群B的情况下,停掉节点A的情况下,往节点B发送⼀笔交易得到⼀个新的交易hash, 然后迅速重启节点A(保证还没来得及恢复集群的情况下),往节点A发送同样nonce的交易,但交易价格提⾼,同样提交进去并且也得到⼀个新的交易hash。
5、我们为了测试提交到queued的交易,继续发送nonce为2(跳过1)的交易到节点A中,会被提交进去,并且可以拿到交易hash,只是交易会被放⼊queued中,并且不会被⼴播到节点B。
6、再次发送nonce为2(跳过1)的交易到节点A中,提交不进去该笔交易。
7、因为节点B的queued并不会去同步节点A之前提交的nonce为2的交易,我们再次把同样的交易提交给节点B,我们可以看到该笔交易可以被提交进去,但交易hash和节点A中相应的是⼀模⼀样的,也就是说我们依然认为是同⼀笔交易。
8、依然重复操作5,我们给节点A提交⼀笔nonce为3的交易进⼊节点A的queued中,随后再次提交⼀笔nonce为3的交易,并且把gas price提⾼10%,依然可以被提交进去,但他们的hash肯定不⼀样。
9、在我们补齐nonce为1的交易后,我们观察到节点A和节点B的queued虽然都维护着nonce为3的交易(hash不同), 但最终进⼊pending中会是gas price价格⾼的交易,⾄此两个节点⼜保持⼀致。结论是gas price价格⾼的会被加⼊到pending中。
9、 如果我们继续往节点A中提交nonce为5的交易进⼊到queued中,保持gas price不变,但提⾼交转账⾦额,
再次提交nonce为5的交易到节点B中,两个节点中⼜分别维护了两笔nonce相同,但交易hash不同的交易,
但此时因为gas price⼀样,在补齐nonce为4的交易后,两个节点中nonce为5的交易都会进⼊到各⾃的pending中,
但是最终只会只有⼀笔会被打包,也就是哪个节点在挖矿,优先选择⾃⼰pending中的交易。
10、 关于nonce的其它可能会碰到的问题
某⽤户的区块链维护的nonce已经到10了,但提交⼀笔交易nonce为10以下(包括10)的交易,此时会提示nonce too low,code=-32000。
某⽤户的区块链提交的交易nonce已经到10了,但依然提交⼀笔交易nonce为10的交易, 如果不改变之前交易的任何信息继续提交(两笔交易的hash是⼀样的),会提示错误,code=-32000。如果改变交易⾦额提交(交易hash不⼀样),也会提示错误,code=-32000。
总结
当nonce太小(小于之前已有交易的nonce值),交易会被直接拒绝。
当nonce太大,交易会一直处于队列之中,长久得不到执行。
当发送一个比较大的nonce值,然后补齐开始的nonce到那个nonce之间的nonce,那么交易依旧可以被执行。
当交易处于队列中时,停止geth客户端,那么交易队列中的交易会被清除。
当有一笔处于pending状态的交易,新的一笔交易与其拥有相同的nonce值,如果新交易的gas price太小,无法覆盖pending状态的交易,如果新交易的gas price高于原交易的110%,则原交易会被覆盖掉。
交易队列只保存最多64个从同一个账户发出的交易,The transaction pool queue will only hold a maximum of 64 transactions with the same From:address with nonces out of sequence. 也就是说,如果要批量转账,同一节点不要发出超过64笔交易。
当前nonce合适,但是账户余额不足时,会被以太坊拒绝;
如果发起一笔交易,但是因为gwei比较低或者网络比较忙的时候,该交易还没矿工挖出,可以通过使用相同的nonce和较高的gas费用,从而“覆盖”前一笔交易。
区块nonce
区块上的nonce是一个无意义的随机数,用于工作量证明,与挖矿的难度有关。
矿工要想成功挖出一个区块,必须不停的穷举随机数nonce,直到通过哈希算法得到的区块hash值小于或等于目标值target,目标值越低,发现随机数需要的时间越多,难度值越高。
具体的数据结构:
// Block represents an entire block in the Ethereum blockchain.
type Block struct {
header *Header
uncles []*Header
transactions Transactions
// caches
hash atomic.Value
size atomic.Value
// Td is used by package core to store the total difficulty
// of the chain up to and including the block.
td *big.Int
// These fields are used by package eth to track
// inter-peer block relay.
ReceivedAt time.Time
ReceivedFrom interface{}
}
// Header represents a block header in the Ethereum blockchain.
type Header struct {
ParentHash common.Hash `json:"parentHash" gencodec:"required"`
UncleHash common.Hash `json:"sha3Uncles" gencodec:"required"`
Coinbase common.Address `json:"miner" gencodec:"required"`
Root common.Hash `json:"stateRoot" gencodec:"required"`
TxHash common.Hash `json:"transactionsRoot" gencodec:"required"`
ReceiptHash common.Hash `json:"receiptsRoot" gencodec:"required"`
Bloom Bloom `json:"logsBloom" gencodec:"required"`
Difficulty *big.Int `json:"difficulty" gencodec:"required"`
Number *big.Int `json:"number" gencodec:"required"`
GasLimit uint64 `json:"gasLimit" gencodec:"required"`
GasUsed uint64 `json:"gasUsed" gencodec:"required"`
Time *big.Int `json:"timestamp" gencodec:"required"`
Extra []byte `json:"extraData" gencodec:"required"`
MixDigest common.Hash `json:"mixHash" gencodec:"required"`
Nonce BlockNonce `json:"nonce" gencodec:"required"`
}
参考
https://wenku.baidu.com/view/c5440a5702f69e3143323968011ca300a6c3f63b.html文章来源:https://www.toymoban.com/news/detail-495970.html
以太坊中的两个nonce值_Elonjelinek的博客-CSDN博客文章来源地址https://www.toymoban.com/news/detail-495970.html
到了这里,关于以太坊中nonce深入解读的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!