github.com/koko1123/flow-go-1@v0.29.6/storage/badger/blocks.go (about) 1 // (c) 2019 Dapper Labs - ALL RIGHTS RESERVED 2 3 package badger 4 5 import ( 6 "errors" 7 "fmt" 8 9 "github.com/dgraph-io/badger/v3" 10 11 "github.com/koko1123/flow-go-1/model/flow" 12 "github.com/koko1123/flow-go-1/storage" 13 "github.com/koko1123/flow-go-1/storage/badger/operation" 14 "github.com/koko1123/flow-go-1/storage/badger/transaction" 15 ) 16 17 // Blocks implements a simple block storage around a badger DB. 18 type Blocks struct { 19 db *badger.DB 20 headers *Headers 21 payloads *Payloads 22 } 23 24 // NewBlocks ... 25 func NewBlocks(db *badger.DB, headers *Headers, payloads *Payloads) *Blocks { 26 b := &Blocks{ 27 db: db, 28 headers: headers, 29 payloads: payloads, 30 } 31 return b 32 } 33 34 func (b *Blocks) StoreTx(block *flow.Block) func(*transaction.Tx) error { 35 return func(tx *transaction.Tx) error { 36 err := b.headers.storeTx(block.Header)(tx) 37 if err != nil { 38 return fmt.Errorf("could not store header: %w", err) 39 } 40 err = b.payloads.storeTx(block.ID(), block.Payload)(tx) 41 if err != nil { 42 return fmt.Errorf("could not store payload: %w", err) 43 } 44 return nil 45 } 46 } 47 48 func (b *Blocks) retrieveTx(blockID flow.Identifier) func(*badger.Txn) (*flow.Block, error) { 49 return func(tx *badger.Txn) (*flow.Block, error) { 50 header, err := b.headers.retrieveTx(blockID)(tx) 51 if err != nil { 52 return nil, fmt.Errorf("could not retrieve header: %w", err) 53 } 54 payload, err := b.payloads.retrieveTx(blockID)(tx) 55 if err != nil { 56 return nil, fmt.Errorf("could not retrieve payload: %w", err) 57 } 58 block := &flow.Block{ 59 Header: header, 60 Payload: payload, 61 } 62 return block, nil 63 } 64 } 65 66 // Store ... 67 func (b *Blocks) Store(block *flow.Block) error { 68 return operation.RetryOnConflictTx(b.db, transaction.Update, b.StoreTx(block)) 69 } 70 71 // ByID ... 72 func (b *Blocks) ByID(blockID flow.Identifier) (*flow.Block, error) { 73 tx := b.db.NewTransaction(false) 74 defer tx.Discard() 75 return b.retrieveTx(blockID)(tx) 76 } 77 78 // ByHeight ... 79 func (b *Blocks) ByHeight(height uint64) (*flow.Block, error) { 80 tx := b.db.NewTransaction(false) 81 defer tx.Discard() 82 83 blockID, err := b.headers.retrieveIdByHeightTx(height)(tx) 84 if err != nil { 85 return nil, err 86 } 87 return b.retrieveTx(blockID)(tx) 88 } 89 90 // ByCollectionID ... 91 func (b *Blocks) ByCollectionID(collID flow.Identifier) (*flow.Block, error) { 92 var blockID flow.Identifier 93 err := b.db.View(operation.LookupCollectionBlock(collID, &blockID)) 94 if err != nil { 95 return nil, fmt.Errorf("could not look up block: %w", err) 96 } 97 return b.ByID(blockID) 98 } 99 100 // IndexBlockForCollections ... 101 func (b *Blocks) IndexBlockForCollections(blockID flow.Identifier, collIDs []flow.Identifier) error { 102 for _, collID := range collIDs { 103 err := operation.RetryOnConflict(b.db.Update, operation.SkipDuplicates(operation.IndexCollectionBlock(collID, blockID))) 104 if err != nil { 105 return fmt.Errorf("could not index collection block (%x): %w", collID, err) 106 } 107 } 108 return nil 109 } 110 111 // InsertLastFullBlockHeightIfNotExists inserts the last full block height 112 func (b *Blocks) InsertLastFullBlockHeightIfNotExists(height uint64) error { 113 return operation.RetryOnConflict(b.db.Update, func(tx *badger.Txn) error { 114 err := operation.InsertLastCompleteBlockHeightIfNotExists(height)(tx) 115 if err != nil { 116 return fmt.Errorf("could not set LastFullBlockHeight: %w", err) 117 } 118 return nil 119 }) 120 } 121 122 // UpdateLastFullBlockHeight upsert (update or insert) the last full block height 123 func (b *Blocks) UpdateLastFullBlockHeight(height uint64) error { 124 return operation.RetryOnConflict(b.db.Update, func(tx *badger.Txn) error { 125 126 // try to update 127 err := operation.UpdateLastCompleteBlockHeight(height)(tx) 128 if err == nil { 129 return nil 130 } 131 132 if !errors.Is(err, storage.ErrNotFound) { 133 return fmt.Errorf("could not update LastFullBlockHeight: %w", err) 134 } 135 136 // if key does not exist, try insert. 137 err = operation.InsertLastCompleteBlockHeight(height)(tx) 138 if err != nil { 139 return fmt.Errorf("could not insert LastFullBlockHeight: %w", err) 140 } 141 142 return nil 143 }) 144 } 145 146 // GetLastFullBlockHeight ... 147 func (b *Blocks) GetLastFullBlockHeight() (uint64, error) { 148 var h uint64 149 err := b.db.View(operation.RetrieveLastCompleteBlockHeight(&h)) 150 if err != nil { 151 return 0, fmt.Errorf("failed to retrieve LastFullBlockHeight: %w", err) 152 } 153 return h, nil 154 }