github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/engine/execution/block_result.go (about) 1 package execution 2 3 import ( 4 "github.com/onflow/flow-go/fvm/storage/snapshot" 5 "github.com/onflow/flow-go/model/flow" 6 "github.com/onflow/flow-go/module/executiondatasync/execution_data" 7 "github.com/onflow/flow-go/module/mempool/entity" 8 ) 9 10 // BlockExecutionResult captures artifacts of execution of block collections 11 type BlockExecutionResult struct { 12 *entity.ExecutableBlock 13 14 collectionExecutionResults []CollectionExecutionResult 15 ExecutionDataRoot *flow.BlockExecutionDataRoot // full root data structure produced from block 16 } 17 18 // NewPopulatedBlockExecutionResult constructs a new BlockExecutionResult, 19 // pre-populated with `chunkCounts` number of collection results 20 func NewPopulatedBlockExecutionResult(eb *entity.ExecutableBlock) *BlockExecutionResult { 21 chunkCounts := len(eb.CompleteCollections) + 1 22 return &BlockExecutionResult{ 23 ExecutableBlock: eb, 24 collectionExecutionResults: make([]CollectionExecutionResult, chunkCounts), 25 } 26 } 27 28 // Size returns the size of collection execution results 29 func (er *BlockExecutionResult) Size() int { 30 return len(er.collectionExecutionResults) 31 } 32 33 func (er *BlockExecutionResult) CollectionExecutionResultAt(colIndex int) *CollectionExecutionResult { 34 if colIndex < 0 && colIndex > len(er.collectionExecutionResults) { 35 return nil 36 } 37 return &er.collectionExecutionResults[colIndex] 38 } 39 40 func (er *BlockExecutionResult) AllEvents() flow.EventsList { 41 res := make(flow.EventsList, 0) 42 for _, ce := range er.collectionExecutionResults { 43 if len(ce.events) > 0 { 44 res = append(res, ce.events...) 45 } 46 } 47 return res 48 } 49 50 func (er *BlockExecutionResult) AllServiceEvents() flow.EventsList { 51 res := make(flow.EventsList, 0) 52 for _, ce := range er.collectionExecutionResults { 53 if len(ce.serviceEvents) > 0 { 54 res = append(res, ce.serviceEvents...) 55 } 56 } 57 return res 58 } 59 60 func (er *BlockExecutionResult) TransactionResultAt(txIdx int) *flow.TransactionResult { 61 allTxResults := er.AllTransactionResults() // TODO: optimize me 62 if txIdx > len(allTxResults) { 63 return nil 64 } 65 return &allTxResults[txIdx] 66 } 67 68 func (er *BlockExecutionResult) AllTransactionResults() flow.TransactionResults { 69 res := make(flow.TransactionResults, 0) 70 for _, ce := range er.collectionExecutionResults { 71 if len(ce.transactionResults) > 0 { 72 res = append(res, ce.transactionResults...) 73 } 74 } 75 return res 76 } 77 78 func (er *BlockExecutionResult) AllExecutionSnapshots() []*snapshot.ExecutionSnapshot { 79 res := make([]*snapshot.ExecutionSnapshot, 0) 80 for _, ce := range er.collectionExecutionResults { 81 es := ce.ExecutionSnapshot() 82 res = append(res, es) 83 } 84 return res 85 } 86 87 func (er *BlockExecutionResult) AllConvertedServiceEvents() flow.ServiceEventList { 88 res := make(flow.ServiceEventList, 0) 89 for _, ce := range er.collectionExecutionResults { 90 if len(ce.convertedServiceEvents) > 0 { 91 res = append(res, ce.convertedServiceEvents...) 92 } 93 } 94 return res 95 } 96 97 // AllUpdatedRegisters returns all updated unique register entries 98 // Note: order is not determinstic 99 func (er *BlockExecutionResult) AllUpdatedRegisters() []flow.RegisterEntry { 100 updates := make(map[flow.RegisterID]flow.RegisterValue) 101 for _, ce := range er.collectionExecutionResults { 102 for regID, regVal := range ce.executionSnapshot.WriteSet { 103 updates[regID] = regVal 104 } 105 } 106 res := make([]flow.RegisterEntry, 0, len(updates)) 107 for regID, regVal := range updates { 108 res = append(res, flow.RegisterEntry{ 109 Key: regID, 110 Value: regVal, 111 }) 112 } 113 return res 114 } 115 116 // BlockAttestationResult holds collection attestation results 117 type BlockAttestationResult struct { 118 *BlockExecutionResult 119 120 collectionAttestationResults []CollectionAttestationResult 121 122 // TODO(ramtin): move this to the outside, everything needed for create this 123 // should be available as part of computation result and most likely trieUpdate 124 // was the reason this is kept here, long term we don't need this data and should 125 // act based on register deltas 126 *execution_data.BlockExecutionData 127 } 128 129 func NewEmptyBlockAttestationResult( 130 blockExecutionResult *BlockExecutionResult, 131 ) *BlockAttestationResult { 132 colSize := blockExecutionResult.Size() 133 return &BlockAttestationResult{ 134 BlockExecutionResult: blockExecutionResult, 135 collectionAttestationResults: make([]CollectionAttestationResult, 0, colSize), 136 BlockExecutionData: &execution_data.BlockExecutionData{ 137 BlockID: blockExecutionResult.ID(), 138 ChunkExecutionDatas: make( 139 []*execution_data.ChunkExecutionData, 140 0, 141 colSize), 142 }, 143 } 144 } 145 146 // CollectionAttestationResultAt returns CollectionAttestationResult at collection index 147 func (ar *BlockAttestationResult) CollectionAttestationResultAt(colIndex int) *CollectionAttestationResult { 148 if colIndex < 0 && colIndex > len(ar.collectionAttestationResults) { 149 return nil 150 } 151 return &ar.collectionAttestationResults[colIndex] 152 } 153 154 func (ar *BlockAttestationResult) AppendCollectionAttestationResult( 155 startStateCommit flow.StateCommitment, 156 endStateCommit flow.StateCommitment, 157 stateProof flow.StorageProof, 158 eventCommit flow.Identifier, 159 chunkExecutionDatas *execution_data.ChunkExecutionData, 160 ) { 161 ar.collectionAttestationResults = append(ar.collectionAttestationResults, 162 CollectionAttestationResult{ 163 startStateCommit: startStateCommit, 164 endStateCommit: endStateCommit, 165 stateProof: stateProof, 166 eventCommit: eventCommit, 167 }, 168 ) 169 ar.ChunkExecutionDatas = append(ar.ChunkExecutionDatas, chunkExecutionDatas) 170 } 171 172 func (ar *BlockAttestationResult) AllChunks() []*flow.Chunk { 173 chunks := make([]*flow.Chunk, len(ar.collectionAttestationResults)) 174 for i := 0; i < len(ar.collectionAttestationResults); i++ { 175 chunks[i] = ar.ChunkAt(i) // TODO(ramtin): cache and optimize this 176 } 177 return chunks 178 } 179 180 func (ar *BlockAttestationResult) ChunkAt(index int) *flow.Chunk { 181 if index < 0 || index >= len(ar.collectionAttestationResults) { 182 return nil 183 } 184 185 execRes := ar.collectionExecutionResults[index] 186 attestRes := ar.collectionAttestationResults[index] 187 188 return flow.NewChunk( 189 ar.Block.ID(), 190 index, 191 attestRes.startStateCommit, 192 len(execRes.TransactionResults()), 193 attestRes.eventCommit, 194 attestRes.endStateCommit, 195 execRes.executionSnapshot.TotalComputationUsed(), 196 ) 197 } 198 199 func (ar *BlockAttestationResult) AllChunkDataPacks() []*flow.ChunkDataPack { 200 chunkDataPacks := make([]*flow.ChunkDataPack, len(ar.collectionAttestationResults)) 201 for i := 0; i < len(ar.collectionAttestationResults); i++ { 202 chunkDataPacks[i] = ar.ChunkDataPackAt(i) // TODO(ramtin): cache and optimize this 203 } 204 return chunkDataPacks 205 } 206 207 func (ar *BlockAttestationResult) ChunkDataPackAt(index int) *flow.ChunkDataPack { 208 if index < 0 || index >= len(ar.collectionAttestationResults) { 209 return nil 210 } 211 212 // Note: There's some inconsistency in how chunk execution data and 213 // chunk data pack populate their collection fields when the collection 214 // is the system collection. 215 // collectionAt would return nil if the collection is system collection 216 collection := ar.CollectionAt(index) 217 218 attestRes := ar.collectionAttestationResults[index] 219 220 return flow.NewChunkDataPack( 221 ar.ChunkAt(index).ID(), // TODO(ramtin): optimize this 222 attestRes.startStateCommit, 223 attestRes.stateProof, 224 collection, 225 *ar.ExecutionDataRoot, 226 ) 227 } 228 229 func (ar *BlockAttestationResult) AllEventCommitments() []flow.Identifier { 230 res := make([]flow.Identifier, 0) 231 for _, ca := range ar.collectionAttestationResults { 232 res = append(res, ca.EventCommitment()) 233 } 234 return res 235 } 236 237 // Size returns the size of collection attestation results 238 func (ar *BlockAttestationResult) Size() int { 239 return len(ar.collectionAttestationResults) 240 }