github.com/koko1123/flow-go-1@v0.29.6/model/flow/execution_result.go (about) 1 package flow 2 3 import ( 4 "encoding/json" 5 "errors" 6 ) 7 8 var ErrNoChunks = errors.New("execution result has no chunks") 9 10 // ExecutionResult is cryptographic commitment to the computation 11 // result(s) from executing a block 12 type ExecutionResult struct { 13 PreviousResultID Identifier // commit of the previous ER 14 BlockID Identifier // commit of the current block 15 Chunks ChunkList 16 ServiceEvents ServiceEventList 17 ExecutionDataID Identifier 18 } 19 20 // ID returns the hash of the execution result body 21 func (er ExecutionResult) ID() Identifier { 22 return MakeID(er) 23 } 24 25 // Checksum ... 26 func (er ExecutionResult) Checksum() Identifier { 27 return MakeID(er) 28 } 29 30 // ValidateChunksLength checks whether the number of chuncks is zero. 31 // 32 // It returns false if the number of chunks is zero (invalid). 33 // By protocol definition, each ExecutionReceipt must contain at least one 34 // chunk (system chunk). 35 func (er ExecutionResult) ValidateChunksLength() bool { 36 return er.Chunks.Len() != 0 37 } 38 39 // FinalStateCommitment returns the Execution Result's commitment to the final 40 // execution state of the block, i.e. the last chunk's output state. 41 // Error returns: 42 // - ErrNoChunks: if there are no chunks (ExecutionResult is malformed) 43 func (er ExecutionResult) FinalStateCommitment() (StateCommitment, error) { 44 if !er.ValidateChunksLength() { 45 return DummyStateCommitment, ErrNoChunks 46 } 47 return er.Chunks[er.Chunks.Len()-1].EndState, nil 48 } 49 50 // InitialStateCommit returns a commitment to the execution state used as input 51 // for computing the block, i.e. the leading chunk's input state. 52 // Error returns: 53 // - ErrNoChunks: if there are no chunks (ExecutionResult is malformed) 54 func (er ExecutionResult) InitialStateCommit() (StateCommitment, error) { 55 if !er.ValidateChunksLength() { 56 return DummyStateCommitment, ErrNoChunks 57 } 58 return er.Chunks[0].StartState, nil 59 } 60 61 func (er ExecutionResult) MarshalJSON() ([]byte, error) { 62 type Alias ExecutionResult 63 return json.Marshal(struct { 64 Alias 65 ID string 66 }{ 67 Alias: Alias(er), 68 ID: er.ID().String(), 69 }) 70 } 71 72 /******************************************************************************* 73 GROUPING allows to split a list of results by some property 74 *******************************************************************************/ 75 76 // ExecutionResultList is a slice of ExecutionResults with the additional 77 // functionality to group them by various properties 78 type ExecutionResultList []*ExecutionResult 79 80 // ExecutionResultGroupedList is a partition of an ExecutionResultList 81 type ExecutionResultGroupedList map[Identifier]ExecutionResultList 82 83 // ExecutionResultGroupingFunction is a function that assigns an identifier to each ExecutionResult 84 type ExecutionResultGroupingFunction func(*ExecutionResult) Identifier 85 86 // GroupBy partitions the ExecutionResultList. All ExecutionResults that are 87 // mapped by the grouping function to the same identifier are placed in the same group. 88 // Within each group, the order and multiplicity of the ExecutionResults is preserved. 89 func (l ExecutionResultList) GroupBy(grouper ExecutionResultGroupingFunction) ExecutionResultGroupedList { 90 groups := make(map[Identifier]ExecutionResultList) 91 for _, r := range l { 92 groupID := grouper(r) 93 groups[groupID] = append(groups[groupID], r) 94 } 95 return groups 96 } 97 98 // GroupByPreviousResultID partitions the ExecutionResultList by the their PreviousResultIDs. 99 // Within each group, the order and multiplicity of the ExecutionResults is preserved. 100 func (l ExecutionResultList) GroupByPreviousResultID() ExecutionResultGroupedList { 101 grouper := func(r *ExecutionResult) Identifier { return r.PreviousResultID } 102 return l.GroupBy(grouper) 103 } 104 105 // GroupByExecutedBlockID partitions the ExecutionResultList by the IDs of the executed blocks. 106 // Within each group, the order and multiplicity of the ExecutionResults is preserved. 107 func (l ExecutionResultList) GroupByExecutedBlockID() ExecutionResultGroupedList { 108 grouper := func(r *ExecutionResult) Identifier { return r.BlockID } 109 return l.GroupBy(grouper) 110 } 111 112 // Size returns the number of ExecutionResults in the list 113 func (l ExecutionResultList) Size() int { 114 return len(l) 115 } 116 117 // GetGroup returns the ExecutionResults that were mapped to the same identifier by the 118 // grouping function. Returns an empty (nil) ExecutionResultList if groupID does not exist. 119 func (g ExecutionResultGroupedList) GetGroup(groupID Identifier) ExecutionResultList { 120 return g[groupID] 121 } 122 123 // NumberGroups returns the number of groups 124 func (g ExecutionResultGroupedList) NumberGroups() int { 125 return len(g) 126 } 127 128 // Lookup generates a map from ExecutionResult ID to ExecutionResult 129 func (l ExecutionResultList) Lookup() map[Identifier]*ExecutionResult { 130 resultsByID := make(map[Identifier]*ExecutionResult, len(l)) 131 for _, result := range l { 132 resultsByID[result.ID()] = result 133 } 134 return resultsByID 135 }