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