github.com/koko1123/flow-go-1@v0.29.6/model/convert/service_event.go (about) 1 package convert 2 3 import ( 4 "encoding/hex" 5 "fmt" 6 7 "github.com/onflow/cadence" 8 "github.com/onflow/cadence/encoding/json" 9 10 "github.com/onflow/flow-go/crypto" 11 "github.com/koko1123/flow-go-1/fvm/systemcontracts" 12 "github.com/koko1123/flow-go-1/model/flow" 13 "github.com/koko1123/flow-go-1/model/flow/assignment" 14 "github.com/koko1123/flow-go-1/model/flow/order" 15 ) 16 17 // ServiceEvent converts a service event encoded as the generic flow.Event 18 // type to a flow.ServiceEvent type for use within protocol software and protocol 19 // state. This acts as the conversion from the Cadence type to the flow-go type. 20 func ServiceEvent(chainID flow.ChainID, event flow.Event) (*flow.ServiceEvent, error) { 21 22 events, err := systemcontracts.ServiceEventsForChain(chainID) 23 if err != nil { 24 return nil, fmt.Errorf("could not get service event info: %w", err) 25 } 26 27 // depending on type of service event construct Go type 28 switch event.Type { 29 case events.EpochSetup.EventType(): 30 return convertServiceEventEpochSetup(event) 31 case events.EpochCommit.EventType(): 32 return convertServiceEventEpochCommit(event) 33 default: 34 return nil, fmt.Errorf("invalid event type: %s", event.Type) 35 } 36 } 37 38 // convertServiceEventEpochSetup converts a service event encoded as the generic 39 // flow.Event type to a ServiceEvent type for an EpochSetup event 40 func convertServiceEventEpochSetup(event flow.Event) (*flow.ServiceEvent, error) { 41 42 // decode bytes using jsoncdc 43 payload, err := json.Decode(nil, event.Payload) 44 if err != nil { 45 return nil, fmt.Errorf("could not unmarshal event payload: %w", err) 46 } 47 48 // parse cadence types to required fields 49 setup := new(flow.EpochSetup) 50 51 // NOTE: variable names prefixed with cdc represent cadence types 52 cdcEvent, ok := payload.(cadence.Event) 53 if !ok { 54 return nil, invalidCadenceTypeError("payload", payload, cadence.Event{}) 55 } 56 57 if len(cdcEvent.Fields) < 9 { 58 return nil, fmt.Errorf("insufficient fields in EpochSetup event (%d < 9)", len(cdcEvent.Fields)) 59 } 60 61 // extract simple fields 62 counter, ok := cdcEvent.Fields[0].(cadence.UInt64) 63 if !ok { 64 return nil, invalidCadenceTypeError("counter", cdcEvent.Fields[0], cadence.UInt64(0)) 65 } 66 setup.Counter = uint64(counter) 67 firstView, ok := cdcEvent.Fields[2].(cadence.UInt64) 68 if !ok { 69 return nil, invalidCadenceTypeError("firstView", cdcEvent.Fields[2], cadence.UInt64(0)) 70 } 71 setup.FirstView = uint64(firstView) 72 finalView, ok := cdcEvent.Fields[3].(cadence.UInt64) 73 if !ok { 74 return nil, invalidCadenceTypeError("finalView", cdcEvent.Fields[3], cadence.UInt64(0)) 75 } 76 setup.FinalView = uint64(finalView) 77 randomSrcHex, ok := cdcEvent.Fields[5].(cadence.String) 78 if !ok { 79 return nil, invalidCadenceTypeError("randomSource", cdcEvent.Fields[5], cadence.String("")) 80 } 81 // Cadence's unsafeRandom().toString() produces a string of variable length. 82 // Here we pad it with enough 0s to meet the required length. 83 paddedRandomSrcHex := fmt.Sprintf("%0*s", 2*flow.EpochSetupRandomSourceLength, string(randomSrcHex)) 84 setup.RandomSource, err = hex.DecodeString(paddedRandomSrcHex) 85 if err != nil { 86 return nil, fmt.Errorf("could not decode random source hex (%v): %w", paddedRandomSrcHex, err) 87 } 88 89 dkgPhase1FinalView, ok := cdcEvent.Fields[6].(cadence.UInt64) 90 if !ok { 91 return nil, invalidCadenceTypeError("dkgPhase1FinalView", cdcEvent.Fields[6], cadence.UInt64(0)) 92 } 93 setup.DKGPhase1FinalView = uint64(dkgPhase1FinalView) 94 dkgPhase2FinalView, ok := cdcEvent.Fields[7].(cadence.UInt64) 95 if !ok { 96 return nil, invalidCadenceTypeError("dkgPhase2FinalView", cdcEvent.Fields[7], cadence.UInt64(0)) 97 } 98 setup.DKGPhase2FinalView = uint64(dkgPhase2FinalView) 99 dkgPhase3FinalView, ok := cdcEvent.Fields[8].(cadence.UInt64) 100 if !ok { 101 return nil, invalidCadenceTypeError("dkgPhase3FinalView", cdcEvent.Fields[8], cadence.UInt64(0)) 102 } 103 setup.DKGPhase3FinalView = uint64(dkgPhase3FinalView) 104 105 // parse cluster assignments 106 cdcClusters, ok := cdcEvent.Fields[4].(cadence.Array) 107 if !ok { 108 return nil, invalidCadenceTypeError("clusters", cdcEvent.Fields[4], cadence.Array{}) 109 } 110 setup.Assignments, err = convertClusterAssignments(cdcClusters.Values) 111 if err != nil { 112 return nil, fmt.Errorf("could not convert cluster assignments: %w", err) 113 } 114 115 // parse epoch participants 116 cdcParticipants, ok := cdcEvent.Fields[1].(cadence.Array) 117 if !ok { 118 return nil, invalidCadenceTypeError("participants", cdcEvent.Fields[1], cadence.Array{}) 119 } 120 setup.Participants, err = convertParticipants(cdcParticipants.Values) 121 if err != nil { 122 return nil, fmt.Errorf("could not convert participants: %w", err) 123 } 124 125 // construct the service event 126 serviceEvent := &flow.ServiceEvent{ 127 Type: flow.ServiceEventSetup, 128 Event: setup, 129 } 130 131 return serviceEvent, nil 132 } 133 134 // convertServiceEventEpochCommit converts a service event encoded as the generic 135 // flow.Event type to a ServiceEvent type for an EpochCommit event 136 func convertServiceEventEpochCommit(event flow.Event) (*flow.ServiceEvent, error) { 137 138 // decode bytes using jsoncdc 139 payload, err := json.Decode(nil, event.Payload) 140 if err != nil { 141 return nil, fmt.Errorf("could not unmarshal event payload: %w", err) 142 } 143 144 // parse cadence types to Go types 145 commit := new(flow.EpochCommit) 146 commit.Counter = uint64(payload.(cadence.Event).Fields[0].(cadence.UInt64)) 147 148 // parse cluster qc votes 149 cdcClusterQCVotes := payload.(cadence.Event).Fields[1].(cadence.Array).Values 150 commit.ClusterQCs, err = convertClusterQCVotes(cdcClusterQCVotes) 151 if err != nil { 152 return nil, fmt.Errorf("could not convert cluster qc votes: %w", err) 153 } 154 155 // parse DKG group key and participants 156 // Note: this is read in the same order as `DKGClient.SubmitResult` ie. with the group public key first followed by individual keys 157 // https://github.com/koko1123/flow-go-1/blob/feature/dkg/module/dkg/client.go#L182-L183 158 cdcDKGKeys := payload.(cadence.Event).Fields[2].(cadence.Array).Values 159 dkgGroupKey, dkgParticipantKeys, err := convertDKGKeys(cdcDKGKeys) 160 if err != nil { 161 return nil, fmt.Errorf("could not convert DKG keys: %w", err) 162 } 163 164 commit.DKGGroupKey = dkgGroupKey 165 commit.DKGParticipantKeys = dkgParticipantKeys 166 167 // create the service event 168 serviceEvent := &flow.ServiceEvent{ 169 Type: flow.ServiceEventCommit, 170 Event: commit, 171 } 172 173 return serviceEvent, nil 174 } 175 176 // convertClusterAssignments converts the Cadence representation of cluster 177 // assignments included in the EpochSetup into the protocol AssignmentList 178 // representation. 179 func convertClusterAssignments(cdcClusters []cadence.Value) (flow.AssignmentList, error) { 180 181 // ensure we don't have duplicate cluster indices 182 indices := make(map[uint]struct{}) 183 184 // parse cluster assignments to Go types 185 identifierLists := make([]flow.IdentifierList, len(cdcClusters)) 186 for _, value := range cdcClusters { 187 188 cdcCluster, ok := value.(cadence.Struct) 189 if !ok { 190 return nil, invalidCadenceTypeError("cluster", cdcCluster, cadence.Struct{}) 191 } 192 193 expectedFields := 2 194 if len(cdcCluster.Fields) < expectedFields { 195 return nil, fmt.Errorf("insufficient fields (%d < %d)", len(cdcCluster.Fields), expectedFields) 196 } 197 198 // ensure cluster index is valid 199 clusterIndex, ok := cdcCluster.Fields[0].(cadence.UInt16) 200 if !ok { 201 return nil, invalidCadenceTypeError("clusterIndex", cdcCluster.Fields[0], cadence.UInt16(0)) 202 } 203 if int(clusterIndex) >= len(cdcClusters) { 204 return nil, fmt.Errorf("invalid cdcCluster index (%d) outside range [0,%d]", clusterIndex, len(cdcClusters)-1) 205 } 206 _, dup := indices[uint(clusterIndex)] 207 if dup { 208 return nil, fmt.Errorf("duplicate cdcCluster index (%d)", clusterIndex) 209 } 210 211 // read weights to retrieve node IDs of cdcCluster members 212 weightsByNodeID, ok := cdcCluster.Fields[1].(cadence.Dictionary) 213 if !ok { 214 return nil, invalidCadenceTypeError("clusterWeights", cdcCluster.Fields[1], cadence.Dictionary{}) 215 } 216 217 for _, pair := range weightsByNodeID.Pairs { 218 219 nodeIDString, ok := pair.Key.(cadence.String) 220 if !ok { 221 return nil, invalidCadenceTypeError("clusterWeights.nodeID", pair.Key, cadence.String("")) 222 } 223 nodeID, err := flow.HexStringToIdentifier(string(nodeIDString)) 224 if err != nil { 225 return nil, fmt.Errorf("could not convert hex string to identifer: %w", err) 226 } 227 228 identifierLists[clusterIndex] = append(identifierLists[clusterIndex], nodeID) 229 } 230 } 231 232 // sort identifier lists in Canonical order 233 assignments := assignment.FromIdentifierLists(identifierLists) 234 235 return assignments, nil 236 } 237 238 // convertParticipants converts the network participants specified in the 239 // EpochSetup event into an IdentityList. 240 func convertParticipants(cdcParticipants []cadence.Value) (flow.IdentityList, error) { 241 242 participants := make(flow.IdentityList, 0, len(cdcParticipants)) 243 var err error 244 245 for _, value := range cdcParticipants { 246 247 cdcNodeInfoStruct, ok := value.(cadence.Struct) 248 if !ok { 249 return nil, invalidCadenceTypeError("cdcNodeInfoFields", value, cadence.Struct{}) 250 } 251 cdcNodeInfoFields := cdcNodeInfoStruct.Fields 252 253 expectedFields := 14 254 if len(cdcNodeInfoFields) < expectedFields { 255 return nil, fmt.Errorf("insufficient fields (%d < %d)", len(cdcNodeInfoFields), expectedFields) 256 } 257 258 // create and assign fields to identity from cadence Struct 259 identity := new(flow.Identity) 260 role, ok := cdcNodeInfoFields[1].(cadence.UInt8) 261 if !ok { 262 return nil, invalidCadenceTypeError("nodeInfo.role", cdcNodeInfoFields[1], cadence.UInt8(0)) 263 } 264 identity.Role = flow.Role(role) 265 if !identity.Role.Valid() { 266 return nil, fmt.Errorf("invalid role %d", role) 267 } 268 269 address, ok := cdcNodeInfoFields[2].(cadence.String) 270 if !ok { 271 return nil, invalidCadenceTypeError("nodeInfo.address", cdcNodeInfoFields[2], cadence.String("")) 272 } 273 identity.Address = string(address) 274 275 initialWeight, ok := cdcNodeInfoFields[13].(cadence.UInt64) 276 if !ok { 277 return nil, invalidCadenceTypeError("nodeInfo.initialWeight", cdcNodeInfoFields[13], cadence.UInt64(0)) 278 } 279 identity.Weight = uint64(initialWeight) 280 281 // convert nodeID string into identifier 282 nodeIDHex, ok := cdcNodeInfoFields[0].(cadence.String) 283 if !ok { 284 return nil, invalidCadenceTypeError("nodeInfo.id", cdcNodeInfoFields[0], cadence.String("")) 285 } 286 identity.NodeID, err = flow.HexStringToIdentifier(string(nodeIDHex)) 287 if err != nil { 288 return nil, fmt.Errorf("could not convert hex string to identifer: %w", err) 289 } 290 291 // parse to PublicKey the networking key hex string 292 networkKeyHex, ok := cdcNodeInfoFields[3].(cadence.String) 293 if !ok { 294 return nil, invalidCadenceTypeError("nodeInfo.networkKey", cdcNodeInfoFields[3], cadence.String("")) 295 } 296 networkKeyBytes, err := hex.DecodeString(string(networkKeyHex)) 297 if err != nil { 298 return nil, fmt.Errorf("could not decode network public key into bytes: %w", err) 299 } 300 identity.NetworkPubKey, err = crypto.DecodePublicKey(crypto.ECDSAP256, networkKeyBytes) 301 if err != nil { 302 return nil, fmt.Errorf("could not decode network public key: %w", err) 303 } 304 305 // parse to PublicKey the staking key hex string 306 stakingKeyHex, ok := cdcNodeInfoFields[4].(cadence.String) 307 if !ok { 308 return nil, invalidCadenceTypeError("nodeInfo.stakingKey", cdcNodeInfoFields[4], cadence.String("")) 309 } 310 stakingKeyBytes, err := hex.DecodeString(string(stakingKeyHex)) 311 if err != nil { 312 return nil, fmt.Errorf("could not decode staking public key into bytes: %w", err) 313 } 314 identity.StakingPubKey, err = crypto.DecodePublicKey(crypto.BLSBLS12381, stakingKeyBytes) 315 if err != nil { 316 return nil, fmt.Errorf("could not decode staking public key: %w", err) 317 } 318 319 participants = append(participants, identity) 320 } 321 322 participants = participants.Sort(order.Canonical) 323 return participants, nil 324 } 325 326 // convertClusterQCVotes converts raw cluster QC votes from the EpochCommit event 327 // to a representation suitable for inclusion in the protocol state. Votes are 328 // aggregated as part of this conversion. 329 func convertClusterQCVotes(cdcClusterQCs []cadence.Value) ([]flow.ClusterQCVoteData, error) { 330 331 // avoid duplicate indices 332 indices := make(map[uint]struct{}) 333 qcVoteDatas := make([]flow.ClusterQCVoteData, len(cdcClusterQCs)) 334 335 // CAUTION: Votes are not validated prior to aggregation. This means a single 336 // invalid vote submission will result in a fully invalid QC for that cluster. 337 // Votes must be validated by the ClusterQC smart contract. 338 339 for _, cdcClusterQC := range cdcClusterQCs { 340 cdcClusterQCStruct, ok := cdcClusterQC.(cadence.Struct) 341 if !ok { 342 return nil, invalidCadenceTypeError("clusterQC", cdcClusterQC, cadence.Struct{}) 343 } 344 cdcClusterQCFields := cdcClusterQCStruct.Fields 345 346 expectedFields := 4 347 if len(cdcClusterQCFields) < expectedFields { 348 return nil, fmt.Errorf("insufficient fields (%d < %d)", len(cdcClusterQCFields), expectedFields) 349 } 350 351 index, ok := cdcClusterQCFields[0].(cadence.UInt16) 352 if !ok { 353 return nil, invalidCadenceTypeError("clusterQC.index", cdcClusterQCFields[0], cadence.UInt16(0)) 354 } 355 if int(index) >= len(cdcClusterQCs) { 356 return nil, fmt.Errorf("invalid index (%d) not in range [0,%d]", index, len(cdcClusterQCs)) 357 } 358 _, dup := indices[uint(index)] 359 if dup { 360 return nil, fmt.Errorf("duplicate cluster QC index (%d)", index) 361 } 362 363 cdcVoterIDs, ok := cdcClusterQCFields[3].(cadence.Array) 364 if !ok { 365 return nil, invalidCadenceTypeError("clusterQC.voterIDs", cdcClusterQCFields[2], cadence.Array{}) 366 } 367 368 voterIDs := make([]flow.Identifier, 0, len(cdcVoterIDs.Values)) 369 for _, cdcVoterID := range cdcVoterIDs.Values { 370 voterIDHex, ok := cdcVoterID.(cadence.String) 371 if !ok { 372 return nil, invalidCadenceTypeError("clusterQC[i].voterID", cdcVoterID, cadence.String("")) 373 } 374 voterID, err := flow.HexStringToIdentifier(string(voterIDHex)) 375 if err != nil { 376 return nil, fmt.Errorf("could not convert voter ID from hex: %w", err) 377 } 378 voterIDs = append(voterIDs, voterID) 379 } 380 381 // gather all the vote signatures 382 cdcRawVotes := cdcClusterQCFields[1].(cadence.Array) 383 signatures := make([]crypto.Signature, 0, len(cdcRawVotes.Values)) 384 for _, cdcRawVote := range cdcRawVotes.Values { 385 rawVoteHex, ok := cdcRawVote.(cadence.String) 386 if !ok { 387 return nil, invalidCadenceTypeError("clusterQC[i].vote", cdcRawVote, cadence.String("")) 388 } 389 rawVoteBytes, err := hex.DecodeString(string(rawVoteHex)) 390 if err != nil { 391 return nil, fmt.Errorf("could not convert raw vote from hex: %w", err) 392 } 393 signatures = append(signatures, rawVoteBytes) 394 } 395 // Aggregate BLS signatures 396 aggregatedSignature, err := crypto.AggregateBLSSignatures(signatures) 397 if err != nil { 398 return nil, fmt.Errorf("cluster qc vote aggregation failed: %w", err) 399 } 400 401 // set the fields on the QC vote data object 402 qcVoteDatas[int(index)] = flow.ClusterQCVoteData{ 403 SigData: aggregatedSignature, 404 VoterIDs: voterIDs, 405 } 406 } 407 408 return qcVoteDatas, nil 409 } 410 411 // convertDKGKeys converts hex-encoded DKG public keys as received by the DKG 412 // smart contract into crypto.PublicKey representations suitable for inclusion 413 // in the protocol state. 414 func convertDKGKeys(cdcDKGKeys []cadence.Value) (groupKey crypto.PublicKey, participantKeys []crypto.PublicKey, err error) { 415 416 hexDKGKeys := make([]string, 0, len(cdcDKGKeys)) 417 for _, value := range cdcDKGKeys { 418 keyHex, ok := value.(cadence.String) 419 if !ok { 420 return nil, nil, invalidCadenceTypeError("dkgKey", value, cadence.String("")) 421 } 422 hexDKGKeys = append(hexDKGKeys, string(keyHex)) 423 } 424 425 // pop first element - group public key hex string 426 groupPubKeyHex := hexDKGKeys[0] 427 hexDKGKeys = hexDKGKeys[1:] 428 429 // decode group public key 430 groupKeyBytes, err := hex.DecodeString(groupPubKeyHex) 431 if err != nil { 432 return nil, nil, fmt.Errorf("could not decode group public key into bytes: %w", err) 433 } 434 groupKey, err = crypto.DecodePublicKey(crypto.BLSBLS12381, groupKeyBytes) 435 if err != nil { 436 return nil, nil, fmt.Errorf("could not decode group public key: %w", err) 437 } 438 439 // decode individual public keys 440 dkgParticipantKeys := make([]crypto.PublicKey, 0, len(hexDKGKeys)) 441 for _, pubKeyString := range hexDKGKeys { 442 443 pubKeyBytes, err := hex.DecodeString(pubKeyString) 444 if err != nil { 445 return nil, nil, fmt.Errorf("could not decode individual public key into bytes: %w", err) 446 } 447 pubKey, err := crypto.DecodePublicKey(crypto.BLSBLS12381, pubKeyBytes) 448 if err != nil { 449 return nil, nil, fmt.Errorf("could not decode dkg public key: %w", err) 450 } 451 dkgParticipantKeys = append(dkgParticipantKeys, pubKey) 452 } 453 454 return groupKey, dkgParticipantKeys, nil 455 } 456 457 func invalidCadenceTypeError(fieldName string, actualType, expectedType cadence.Value) error { 458 return fmt.Errorf("invalid Cadence type for field %s (got=%s, expected=%s)", 459 fieldName, 460 actualType.Type().ID(), 461 expectedType.Type().ID()) 462 }