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