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  }