github.com/koko1123/flow-go-1@v0.29.6/model/flow/epoch.go (about) 1 package flow 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "fmt" 7 "io" 8 9 "github.com/ethereum/go-ethereum/rlp" 10 "github.com/fxamacker/cbor/v2" 11 "github.com/vmihailenco/msgpack/v4" 12 13 "github.com/koko1123/flow-go-1/model/encodable" 14 "github.com/onflow/flow-go/crypto" 15 ) 16 17 // EpochPhase represents a phase of the Epoch Preparation Protocol. The phase 18 // of an epoch is resolved based on a block reference and is fork-dependent. 19 // An epoch begins in the staking phase, then transitions to the setup phase in 20 // the block containing the EpochSetup service event, then to the committed 21 // phase in the block containing the EpochCommit service event. 22 // |<-- EpochPhaseStaking -->|<-- EpochPhaseSetup -->|<-- EpochPhaseCommitted -->|<-- EpochPhaseStaking -->... 23 // |<------------------------------- Epoch N ------------------------------------>|<-- Epoch N + 1 --... 24 type EpochPhase int 25 26 const ( 27 EpochPhaseUndefined EpochPhase = iota 28 EpochPhaseStaking 29 EpochPhaseSetup 30 EpochPhaseCommitted 31 ) 32 33 func (p EpochPhase) String() string { 34 return [...]string{ 35 "EpochPhaseUndefined", 36 "EpochPhaseStaking", 37 "EpochPhaseSetup", 38 "EpochPhaseCommitted", 39 }[p] 40 } 41 42 func GetEpochPhase(phase string) EpochPhase { 43 phases := []EpochPhase{ 44 EpochPhaseUndefined, 45 EpochPhaseStaking, 46 EpochPhaseSetup, 47 EpochPhaseCommitted, 48 } 49 for _, p := range phases { 50 if p.String() == phase { 51 return p 52 } 53 } 54 55 return EpochPhaseUndefined 56 } 57 58 // EpochSetupRandomSourceLength is the required length of the random source 59 // included in an EpochSetup service event. 60 const EpochSetupRandomSourceLength = 16 61 62 // EpochSetup is a service event emitted when the network is ready to set up 63 // for the upcoming epoch. It contains the participants in the epoch, the 64 // length, the cluster assignment, and the seed for leader selection. 65 type EpochSetup struct { 66 Counter uint64 // the number of the epoch 67 FirstView uint64 // the first view of the epoch 68 DKGPhase1FinalView uint64 // the final view of DKG phase 1 69 DKGPhase2FinalView uint64 // the final view of DKG phase 2 70 DKGPhase3FinalView uint64 // the final view of DKG phase 3 71 FinalView uint64 // the final view of the epoch 72 Participants IdentityList // all participants of the epoch 73 Assignments AssignmentList // cluster assignment for the epoch 74 RandomSource []byte // source of randomness for epoch-specific setup tasks 75 } 76 77 func (setup *EpochSetup) ServiceEvent() ServiceEvent { 78 return ServiceEvent{ 79 Type: ServiceEventSetup, 80 Event: setup, 81 } 82 } 83 84 // ID returns the hash of the event contents. 85 func (setup *EpochSetup) ID() Identifier { 86 return MakeID(setup) 87 } 88 89 func (setup *EpochSetup) EqualTo(other *EpochSetup) bool { 90 if setup.Counter != other.Counter { 91 return false 92 } 93 if setup.FirstView != other.FirstView { 94 return false 95 } 96 if setup.DKGPhase1FinalView != other.DKGPhase1FinalView { 97 return false 98 } 99 if setup.DKGPhase2FinalView != other.DKGPhase2FinalView { 100 return false 101 } 102 if setup.DKGPhase3FinalView != other.DKGPhase3FinalView { 103 return false 104 } 105 if setup.FinalView != other.FinalView { 106 return false 107 } 108 if !setup.Participants.EqualTo(other.Participants) { 109 return false 110 } 111 if !setup.Assignments.EqualTo(other.Assignments) { 112 return false 113 } 114 return bytes.Equal(setup.RandomSource, other.RandomSource) 115 } 116 117 // EpochCommit is a service event emitted when epoch setup has been completed. 118 // When an EpochCommit event is emitted, the network is ready to transition to 119 // the epoch. 120 type EpochCommit struct { 121 Counter uint64 // the number of the epoch 122 ClusterQCs []ClusterQCVoteData // quorum certificates for each cluster 123 DKGGroupKey crypto.PublicKey // group key from DKG 124 DKGParticipantKeys []crypto.PublicKey // public keys for DKG participants 125 } 126 127 // ClusterQCVoteData represents the votes for a cluster quorum certificate, as 128 // gathered by the ClusterQC smart contract. It contains the aggregated 129 // signature over the root block for the cluster as well as the set of voters. 130 type ClusterQCVoteData struct { 131 SigData crypto.Signature // the aggregated signature over all the votes 132 VoterIDs []Identifier // the set of voters that contributed to the qc 133 } 134 135 func (c *ClusterQCVoteData) EqualTo(other *ClusterQCVoteData) bool { 136 if len(c.VoterIDs) != len(other.VoterIDs) { 137 return false 138 } 139 if !bytes.Equal(c.SigData, other.SigData) { 140 return false 141 } 142 for i, v := range c.VoterIDs { 143 if v != other.VoterIDs[i] { 144 return false 145 } 146 } 147 return true 148 } 149 150 // ClusterQCVoteDataFromQC converts a quorum certificate to the representation 151 // used by the smart contract, essentially discarding the block ID and view 152 // (which are protocol-defined given the EpochSetup event). 153 func ClusterQCVoteDataFromQC(qc *QuorumCertificateWithSignerIDs) ClusterQCVoteData { 154 return ClusterQCVoteData{ 155 SigData: qc.SigData, 156 VoterIDs: qc.SignerIDs, 157 } 158 } 159 160 func ClusterQCVoteDatasFromQCs(qcs []*QuorumCertificateWithSignerIDs) []ClusterQCVoteData { 161 qcVotes := make([]ClusterQCVoteData, 0, len(qcs)) 162 for _, qc := range qcs { 163 qcVotes = append(qcVotes, ClusterQCVoteDataFromQC(qc)) 164 } 165 return qcVotes 166 } 167 168 func (commit *EpochCommit) ServiceEvent() ServiceEvent { 169 return ServiceEvent{ 170 Type: ServiceEventCommit, 171 Event: commit, 172 } 173 } 174 175 type encodableCommit struct { 176 Counter uint64 177 ClusterQCs []ClusterQCVoteData 178 DKGGroupKey encodable.RandomBeaconPubKey 179 DKGParticipantKeys []encodable.RandomBeaconPubKey 180 } 181 182 func encodableFromCommit(commit *EpochCommit) encodableCommit { 183 encKeys := make([]encodable.RandomBeaconPubKey, 0, len(commit.DKGParticipantKeys)) 184 for _, key := range commit.DKGParticipantKeys { 185 encKeys = append(encKeys, encodable.RandomBeaconPubKey{PublicKey: key}) 186 } 187 return encodableCommit{ 188 Counter: commit.Counter, 189 ClusterQCs: commit.ClusterQCs, 190 DKGGroupKey: encodable.RandomBeaconPubKey{PublicKey: commit.DKGGroupKey}, 191 DKGParticipantKeys: encKeys, 192 } 193 } 194 195 func commitFromEncodable(enc encodableCommit) EpochCommit { 196 dkgKeys := make([]crypto.PublicKey, 0, len(enc.DKGParticipantKeys)) 197 for _, key := range enc.DKGParticipantKeys { 198 dkgKeys = append(dkgKeys, key.PublicKey) 199 } 200 return EpochCommit{ 201 Counter: enc.Counter, 202 ClusterQCs: enc.ClusterQCs, 203 DKGGroupKey: enc.DKGGroupKey.PublicKey, 204 DKGParticipantKeys: dkgKeys, 205 } 206 } 207 208 func (commit EpochCommit) MarshalJSON() ([]byte, error) { 209 return json.Marshal(encodableFromCommit(&commit)) 210 } 211 212 func (commit *EpochCommit) UnmarshalJSON(b []byte) error { 213 var enc encodableCommit 214 err := json.Unmarshal(b, &enc) 215 if err != nil { 216 return err 217 } 218 219 *commit = commitFromEncodable(enc) 220 return nil 221 } 222 223 func (commit *EpochCommit) MarshalCBOR() ([]byte, error) { 224 return cbor.Marshal(encodableFromCommit(commit)) 225 } 226 227 func (commit *EpochCommit) UnmarshalCBOR(b []byte) error { 228 var enc encodableCommit 229 err := cbor.Unmarshal(b, &enc) 230 if err != nil { 231 return err 232 } 233 234 *commit = commitFromEncodable(enc) 235 return nil 236 } 237 238 func (commit *EpochCommit) MarshalMsgpack() ([]byte, error) { 239 return msgpack.Marshal(encodableFromCommit(commit)) 240 } 241 242 func (commit *EpochCommit) UnmarshalMsgpack(b []byte) error { 243 var enc encodableCommit 244 err := msgpack.Unmarshal(b, &enc) 245 if err != nil { 246 return err 247 } 248 *commit = commitFromEncodable(enc) 249 return nil 250 } 251 252 // EncodeRLP encodes the commit as RLP. The RLP encoding needs to be handled 253 // differently from JSON/msgpack, because it does not handle custom encoders 254 // within map types. 255 // NOTE: DecodeRLP is not needed, as this is only used for hashing. 256 func (commit *EpochCommit) EncodeRLP(w io.Writer) error { 257 rlpEncodable := struct { 258 Counter uint64 259 ClusterQCs []ClusterQCVoteData 260 DKGGroupKey []byte 261 DKGParticipantKeys [][]byte 262 }{ 263 Counter: commit.Counter, 264 ClusterQCs: commit.ClusterQCs, 265 DKGGroupKey: commit.DKGGroupKey.Encode(), 266 DKGParticipantKeys: make([][]byte, 0, len(commit.DKGParticipantKeys)), 267 } 268 for _, key := range commit.DKGParticipantKeys { 269 rlpEncodable.DKGParticipantKeys = append(rlpEncodable.DKGParticipantKeys, key.Encode()) 270 } 271 272 return rlp.Encode(w, rlpEncodable) 273 } 274 275 // ID returns the hash of the event contents. 276 func (commit *EpochCommit) ID() Identifier { 277 return MakeID(commit) 278 } 279 280 func (commit *EpochCommit) EqualTo(other *EpochCommit) bool { 281 if commit.Counter != other.Counter { 282 return false 283 } 284 if len(commit.ClusterQCs) != len(other.ClusterQCs) { 285 return false 286 } 287 for i, qc := range commit.ClusterQCs { 288 if !qc.EqualTo(&other.ClusterQCs[i]) { 289 return false 290 } 291 } 292 if (commit.DKGGroupKey == nil && other.DKGGroupKey != nil) || 293 (commit.DKGGroupKey != nil && other.DKGGroupKey == nil) { 294 return false 295 } 296 if commit.DKGGroupKey != nil && other.DKGGroupKey != nil && !commit.DKGGroupKey.Equals(other.DKGGroupKey) { 297 return false 298 } 299 if len(commit.DKGParticipantKeys) != len(other.DKGParticipantKeys) { 300 return false 301 } 302 303 for i, key := range commit.DKGParticipantKeys { 304 if !key.Equals(other.DKGParticipantKeys[i]) { 305 return false 306 } 307 } 308 309 return true 310 } 311 312 // ToDKGParticipantLookup constructs a DKG participant lookup from an identity 313 // list and a key list. The identity list must be EXACTLY the same (order and 314 // contents) as that used when initializing the corresponding DKG instance. 315 func ToDKGParticipantLookup(participants IdentityList, keys []crypto.PublicKey) (map[Identifier]DKGParticipant, error) { 316 if len(participants) != len(keys) { 317 return nil, fmt.Errorf("participant list (len=%d) does not match key list (len=%d)", len(participants), len(keys)) 318 } 319 320 lookup := make(map[Identifier]DKGParticipant, len(participants)) 321 for i := 0; i < len(participants); i++ { 322 part := participants[i] 323 key := keys[i] 324 lookup[part.NodeID] = DKGParticipant{ 325 Index: uint(i), 326 KeyShare: key, 327 } 328 } 329 return lookup, nil 330 } 331 332 type DKGParticipant struct { 333 Index uint 334 KeyShare crypto.PublicKey 335 } 336 337 type encodableDKGParticipant struct { 338 Index uint 339 KeyShare encodable.RandomBeaconPubKey 340 } 341 342 func encodableFromDKGParticipant(part DKGParticipant) encodableDKGParticipant { 343 return encodableDKGParticipant{ 344 Index: part.Index, 345 KeyShare: encodable.RandomBeaconPubKey{PublicKey: part.KeyShare}, 346 } 347 } 348 349 func dkgParticipantFromEncodable(enc encodableDKGParticipant) DKGParticipant { 350 return DKGParticipant{ 351 Index: enc.Index, 352 KeyShare: enc.KeyShare.PublicKey, 353 } 354 } 355 356 func (part DKGParticipant) MarshalJSON() ([]byte, error) { 357 enc := encodableFromDKGParticipant(part) 358 return json.Marshal(enc) 359 } 360 361 func (part *DKGParticipant) UnmarshalJSON(b []byte) error { 362 var enc encodableDKGParticipant 363 err := json.Unmarshal(b, &enc) 364 if err != nil { 365 return err 366 } 367 368 *part = dkgParticipantFromEncodable(enc) 369 return nil 370 } 371 372 func (part DKGParticipant) MarshalCBOR() ([]byte, error) { 373 enc := encodableFromDKGParticipant(part) 374 return cbor.Marshal(enc) 375 } 376 377 func (part *DKGParticipant) UnmarshalCBOR(b []byte) error { 378 var enc encodableDKGParticipant 379 err := cbor.Unmarshal(b, &enc) 380 if err != nil { 381 return err 382 } 383 384 *part = dkgParticipantFromEncodable(enc) 385 return nil 386 } 387 388 func (part DKGParticipant) MarshalMsgpack() ([]byte, error) { 389 return msgpack.Marshal(encodableFromDKGParticipant(part)) 390 } 391 392 func (part *DKGParticipant) UnmarshalMsgpack(b []byte) error { 393 var enc encodableDKGParticipant 394 err := msgpack.Unmarshal(b, &enc) 395 if err != nil { 396 return err 397 } 398 *part = dkgParticipantFromEncodable(enc) 399 return nil 400 } 401 402 func (part DKGParticipant) EncodeRLP(w io.Writer) error { 403 return rlp.Encode(w, encodableFromDKGParticipant(part)) 404 } 405 406 // EpochStatus represents the status of the current and next epoch with respect 407 // to a reference block. Concretely, it contains the IDs for all relevant 408 // service events emitted as of the reference block. Events not yet emitted are 409 // represented by ZeroID. 410 type EpochStatus struct { 411 PreviousEpoch EventIDs // EpochSetup and EpochCommit events for the previous epoch 412 CurrentEpoch EventIDs // EpochSetup and EpochCommit events for the current epoch 413 NextEpoch EventIDs // EpochSetup and EpochCommit events for the next epoch 414 } 415 416 // Copy returns a copy of the epoch status. 417 func (es *EpochStatus) Copy() *EpochStatus { 418 return &EpochStatus{ 419 PreviousEpoch: es.PreviousEpoch, 420 CurrentEpoch: es.CurrentEpoch, 421 NextEpoch: es.NextEpoch, 422 } 423 } 424 425 // EventIDs is a container for IDs of epoch service events. 426 type EventIDs struct { 427 // SetupID is the ID of the EpochSetup event for the respective Epoch 428 SetupID Identifier 429 // CommitID is the ID of the EpochCommit event for the respective Epoch 430 CommitID Identifier 431 } 432 433 func NewEpochStatus(previousSetup, previousCommit, currentSetup, currentCommit, nextSetup, nextCommit Identifier) (*EpochStatus, error) { 434 status := &EpochStatus{ 435 PreviousEpoch: EventIDs{ 436 SetupID: previousSetup, 437 CommitID: previousCommit, 438 }, 439 CurrentEpoch: EventIDs{ 440 SetupID: currentSetup, 441 CommitID: currentCommit, 442 }, 443 NextEpoch: EventIDs{ 444 SetupID: nextSetup, 445 CommitID: nextCommit, 446 }, 447 } 448 449 err := status.Check() 450 if err != nil { 451 return nil, err 452 } 453 return status, nil 454 } 455 456 // Check checks that the status is well-formed, returning an error if it is not. 457 // All errors indicate a malformed EpochStatus. 458 func (es *EpochStatus) Check() error { 459 460 if es == nil { 461 return fmt.Errorf("nil epoch status") 462 } 463 // must reference either both or neither event IDs for previous epoch 464 if (es.PreviousEpoch.SetupID == ZeroID) != (es.PreviousEpoch.CommitID == ZeroID) { 465 return fmt.Errorf("epoch status with only setup or only commit service event") 466 } 467 // must reference event IDs for current epoch 468 if es.CurrentEpoch.SetupID == ZeroID || es.CurrentEpoch.CommitID == ZeroID { 469 return fmt.Errorf("epoch status with empty current epoch service events") 470 } 471 // must not reference a commit without a setup 472 if es.NextEpoch.SetupID == ZeroID && es.NextEpoch.CommitID != ZeroID { 473 return fmt.Errorf("epoch status with commit but no setup service event") 474 } 475 return nil 476 } 477 478 // Phase returns the phase for the CURRENT epoch, given this epoch status. 479 // All errors indicate a malformed EpochStatus. 480 func (es *EpochStatus) Phase() (EpochPhase, error) { 481 482 err := es.Check() 483 if err != nil { 484 return EpochPhaseUndefined, err 485 } 486 if es.NextEpoch.SetupID == ZeroID { 487 return EpochPhaseStaking, nil 488 } 489 if es.NextEpoch.CommitID == ZeroID { 490 return EpochPhaseSetup, nil 491 } 492 return EpochPhaseCommitted, nil 493 } 494 495 func (es *EpochStatus) HasPrevious() bool { 496 return es.PreviousEpoch.SetupID != ZeroID && es.PreviousEpoch.CommitID != ZeroID 497 }