github.com/koko1123/flow-go-1@v0.29.6/storage/badger/payloads.go (about) 1 package badger 2 3 import ( 4 "errors" 5 "fmt" 6 7 "github.com/dgraph-io/badger/v3" 8 9 "github.com/koko1123/flow-go-1/model/flow" 10 "github.com/koko1123/flow-go-1/storage" 11 "github.com/koko1123/flow-go-1/storage/badger/operation" 12 "github.com/koko1123/flow-go-1/storage/badger/transaction" 13 ) 14 15 type Payloads struct { 16 db *badger.DB 17 index *Index 18 guarantees *Guarantees 19 seals *Seals 20 receipts *ExecutionReceipts 21 results *ExecutionResults 22 } 23 24 func NewPayloads(db *badger.DB, index *Index, guarantees *Guarantees, seals *Seals, receipts *ExecutionReceipts, 25 results *ExecutionResults) *Payloads { 26 27 p := &Payloads{ 28 db: db, 29 index: index, 30 guarantees: guarantees, 31 seals: seals, 32 receipts: receipts, 33 results: results, 34 } 35 36 return p 37 } 38 39 func (p *Payloads) storeTx(blockID flow.Identifier, payload *flow.Payload) func(*transaction.Tx) error { 40 // For correct payloads, the execution result is part of the payload or it's already stored 41 // in storage. If execution result is not present in either of those places, we error. 42 // ATTENTION: this is unnecessarily complex if we have execution receipt which points an execution result 43 // which is not included in current payload but was incorporated in one of previous blocks. 44 45 return func(tx *transaction.Tx) error { 46 47 resultsByID := payload.Results.Lookup() 48 fullReceipts := make([]*flow.ExecutionReceipt, 0, len(payload.Receipts)) 49 var err error 50 for _, meta := range payload.Receipts { 51 result, ok := resultsByID[meta.ResultID] 52 if !ok { 53 result, err = p.results.ByIDTx(meta.ResultID)(tx) 54 if err != nil { 55 if errors.Is(err, storage.ErrNotFound) { 56 err = fmt.Errorf("invalid payload referencing unknown execution result %v, err: %w", meta.ResultID, err) 57 } 58 return err 59 } 60 } 61 fullReceipts = append(fullReceipts, flow.ExecutionReceiptFromMeta(*meta, *result)) 62 } 63 64 // make sure all payload guarantees are stored 65 for _, guarantee := range payload.Guarantees { 66 err := p.guarantees.storeTx(guarantee)(tx) 67 if err != nil { 68 return fmt.Errorf("could not store guarantee: %w", err) 69 } 70 } 71 72 // make sure all payload seals are stored 73 for _, seal := range payload.Seals { 74 err := p.seals.storeTx(seal)(tx) 75 if err != nil { 76 return fmt.Errorf("could not store seal: %w", err) 77 } 78 } 79 80 // store all payload receipts 81 for _, receipt := range fullReceipts { 82 err := p.receipts.storeTx(receipt)(tx) 83 if err != nil { 84 return fmt.Errorf("could not store receipt: %w", err) 85 } 86 } 87 88 // store the index 89 err = p.index.storeTx(blockID, payload.Index())(tx) 90 if err != nil { 91 return fmt.Errorf("could not store index: %w", err) 92 } 93 94 return nil 95 } 96 } 97 98 func (p *Payloads) retrieveTx(blockID flow.Identifier) func(tx *badger.Txn) (*flow.Payload, error) { 99 return func(tx *badger.Txn) (*flow.Payload, error) { 100 101 // retrieve the index 102 idx, err := p.index.retrieveTx(blockID)(tx) 103 if err != nil { 104 return nil, fmt.Errorf("could not retrieve index: %w", err) 105 } 106 107 // retrieve guarantees 108 guarantees := make([]*flow.CollectionGuarantee, 0, len(idx.CollectionIDs)) 109 for _, collID := range idx.CollectionIDs { 110 guarantee, err := p.guarantees.retrieveTx(collID)(tx) 111 if err != nil { 112 return nil, fmt.Errorf("could not retrieve guarantee (%x): %w", collID, err) 113 } 114 guarantees = append(guarantees, guarantee) 115 } 116 117 // retrieve seals 118 seals := make([]*flow.Seal, 0, len(idx.SealIDs)) 119 for _, sealID := range idx.SealIDs { 120 seal, err := p.seals.retrieveTx(sealID)(tx) 121 if err != nil { 122 return nil, fmt.Errorf("could not retrieve seal (%x): %w", sealID, err) 123 } 124 seals = append(seals, seal) 125 } 126 127 // retrieve receipts 128 receipts := make([]*flow.ExecutionReceiptMeta, 0, len(idx.ReceiptIDs)) 129 for _, recID := range idx.ReceiptIDs { 130 receipt, err := p.receipts.byID(recID)(tx) 131 if err != nil { 132 return nil, fmt.Errorf("could not retrieve receipt %x: %w", recID, err) 133 } 134 receipts = append(receipts, receipt.Meta()) 135 } 136 137 // retrieve results 138 results := make([]*flow.ExecutionResult, 0, len(idx.ResultIDs)) 139 for _, resID := range idx.ResultIDs { 140 result, err := p.results.byID(resID)(tx) 141 if err != nil { 142 return nil, fmt.Errorf("could not retrieve result %x: %w", resID, err) 143 } 144 results = append(results, result) 145 } 146 payload := &flow.Payload{ 147 Seals: seals, 148 Guarantees: guarantees, 149 Receipts: receipts, 150 Results: results, 151 } 152 153 return payload, nil 154 } 155 } 156 157 func (p *Payloads) Store(blockID flow.Identifier, payload *flow.Payload) error { 158 return operation.RetryOnConflictTx(p.db, transaction.Update, p.storeTx(blockID, payload)) 159 } 160 161 func (p *Payloads) ByBlockID(blockID flow.Identifier) (*flow.Payload, error) { 162 tx := p.db.NewTransaction(false) 163 defer tx.Discard() 164 return p.retrieveTx(blockID)(tx) 165 }