github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/storage/badger/blocks.go (about) 1 package badger 2 3 import ( 4 "fmt" 5 6 "github.com/dgraph-io/badger/v2" 7 8 "github.com/onflow/flow-go/model/flow" 9 "github.com/onflow/flow-go/storage/badger/operation" 10 "github.com/onflow/flow-go/storage/badger/transaction" 11 ) 12 13 // Blocks implements a simple block storage around a badger DB. 14 type Blocks struct { 15 db *badger.DB 16 headers *Headers 17 payloads *Payloads 18 } 19 20 // NewBlocks ... 21 func NewBlocks(db *badger.DB, headers *Headers, payloads *Payloads) *Blocks { 22 b := &Blocks{ 23 db: db, 24 headers: headers, 25 payloads: payloads, 26 } 27 return b 28 } 29 30 func (b *Blocks) StoreTx(block *flow.Block) func(*transaction.Tx) error { 31 return func(tx *transaction.Tx) error { 32 err := b.headers.storeTx(block.Header)(tx) 33 if err != nil { 34 return fmt.Errorf("could not store header %v: %w", block.Header.ID(), err) 35 } 36 err = b.payloads.storeTx(block.ID(), block.Payload)(tx) 37 if err != nil { 38 return fmt.Errorf("could not store payload: %w", err) 39 } 40 return nil 41 } 42 } 43 44 func (b *Blocks) retrieveTx(blockID flow.Identifier) func(*badger.Txn) (*flow.Block, error) { 45 return func(tx *badger.Txn) (*flow.Block, error) { 46 header, err := b.headers.retrieveTx(blockID)(tx) 47 if err != nil { 48 return nil, fmt.Errorf("could not retrieve header: %w", err) 49 } 50 payload, err := b.payloads.retrieveTx(blockID)(tx) 51 if err != nil { 52 return nil, fmt.Errorf("could not retrieve payload: %w", err) 53 } 54 block := &flow.Block{ 55 Header: header, 56 Payload: payload, 57 } 58 return block, nil 59 } 60 } 61 62 // Store ... 63 func (b *Blocks) Store(block *flow.Block) error { 64 return operation.RetryOnConflictTx(b.db, transaction.Update, b.StoreTx(block)) 65 } 66 67 // ByID ... 68 func (b *Blocks) ByID(blockID flow.Identifier) (*flow.Block, error) { 69 tx := b.db.NewTransaction(false) 70 defer tx.Discard() 71 return b.retrieveTx(blockID)(tx) 72 } 73 74 // ByHeight ... 75 func (b *Blocks) ByHeight(height uint64) (*flow.Block, error) { 76 tx := b.db.NewTransaction(false) 77 defer tx.Discard() 78 79 blockID, err := b.headers.retrieveIdByHeightTx(height)(tx) 80 if err != nil { 81 return nil, err 82 } 83 return b.retrieveTx(blockID)(tx) 84 } 85 86 // ByCollectionID ... 87 func (b *Blocks) ByCollectionID(collID flow.Identifier) (*flow.Block, error) { 88 var blockID flow.Identifier 89 err := b.db.View(operation.LookupCollectionBlock(collID, &blockID)) 90 if err != nil { 91 return nil, fmt.Errorf("could not look up block: %w", err) 92 } 93 return b.ByID(blockID) 94 } 95 96 // IndexBlockForCollections ... 97 func (b *Blocks) IndexBlockForCollections(blockID flow.Identifier, collIDs []flow.Identifier) error { 98 for _, collID := range collIDs { 99 err := operation.RetryOnConflict(b.db.Update, operation.SkipDuplicates(operation.IndexCollectionBlock(collID, blockID))) 100 if err != nil { 101 return fmt.Errorf("could not index collection block (%x): %w", collID, err) 102 } 103 } 104 return nil 105 }