github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/state/cluster/badger/snapshot.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/cluster"
     9  	"github.com/onflow/flow-go/model/flow"
    10  	"github.com/onflow/flow-go/storage/badger/operation"
    11  	"github.com/onflow/flow-go/storage/badger/procedure"
    12  )
    13  
    14  // Snapshot represents a snapshot of chain state anchored at a particular
    15  // reference block.
    16  type Snapshot struct {
    17  	err     error
    18  	state   *State
    19  	blockID flow.Identifier
    20  }
    21  
    22  func (s *Snapshot) Collection() (*flow.Collection, error) {
    23  	if s.err != nil {
    24  		return nil, s.err
    25  	}
    26  
    27  	var collection flow.Collection
    28  	err := s.state.db.View(func(tx *badger.Txn) error {
    29  
    30  		// get the header for this snapshot
    31  		var header flow.Header
    32  		err := s.head(&header)(tx)
    33  		if err != nil {
    34  			return fmt.Errorf("failed to get snapshot header: %w", err)
    35  		}
    36  
    37  		// get the payload
    38  		var payload cluster.Payload
    39  		err = procedure.RetrieveClusterPayload(header.ID(), &payload)(tx)
    40  		if err != nil {
    41  			return fmt.Errorf("failed to get snapshot payload: %w", err)
    42  		}
    43  
    44  		// set the collection
    45  		collection = payload.Collection
    46  
    47  		return nil
    48  	})
    49  
    50  	return &collection, err
    51  }
    52  
    53  func (s *Snapshot) Head() (*flow.Header, error) {
    54  	if s.err != nil {
    55  		return nil, s.err
    56  	}
    57  
    58  	var head flow.Header
    59  	err := s.state.db.View(func(tx *badger.Txn) error {
    60  		return s.head(&head)(tx)
    61  	})
    62  	return &head, err
    63  }
    64  
    65  func (s *Snapshot) Pending() ([]flow.Identifier, error) {
    66  	if s.err != nil {
    67  		return nil, s.err
    68  	}
    69  	return s.pending(s.blockID)
    70  }
    71  
    72  // head finds the header referenced by the snapshot.
    73  func (s *Snapshot) head(head *flow.Header) func(*badger.Txn) error {
    74  	return func(tx *badger.Txn) error {
    75  
    76  		// get the snapshot header
    77  		err := operation.RetrieveHeader(s.blockID, head)(tx)
    78  		if err != nil {
    79  			return fmt.Errorf("could not retrieve header for block (%s): %w", s.blockID, err)
    80  		}
    81  
    82  		return nil
    83  	}
    84  }
    85  
    86  func (s *Snapshot) pending(blockID flow.Identifier) ([]flow.Identifier, error) {
    87  
    88  	var pendingIDs flow.IdentifierList
    89  	err := s.state.db.View(procedure.LookupBlockChildren(blockID, &pendingIDs))
    90  	if err != nil {
    91  		return nil, fmt.Errorf("could not get pending children: %w", err)
    92  	}
    93  
    94  	for _, pendingID := range pendingIDs {
    95  		additionalIDs, err := s.pending(pendingID)
    96  		if err != nil {
    97  			return nil, fmt.Errorf("could not get pending grandchildren: %w", err)
    98  		}
    99  		pendingIDs = append(pendingIDs, additionalIDs...)
   100  	}
   101  	return pendingIDs, nil
   102  }