中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Bytom孤塊出現的原因以及相關操作介紹

發布時間:2021-09-04 09:16:56 來源:億速云 閱讀:172 作者:chen 欄目:互聯網科技

這篇文章主要介紹“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孤塊出現的原因以及相關操作介紹”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

潮州市| 和平区| 白朗县| 荔浦县| 龙井市| 巨鹿县| 新绛县| 土默特左旗| 堆龙德庆县| 铁岭市| 清水河县| 石泉县| 沈丘县| 鹿邑县| 汤阴县| 临江市| 正镶白旗| 大关县| 武夷山市| 金秀| 来凤县| 乳源| 海林市| 云阳县| 讷河市| 信宜市| 荣昌县| 纳雍县| 延庆县| 南木林县| 通化县| 林甸县| 宁陵县| 东城区| 唐海县| 翁牛特旗| 红河县| 姚安县| 原阳县| 盱眙县| 海阳市|