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 }