github.com/onflow/flow-go@v0.33.17/storage/badger/seals.go (about) 1 // (c) 2019 Dapper Labs - ALL RIGHTS RESERVED 2 3 package badger 4 5 import ( 6 "fmt" 7 8 "github.com/dgraph-io/badger/v2" 9 10 "github.com/onflow/flow-go/model/flow" 11 "github.com/onflow/flow-go/module" 12 "github.com/onflow/flow-go/module/metrics" 13 "github.com/onflow/flow-go/storage/badger/operation" 14 "github.com/onflow/flow-go/storage/badger/transaction" 15 ) 16 17 type Seals struct { 18 db *badger.DB 19 cache *Cache[flow.Identifier, *flow.Seal] 20 } 21 22 func NewSeals(collector module.CacheMetrics, db *badger.DB) *Seals { 23 24 store := func(sealID flow.Identifier, seal *flow.Seal) func(*transaction.Tx) error { 25 return transaction.WithTx(operation.SkipDuplicates(operation.InsertSeal(sealID, seal))) 26 } 27 28 retrieve := func(sealID flow.Identifier) func(*badger.Txn) (*flow.Seal, error) { 29 return func(tx *badger.Txn) (*flow.Seal, error) { 30 var seal flow.Seal 31 err := operation.RetrieveSeal(sealID, &seal)(tx) 32 return &seal, err 33 } 34 } 35 36 s := &Seals{ 37 db: db, 38 cache: newCache[flow.Identifier, *flow.Seal](collector, metrics.ResourceSeal, 39 withLimit[flow.Identifier, *flow.Seal](flow.DefaultTransactionExpiry+100), 40 withStore(store), 41 withRetrieve(retrieve)), 42 } 43 44 return s 45 } 46 47 func (s *Seals) storeTx(seal *flow.Seal) func(*transaction.Tx) error { 48 return s.cache.PutTx(seal.ID(), seal) 49 } 50 51 func (s *Seals) retrieveTx(sealID flow.Identifier) func(*badger.Txn) (*flow.Seal, error) { 52 return func(tx *badger.Txn) (*flow.Seal, error) { 53 val, err := s.cache.Get(sealID)(tx) 54 if err != nil { 55 return nil, err 56 } 57 return val, err 58 } 59 } 60 61 func (s *Seals) Store(seal *flow.Seal) error { 62 return operation.RetryOnConflictTx(s.db, transaction.Update, s.storeTx(seal)) 63 } 64 65 func (s *Seals) ByID(sealID flow.Identifier) (*flow.Seal, error) { 66 tx := s.db.NewTransaction(false) 67 defer tx.Discard() 68 return s.retrieveTx(sealID)(tx) 69 } 70 71 // HighestInFork retrieves the highest seal that was included in the 72 // fork up to (and including) blockID. This method should return a seal 73 // for any block known to the node. Returns storage.ErrNotFound if 74 // blockID is unknown. 75 func (s *Seals) HighestInFork(blockID flow.Identifier) (*flow.Seal, error) { 76 var sealID flow.Identifier 77 err := s.db.View(operation.LookupLatestSealAtBlock(blockID, &sealID)) 78 if err != nil { 79 return nil, fmt.Errorf("failed to retrieve seal for fork with head %x: %w", blockID, err) 80 } 81 return s.ByID(sealID) 82 } 83 84 // FinalizedSealForBlock returns the seal for the given block, only if that seal 85 // has been included in a finalized block. 86 // Returns storage.ErrNotFound if the block is unknown or unsealed. 87 func (s *Seals) FinalizedSealForBlock(blockID flow.Identifier) (*flow.Seal, error) { 88 var sealID flow.Identifier 89 err := s.db.View(operation.LookupBySealedBlockID(blockID, &sealID)) 90 if err != nil { 91 return nil, fmt.Errorf("failed to retrieve seal for block %x: %w", blockID, err) 92 } 93 return s.ByID(sealID) 94 }