github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/model/flow/execution_receipt.go (about) 1 package flow 2 3 import ( 4 "encoding/json" 5 6 "github.com/onflow/crypto" 7 ) 8 9 type Spock []byte 10 11 // ExecutionReceipt is the full execution receipt, as sent by the Execution Node. 12 // Specifically, it contains the detailed execution result. 13 type ExecutionReceipt struct { 14 ExecutorID Identifier 15 ExecutionResult 16 Spocks []crypto.Signature 17 ExecutorSignature crypto.Signature 18 } 19 20 // ID returns the canonical ID of the execution receipt. 21 func (er *ExecutionReceipt) ID() Identifier { 22 return er.Meta().ID() 23 } 24 25 // Checksum returns a checksum for the execution receipt including the signatures. 26 func (er *ExecutionReceipt) Checksum() Identifier { 27 return MakeID(er) 28 } 29 30 // Meta returns the receipt metadata for the receipt. 31 func (er *ExecutionReceipt) Meta() *ExecutionReceiptMeta { 32 return &ExecutionReceiptMeta{ 33 ExecutorID: er.ExecutorID, 34 ResultID: er.ExecutionResult.ID(), 35 Spocks: er.Spocks, 36 ExecutorSignature: er.ExecutorSignature, 37 } 38 } 39 40 // ExecutionReceiptMeta contains the fields from the Execution Receipts 41 // that vary from one executor to another (assuming they commit to the same 42 // result). It only contains the ID (cryptographic hash) of the execution 43 // result the receipt commits to. The ExecutionReceiptMeta is useful for 44 // storing results and receipts separately in a composable way. 45 type ExecutionReceiptMeta struct { 46 ExecutorID Identifier 47 ResultID Identifier 48 Spocks []crypto.Signature 49 ExecutorSignature crypto.Signature 50 } 51 52 func ExecutionReceiptFromMeta(meta ExecutionReceiptMeta, result ExecutionResult) *ExecutionReceipt { 53 return &ExecutionReceipt{ 54 ExecutorID: meta.ExecutorID, 55 ExecutionResult: result, 56 Spocks: meta.Spocks, 57 ExecutorSignature: meta.ExecutorSignature, 58 } 59 } 60 61 // ID returns the canonical ID of the execution receipt. 62 // It is identical to the ID of the full receipt. 63 func (er *ExecutionReceiptMeta) ID() Identifier { 64 body := struct { 65 ExecutorID Identifier 66 ResultID Identifier 67 Spocks []crypto.Signature 68 }{ 69 ExecutorID: er.ExecutorID, 70 ResultID: er.ResultID, 71 Spocks: er.Spocks, 72 } 73 return MakeID(body) 74 } 75 76 func (er ExecutionReceiptMeta) MarshalJSON() ([]byte, error) { 77 type Alias ExecutionReceiptMeta 78 return json.Marshal(struct { 79 Alias 80 ID string 81 }{ 82 Alias: Alias(er), 83 ID: er.ID().String(), 84 }) 85 } 86 87 // Checksum returns a checksum for the execution receipt including the signatures. 88 func (er *ExecutionReceiptMeta) Checksum() Identifier { 89 return MakeID(er) 90 } 91 92 /******************************************************************************* 93 GROUPING for full ExecutionReceipts: 94 allows to split a list of receipts by some property 95 *******************************************************************************/ 96 97 // ExecutionReceiptList is a slice of ExecutionReceipts with the additional 98 // functionality to group receipts by various properties 99 type ExecutionReceiptList []*ExecutionReceipt 100 101 // ExecutionReceiptGroupedList is a partition of an ExecutionReceiptList 102 type ExecutionReceiptGroupedList map[Identifier]ExecutionReceiptList 103 104 // ExecutionReceiptGroupingFunction is a function that assigns an identifier to each receipt 105 type ExecutionReceiptGroupingFunction func(*ExecutionReceipt) Identifier 106 107 // GroupBy partitions the ExecutionReceiptList. All receipts that are mapped 108 // by the grouping function to the same identifier are placed in the same group. 109 // Within each group, the order and multiplicity of the receipts is preserved. 110 func (l ExecutionReceiptList) GroupBy(grouper ExecutionReceiptGroupingFunction) ExecutionReceiptGroupedList { 111 groups := make(map[Identifier]ExecutionReceiptList) 112 for _, rcpt := range l { 113 groupID := grouper(rcpt) 114 groups[groupID] = append(groups[groupID], rcpt) 115 } 116 return groups 117 } 118 119 // GroupByExecutorID partitions the ExecutionReceiptList by the receipts' ExecutorIDs. 120 // Within each group, the order and multiplicity of the receipts is preserved. 121 func (l ExecutionReceiptList) GroupByExecutorID() ExecutionReceiptGroupedList { 122 grouper := func(receipt *ExecutionReceipt) Identifier { return receipt.ExecutorID } 123 return l.GroupBy(grouper) 124 } 125 126 // GroupByResultID partitions the ExecutionReceiptList by the receipts' Result IDs. 127 // Within each group, the order and multiplicity of the receipts is preserved. 128 func (l ExecutionReceiptList) GroupByResultID() ExecutionReceiptGroupedList { 129 grouper := func(receipt *ExecutionReceipt) Identifier { return receipt.ExecutionResult.ID() } 130 return l.GroupBy(grouper) 131 } 132 133 // Size returns the number of receipts in the list 134 func (l ExecutionReceiptList) Size() int { 135 return len(l) 136 } 137 138 // GetGroup returns the receipts that were mapped to the same identifier by the 139 // grouping function. Returns an empty (nil) ExecutionReceiptList if groupID does not exist. 140 func (g ExecutionReceiptGroupedList) GetGroup(groupID Identifier) ExecutionReceiptList { 141 return g[groupID] 142 } 143 144 // NumberGroups returns the number of groups 145 func (g ExecutionReceiptGroupedList) NumberGroups() int { 146 return len(g) 147 } 148 149 /******************************************************************************* 150 GROUPING for ExecutionReceiptMeta information: 151 allows to split a list of receipt meta information by some property 152 *******************************************************************************/ 153 154 // ExecutionReceiptMetaList is a slice of ExecutionResultMetas with the additional 155 // functionality to group them by various properties 156 type ExecutionReceiptMetaList []*ExecutionReceiptMeta 157 158 // ExecutionReceiptMetaGroupedList is a partition of an ExecutionReceiptMetaList 159 type ExecutionReceiptMetaGroupedList map[Identifier]ExecutionReceiptMetaList 160 161 // ExecutionReceiptMetaGroupingFunction is a function that assigns an identifier to each receipt meta 162 type ExecutionReceiptMetaGroupingFunction func(*ExecutionReceiptMeta) Identifier 163 164 // GroupBy partitions the ExecutionReceiptMetaList. All receipts that are mapped 165 // by the grouping function to the same identifier are placed in the same group. 166 // Within each group, the order and multiplicity of the receipts is preserved. 167 func (l ExecutionReceiptMetaList) GroupBy(grouper ExecutionReceiptMetaGroupingFunction) ExecutionReceiptMetaGroupedList { 168 groups := make(map[Identifier]ExecutionReceiptMetaList) 169 for _, rcpt := range l { 170 groupID := grouper(rcpt) 171 groups[groupID] = append(groups[groupID], rcpt) 172 } 173 return groups 174 } 175 176 // GroupByExecutorID partitions the ExecutionReceiptMetaList by the receipts' ExecutorIDs. 177 // Within each group, the order and multiplicity of the receipts is preserved. 178 func (l ExecutionReceiptMetaList) GroupByExecutorID() ExecutionReceiptMetaGroupedList { 179 grouper := func(receipt *ExecutionReceiptMeta) Identifier { return receipt.ExecutorID } 180 return l.GroupBy(grouper) 181 } 182 183 // GroupByResultID partitions the ExecutionReceiptMetaList by the receipts' Result IDs. 184 // Within each group, the order and multiplicity of the receipts is preserved. 185 func (l ExecutionReceiptMetaList) GroupByResultID() ExecutionReceiptMetaGroupedList { 186 grouper := func(receipt *ExecutionReceiptMeta) Identifier { return receipt.ResultID } 187 return l.GroupBy(grouper) 188 } 189 190 // Size returns the number of receipts in the list 191 func (l ExecutionReceiptMetaList) Size() int { 192 return len(l) 193 } 194 195 // GetGroup returns the receipts that were mapped to the same identifier by the 196 // grouping function. Returns an empty (nil) ExecutionReceiptMetaList if groupID does not exist. 197 func (g ExecutionReceiptMetaGroupedList) GetGroup(groupID Identifier) ExecutionReceiptMetaList { 198 return g[groupID] 199 } 200 201 // NumberGroups returns the number of groups 202 func (g ExecutionReceiptMetaGroupedList) NumberGroups() int { 203 return len(g) 204 } 205 206 // Lookup generates a map from ExecutionReceipt ID to ExecutionReceiptMeta 207 func (l ExecutionReceiptMetaList) Lookup() map[Identifier]*ExecutionReceiptMeta { 208 receiptsByID := make(map[Identifier]*ExecutionReceiptMeta, len(l)) 209 for _, receipt := range l { 210 receiptsByID[receipt.ID()] = receipt 211 } 212 return receiptsByID 213 }