github.com/koko1123/flow-go-1@v0.29.6/storage/badger/procedure/children.go (about)

     1  package procedure
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  
     7  	"github.com/dgraph-io/badger/v3"
     8  
     9  	"github.com/koko1123/flow-go-1/model/flow"
    10  	"github.com/koko1123/flow-go-1/storage"
    11  	"github.com/koko1123/flow-go-1/storage/badger/operation"
    12  )
    13  
    14  // IndexNewBlock will add parent-child index for the new block.
    15  //   - Each block has a parent, we use this parent-child relationship to build a reverse index
    16  //   - for looking up children blocks for a given block. This is useful for forks recovery
    17  //     where we want to find all the pending children blocks for the lastest finalized block.
    18  //
    19  // When adding parent-child index for a new block, we will add two indexes:
    20  //  1. since it's a new block, the new block should have no child, so adding an empty
    21  //     index for the new block. Note: It's impossible there is a block whose parent is the
    22  //     new block.
    23  //  2. since the parent block has this new block as a child, adding an index for that.
    24  //     there are two special cases for (2):
    25  //     - if the parent block is zero, then we don't need to add this index.
    26  //     - if the parent block doesn't exist, then we will insert the child index instead of updating
    27  func IndexNewBlock(blockID flow.Identifier, parentID flow.Identifier) func(*badger.Txn) error {
    28  	return func(tx *badger.Txn) error {
    29  		// Step 1: index the child for the new block.
    30  		// the new block has no child, so adding an empty child index for it
    31  		err := operation.InsertBlockChildren(blockID, nil)(tx)
    32  		if err != nil {
    33  			return fmt.Errorf("could not insert empty block children: %w", err)
    34  		}
    35  
    36  		// Step 2: adding the second index for the parent block
    37  		// if the parent block is zero, for instance root block has no parent,
    38  		// then no need to add index for it
    39  		if parentID == flow.ZeroID {
    40  			return nil
    41  		}
    42  
    43  		// if the parent block is not zero, depending on whether the parent block has
    44  		// children or not, we will either update the index or insert the index:
    45  		// when parent block doesn't exist, we will insert the block children.
    46  		// when parent block exists already, we will update the block children,
    47  		var childrenIDs flow.IdentifierList
    48  		err = operation.RetrieveBlockChildren(parentID, &childrenIDs)(tx)
    49  
    50  		var saveIndex func(blockID flow.Identifier, childrenIDs flow.IdentifierList) func(*badger.Txn) error
    51  		if errors.Is(err, storage.ErrNotFound) {
    52  			saveIndex = operation.InsertBlockChildren
    53  		} else if err != nil {
    54  			return fmt.Errorf("could not look up block children: %w", err)
    55  		} else { // err == nil
    56  			saveIndex = operation.UpdateBlockChildren
    57  		}
    58  
    59  		// check we don't add a duplicate
    60  		for _, dupID := range childrenIDs {
    61  			if blockID == dupID {
    62  				return storage.ErrAlreadyExists
    63  			}
    64  		}
    65  
    66  		// adding the new block to be another child of the parent
    67  		childrenIDs = append(childrenIDs, blockID)
    68  
    69  		// saving the index
    70  		err = saveIndex(parentID, childrenIDs)(tx)
    71  		if err != nil {
    72  			return fmt.Errorf("could not update children index: %w", err)
    73  		}
    74  
    75  		return nil
    76  	}
    77  }
    78  
    79  // LookupBlockChildren looks up the IDs of all child blocks of the given parent block.
    80  func LookupBlockChildren(blockID flow.Identifier, childrenIDs *flow.IdentifierList) func(tx *badger.Txn) error {
    81  	return operation.RetrieveBlockChildren(blockID, childrenIDs)
    82  }