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  }