Derek interprets Bytom source code-orphan block management

Source: Internet
Author: User

Author: Derek

Brief introduction

GitHub Address: Https://github.com/Bytom/bytom

Gitee Address: Https://gitee.com/BytomBlockc ...

This chapter describes Bytom code orphan block Management

The author uses the MacOS operating system, and the other platforms are similar

Golang version:1.8

Orphan block Introduction

What is a solitary block?

When a node receives a valid chunk, and its parent block is not found in the existing main chain, the chunk is considered a "lone block". The parent chunk refers to the hash value of the Previousblockhash field of the current chunk that points to the previous chunk.

The orphaned blocks received will be stored in the lone pool until their parent chunk is received by the node. Once the parent chunk is received, the node takes the orphan block out of the pool and connects to its parent block, making it part of the blockchain.

The reason why the solitary block appears

When two or more chunks are dug up within a short interval of time, the nodes may receive them in a different order, and this is when the solitary block phenomenon occurs.

We assume that there are three blocks with a height of 100, 101, and 102, which are received by the nodes in reverse order of 102, 101, 100, respectively. At this point, the node puts 102, 101 into the orphan block management cache pool, waiting for each other's parent block. When a block with a height of 100 is synchronized, the chunks and trades are validated and then stored on the blockchain. In this case, the lone block cache pool will be recursive query, according to the block height of 100 to find 101 chunks and stored on the blockchain, and then according to the height of 101 blocks to find 102 chunks and stored in the blockchain.

Isolated block source code analysis

Orphan block management cache pool structure body

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 storage orphan block, key is block Hash,value for block structure
    • Prevorphans the parent block of the stored orphan block
    • MTX mutex to protect the map structure to maintain data consistency in multiple concurrent read and write situations

Add orphaned blocks to the cache pool

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")}

When a lone block is added to the cache pool, it is also necessary to record the parent block hash of the orphan block. Query for parent block hash

Querying for orphaned blocks and parent solitary blocks

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}

Delete Orphan blocks

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        }    }}

Delete the orphaned block while deleting the parent block

Orphan block processing logic

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)    // ...}    

The Processblock function processes the block block before it joins the block chain.

C.blockexist determines whether the current block blocks exist on the blockchain or if there is a lone block cache pool, and returns if present.

C.index.getnode determines whether the parent node of block blocks exists. If the parent chunk is not found in the existing main chain, the block block is added to the orphaned block cache pool.

C.saveblock This step shows that the block parent node is present in the blockchain, and then the block block is stored in the block chain. This function verifies the block and the transaction validity.

The Savesubblock code is as follows:

The 
  func (c *chain) Savesubblock (Block *types. Block) *types. Block {blockhash: = block. Hash () Prevorphans, OK: = C.orphanmanage.getprevorphans (&blockhash) if!ok {return block} Bestblo  CK: = 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 (orph Anblock); Err! = Nil {log. Withfields (log. fields{"Hash": prevorphan.string (), "height": orphanblock.height}). Warning ("Savesubblock fail to save Block") continue} if Subbestblock: = C.savesubblock (Orphanblo CK); Subbestblock.height > Bestblock.height {bestblock = Subbestblock}} return Bestblock}  /pre>

Savesubblock queries for the existence of the next chunk of the current chunk in the lone block cache pool. For example, if the current chunk height is 100, then query for chunks with a block height of 101 in the lone block cache pool. If present, store 101 chunks in the blockchain and delete the chunk from the orphaned block cache pool.

Savesubblock is the implementation of a recursive function. The aim is to find the recursive way of the deepest leaf nodes. For example, the current block height of 100, recursive query out height of 99, 98, 97, such as the height of the block.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.