geth 中 miner 模块 - unconfirmed 文件详解

该博客详细介绍了 unconfirmed 文件,它用于描述本地节点挖掘出的未被全网确认的区块。判断区块被全网确认的方法是最新区块链包含该区块且其后至少连 7 个区块。未确认区块放环形链表,确认或不符合条件会剔除,关键操作日志存证,当前源码版本 1.9.0 - unstable。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

unconfirmed 详解

如文件名所描述的一样,该文件用于描述存储本地节点挖掘出来的尚未被全网所确认的区块。判断一个区块被全网确认的方法是,最新的区块链中包含该区块,并且该区块后面至少连接了 7 个区块。

所有的 unconfirmed 区块会被放入一个环形链表中,一旦被确认就会从链表中剔除。此外,如果最终发现一个区块既不在区块链中,也不在区块链中区块的叔块中,那么该区块也会从环形链表中剔除。所有的这些关键操作都会以日志的方式记录存证。

2

当前源码版本为:1.9.0-unstable

// 接口,调用该接口的对象必须要实现该接口中定义的方法。根据区块号获取区块头和区块
type chainRetriever interface {
	// 由区块高度获取区块链中的区块头,用于判断 unconfirmed 区块是否在最新的区块链中充当区块角色
	GetHeaderByNumber(number uint64) *types.Header

	// 由区块高度获取区块链中的区块,用于已经确认unconfirmed 区块不在最新的区块链中充当区块角色之后,判断 unconfirmed 区块是否在最新的区块链充当叔块的角色
	GetBlockByNumber(number uint64) *types.Block
}
//本地挖出的 unconfirmed 区块所存储的数据结构
type unconfirmedBlock struct {
	index uint64  //当前区块的高度
	hash  common.Hash   //当前区块 hash,可以参考 worker.go 中 601 行 w.unconfirmed.Insert(block.NumberU64(), block.Hash())
}
//最核心的数据结构,可以存储 unconfirmed 区块集合。
type unconfirmedBlocks struct {
	chain  chainRetriever //该属性对应上面的接口定义,用于提供权威的信息证明,判断区块是否被区块链所接纳
	depth  uint           // 区块确认的最小长度,用于判断 unconfirmed 区块同区块链上最新的区块之间的长度关系,以此来决定是否丢弃 unconfirmed 区块
	blocks *ring.Ring     // 存储所有 unconfirmed 区块的环形链表结构
	lock   sync.RWMutex   // 并发访问保护的锁
}
//构造函数,初始化 unconfirmedBlocks 数据结构,返回一个指针对象
func newUnconfirmedBlocks(chain chainRetriever, depth uint) *unconfirmedBlocks {
	return &unconfirmedBlocks{
		chain: chain,
		depth: depth,
	}
}
//该方法用于往 unconfirmedBlocks 中添加新的 unconfiemed 区块
func (set *unconfirmedBlocks) Insert(index uint64, hash common.Hash) {
	// 移除环形链表中满足条件的 unconfirmed 区块
	set.Shift(index)

	// 根据传入的 index 和 hash 创建新的 unconfirmed 区块,并将它放入 ring 中
	item := ring.New(1)
	item.Value = &unconfirmedBlock{
		index: index,
		hash:  hash,
	}
	// 将新创建的 ring 添加至已有的 blocks 链尾
	set.lock.Lock()
	defer set.lock.Unlock()

	if set.blocks == nil {
		set.blocks = item
	} else {
		set.blocks.Move(-1).Link(item)
	}
	// 用日志的形式通知用户,挖到了一个新的区块
	log.Info("? mined potential block", "number", index, "hash", hash)
}
//移除所有超过 unconfirmed 集合长度限制的 unconfirmed 区块。
func (set *unconfirmedBlocks) Shift(height uint64) {
	set.lock.Lock()
	defer set.lock.Unlock()

	for set.blocks != nil {  //for 循环删除
        next := set.blocks.Value.(*unconfirmedBlock)
        //如果当前 unconfirmed 区块的高度 + 确认所需的区块数量长度 > 区块链中最新的区块高度,则 break 跳出当前 for 循环。否则,就判断当前 unconfirmed 区块是否在区块链中,或者是否在区块链区块的叔块中
		if next.index+uint64(set.depth) > height {
			break
		}
		// 根据当前 unconfirmed 区块号获取区块头
        header := set.chain.GetHeaderByNumber(next.index)
        //根据获取的区块头进行对应的处理
		switch {
		case header == nil: //未能获取区块头,日志记录警告
			log.Warn("Failed to retrieve header of mined block", "number", next.index, "hash", next.hash)
		case header.Hash() == next.hash: //区块头对应生成的 hash == 当前 confirmed hash,说明当前 confirmed 区块被全网成功确认,日志记录,恭喜一波
			log.Info("? block reached canonical chain", "number", next.index, "hash", next.hash)
		default:  //当前 confirmed hash 和区块头对应的 hash 值不一致
			// Block is not canonical, check whether we have an uncle or a lost block
			included := false
			for number := next.index; !included && number < next.index+uint64(set.depth) && number <= height; number++ {  //判断当前 unconfirmed 区块是否在区块链剩余区块的叔块中
				if block := set.chain.GetBlockByNumber(number); block != nil {
					for _, uncle := range block.Uncles() {
						if uncle.Hash() == next.hash {  //如果在区块的叔块结构中,就 break 跳出 for 循环
							included = true
							break
						}
					}
				}
			}
			if included {  // 当前 unconfirmed 区块作为叔块存在区块链中,记录一波
				log.Info("⑂ block became an uncle", "number", next.index, "hash", next.hash)
			} else {    //否则,完蛋了,区块丢失,在区块链上没有一丢丢记录,矿工没有拿到一分钱
				log.Info("? block lost", "number", next.index, "hash", next.hash)
			}
		}
		// 从环形链表结构中删除当前 unconfirmed 区块
		if set.blocks.Value == set.blocks.Next().Value {
			set.blocks = nil
		} else {
			set.blocks = set.blocks.Move(-1)
			set.blocks.Unlink(1)
			set.blocks = set.blocks.Move(1)
		}
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值