千家信息网

Bytom孤块出现的原因以及相关操作介绍

发表于:2025-12-02 作者:千家信息网编辑
千家信息网最后更新 2025年12月02日,这篇文章主要介绍"Bytom孤块出现的原因以及相关操作介绍",在日常操作中,相信很多人在Bytom孤块出现的原因以及相关操作介绍问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家
千家信息网最后更新 2025年12月02日Bytom孤块出现的原因以及相关操作介绍

这篇文章主要介绍"Bytom孤块出现的原因以及相关操作介绍",在日常操作中,相信很多人在Bytom孤块出现的原因以及相关操作介绍问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答"Bytom孤块出现的原因以及相关操作介绍"的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

孤块介绍

什么是孤块

当节点收到了一个有效的区块,而在现有的主链中却未找到它的父区块,那么这个区块被认为是"孤块"。父区块是指当前区块的PreviousBlockHash字段指向上一区块的hash值。

接收到的孤块会被存储在孤块池中,直到它们的父区块被节点收到。一旦收到了父区块,节点就会将孤块从孤块池中取出,并且连接到它的父区块,让它作为区块链的一部分。

孤块出现的原因

当两个或多个区块在很短的时间间隔内被挖出来,节点有可能会以不同的顺序接收到它们,这个时候孤块现象就会出现。

我们假设有三个高度分别为100、101、102的块,分别以102、101、100的颠倒顺序被节点接收。此时节点将102、101放入到孤块管理缓存池中,等待彼此的父块。当高度为100的区块被同步进来时,会被验证区块和交易,然后存储到区块链上。这时会对孤块缓存池进行递归查询,根据高度为100的区块找到101的区块并存储到区块链上,再根据高度为101的区块找到102的区块并存储到区块链上。

孤块源码分析

孤块管理缓存池结构体

protocol/orphan_manage.go

type OrphanManage struct {    orphan      map[bc.Hash]*types.Block    prevOrphans map[bc.Hash][]*bc.Hash    mtx         sync.RWMutex}func NewOrphanManage() *OrphanManage {    return &OrphanManage{        orphan:      make(map[bc.Hash]*types.Block),        prevOrphans: make(map[bc.Hash][]*bc.Hash),    }}
  • orphan 存储孤块,key为block hash,value为block结构体

  • prevOrphans 存储孤块的父块

  • mtx 互斥锁,保护map结构在多并发读写状态下保持数据一致

添加孤块到缓存池

func (o *OrphanManage) Add(block *types.Block) {    blockHash := block.Hash()    o.mtx.Lock()    defer o.mtx.Unlock()    if _, ok := o.orphan[blockHash]; ok {        return    }    o.orphan[blockHash] = block    o.prevOrphans[block.PreviousBlockHash] = append(o.prevOrphans[block.PreviousBlockHash], &blockHash)    log.WithFields(log.Fields{"hash": blockHash.String(), "height": block.Height}).Info("add block to orphan")}

当一个孤块被添加到缓存池中,还需要记录该孤块的父块hash。用于父块hash的查询

查询孤块和父孤块

func (o *OrphanManage) Get(hash *bc.Hash) (*types.Block, bool) {    o.mtx.RLock()    block, ok := o.orphan[*hash]    o.mtx.RUnlock()    return block, ok}func (o *OrphanManage) GetPrevOrphans(hash *bc.Hash) ([]*bc.Hash, bool) {    o.mtx.RLock()    prevOrphans, ok := o.prevOrphans[*hash]    o.mtx.RUnlock()    return prevOrphans, ok}

删除孤块

func (o *OrphanManage) Delete(hash *bc.Hash) {    o.mtx.Lock()    defer o.mtx.Unlock()    block, ok := o.orphan[*hash]    if !ok {        return    }    delete(o.orphan, *hash)    prevOrphans, ok := o.prevOrphans[block.PreviousBlockHash]    if !ok || len(prevOrphans) == 1 {        delete(o.prevOrphans, block.PreviousBlockHash)        return    }    for i, preOrphan := range prevOrphans {        if preOrphan == hash {            o.prevOrphans[block.PreviousBlockHash] = append(prevOrphans[:i], prevOrphans[i+1:]...)            return        }    }}

删除孤块的过程中,同时删除父块

孤块处理逻辑

protocol/block.go

func (c *Chain) processBlock(block *types.Block) (bool, error) {blockHash := block.Hash()    if c.BlockExist(&blockHash) {        log.WithFields(log.Fields{"hash": blockHash.String(), "height": block.Height}).Info("block has been processed")        return c.orphanManage.BlockExist(&blockHash), nil    }    if parent := c.index.GetNode(&block.PreviousBlockHash); parent == nil {        c.orphanManage.Add(block)        return true, nil    }    if err := c.saveBlock(block); err != nil {        return false, err    }    bestBlock := c.saveSubBlock(block)    // ...}

processBlock函数处理block块加入区块链上之前的过程。

c.BlockExist判断当前block块是否存在于区块链上或是否存在孤块缓存池中,如果存在则返回。

c.index.GetNode判断block块的父节点是否存在。如果在现有的主链中却未找到它的父区块则将block块添加到孤块缓存池。

c.saveBlock走到了这一步说明,block父节点是存在于区块链,则将block块存储到区块链。该函数会验证区块和交易有效性。

saveSubBlock 代码如下:

func (c *Chain) saveSubBlock(block *types.Block) *types.Block {    blockHash := block.Hash()    prevOrphans, ok := c.orphanManage.GetPrevOrphans(&blockHash)    if !ok {        return block    }    bestBlock := block    for _, prevOrphan := range prevOrphans {        orphanBlock, ok := c.orphanManage.Get(prevOrphan)        if !ok {            log.WithFields(log.Fields{"hash": prevOrphan.String()}).Warning("saveSubBlock fail to get block from orphanManage")            continue        }        if err := c.saveBlock(orphanBlock); err != nil {            log.WithFields(log.Fields{"hash": prevOrphan.String(), "height": orphanBlock.Height}).Warning("saveSubBlock fail to save block")            continue        }        if subBestBlock := c.saveSubBlock(orphanBlock); subBestBlock.Height > bestBlock.Height {            bestBlock = subBestBlock        }    }    return bestBlock}

saveSubBlock 在孤块缓存池中查询是否存在当前区块的下一个区块。比如当前区块高度为100,则在孤块缓存池中查询是否有区块高度为101的区块。如果存在则将101区块存储到区块链并从孤块缓存池中删除该区块。

saveSubBlock是一个递归函数的实现。目的是为了寻找最深叶子节点的递归方式。比如当前区块高度为100的,递归查询出高度为99、98、97等高度的区块。

到此,关于"Bytom孤块出现的原因以及相关操作介绍"的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注网站,小编会继续努力为大家带来更多实用的文章!

区块 缓存 高度 节点 存储 查询 原因 递归 学习 函数 结构 有效 更多 过程 顺序 交易 处理 帮助 管理 验证 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 昆山软件开发招商 服务器密码忘了怎么清除密码 厦门共享电动车软件开发公司 评论怎么保存 数据库 投屏为什么电视会提示服务器拒绝 软件开发过程模型的特点 数据库1802错误 服务器怎么将自动改为手动 我的世界服务器踢出一名玩家指令 福建pdu服务器专用电源专卖店 合川区工商软件开发服务公司 如果玩家不充钱服务器需要多少钱 hp 服务器电话 日本网络技术不高 关系数据库软件 网络安全公益讲座截图 网络技术学院风裙子夏季 中国农产品进出口数据库 临沂分销软件开发 妇女儿童网络安全宣传活动 数据库访问权限冲突 软件开发加游戏e3 e5 手机指纹机数据库连接失败 开平区信息网络技术不二之选 阿里云08数据库远程 网络技术助理干什么的 网络安全 开汇编程序设计吗 网络安全画手绘一等奖图片 手机网络安全形式分析 分布式数据库数据一致性测试
0