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 }