github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/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/onflow/crypto"
    12  	"github.com/vmihailenco/msgpack/v4"
    13  
    14  	"github.com/onflow/flow-go/model/encodable"
    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       IdentitySkeletonList // all participants of the epoch in canonical order
    73  	Assignments        AssignmentList       // cluster assignment for the epoch
    74  	RandomSource       []byte               // source of randomness for epoch-specific setup tasks
    75  	TargetDuration     uint64               // desired real-world duration for the epoch [seconds]
    76  	TargetEndTime      uint64               // desired real-world end time for the epoch in UNIX time [seconds]
    77  }
    78  
    79  func (setup *EpochSetup) ServiceEvent() ServiceEvent {
    80  	return ServiceEvent{
    81  		Type:  ServiceEventSetup,
    82  		Event: setup,
    83  	}
    84  }
    85  
    86  // ID returns the hash of the event contents.
    87  func (setup *EpochSetup) ID() Identifier {
    88  	return MakeID(setup)
    89  }
    90  
    91  func (setup *EpochSetup) EqualTo(other *EpochSetup) bool {
    92  	if setup.Counter != other.Counter {
    93  		return false
    94  	}
    95  	if setup.FirstView != other.FirstView {
    96  		return false
    97  	}
    98  	if setup.DKGPhase1FinalView != other.DKGPhase1FinalView {
    99  		return false
   100  	}
   101  	if setup.DKGPhase2FinalView != other.DKGPhase2FinalView {
   102  		return false
   103  	}
   104  	if setup.DKGPhase3FinalView != other.DKGPhase3FinalView {
   105  		return false
   106  	}
   107  	if setup.FinalView != other.FinalView {
   108  		return false
   109  	}
   110  	if setup.TargetDuration != other.TargetDuration {
   111  		return false
   112  	}
   113  	if setup.TargetEndTime != other.TargetEndTime {
   114  		return false
   115  	}
   116  	if !IdentitySkeletonListEqualTo(setup.Participants, other.Participants) {
   117  		return false
   118  	}
   119  	if !setup.Assignments.EqualTo(other.Assignments) {
   120  		return false
   121  	}
   122  	return bytes.Equal(setup.RandomSource, other.RandomSource)
   123  }
   124  
   125  // EpochCommit is a service event emitted when epoch setup has been completed.
   126  // When an EpochCommit event is emitted, the network is ready to transition to
   127  // the epoch.
   128  type EpochCommit struct {
   129  	Counter            uint64              // the number of the epoch
   130  	ClusterQCs         []ClusterQCVoteData // quorum certificates for each cluster
   131  	DKGGroupKey        crypto.PublicKey    // group key from DKG
   132  	DKGParticipantKeys []crypto.PublicKey  // public keys for DKG participants
   133  }
   134  
   135  // ClusterQCVoteData represents the votes for a cluster quorum certificate, as
   136  // gathered by the ClusterQC smart contract. It contains the aggregated
   137  // signature over the root block for the cluster as well as the set of voters.
   138  type ClusterQCVoteData struct {
   139  	SigData  crypto.Signature // the aggregated signature over all the votes
   140  	VoterIDs []Identifier     // the set of voters that contributed to the qc
   141  }
   142  
   143  func (c *ClusterQCVoteData) EqualTo(other *ClusterQCVoteData) bool {
   144  	if len(c.VoterIDs) != len(other.VoterIDs) {
   145  		return false
   146  	}
   147  	if !bytes.Equal(c.SigData, other.SigData) {
   148  		return false
   149  	}
   150  	for i, v := range c.VoterIDs {
   151  		if v != other.VoterIDs[i] {
   152  			return false
   153  		}
   154  	}
   155  	return true
   156  }
   157  
   158  // ClusterQCVoteDataFromQC converts a quorum certificate to the representation
   159  // used by the smart contract, essentially discarding the block ID and view
   160  // (which are protocol-defined given the EpochSetup event).
   161  func ClusterQCVoteDataFromQC(qc *QuorumCertificateWithSignerIDs) ClusterQCVoteData {
   162  	return ClusterQCVoteData{
   163  		SigData:  qc.SigData,
   164  		VoterIDs: qc.SignerIDs,
   165  	}
   166  }
   167  
   168  func ClusterQCVoteDatasFromQCs(qcs []*QuorumCertificateWithSignerIDs) []ClusterQCVoteData {
   169  	qcVotes := make([]ClusterQCVoteData, 0, len(qcs))
   170  	for _, qc := range qcs {
   171  		qcVotes = append(qcVotes, ClusterQCVoteDataFromQC(qc))
   172  	}
   173  	return qcVotes
   174  }
   175  
   176  func (commit *EpochCommit) ServiceEvent() ServiceEvent {
   177  	return ServiceEvent{
   178  		Type:  ServiceEventCommit,
   179  		Event: commit,
   180  	}
   181  }
   182  
   183  type encodableCommit struct {
   184  	Counter            uint64
   185  	ClusterQCs         []ClusterQCVoteData
   186  	DKGGroupKey        encodable.RandomBeaconPubKey
   187  	DKGParticipantKeys []encodable.RandomBeaconPubKey
   188  }
   189  
   190  func encodableFromCommit(commit *EpochCommit) encodableCommit {
   191  	encKeys := make([]encodable.RandomBeaconPubKey, 0, len(commit.DKGParticipantKeys))
   192  	for _, key := range commit.DKGParticipantKeys {
   193  		encKeys = append(encKeys, encodable.RandomBeaconPubKey{PublicKey: key})
   194  	}
   195  	return encodableCommit{
   196  		Counter:            commit.Counter,
   197  		ClusterQCs:         commit.ClusterQCs,
   198  		DKGGroupKey:        encodable.RandomBeaconPubKey{PublicKey: commit.DKGGroupKey},
   199  		DKGParticipantKeys: encKeys,
   200  	}
   201  }
   202  
   203  func commitFromEncodable(enc encodableCommit) EpochCommit {
   204  	dkgKeys := make([]crypto.PublicKey, 0, len(enc.DKGParticipantKeys))
   205  	for _, key := range enc.DKGParticipantKeys {
   206  		dkgKeys = append(dkgKeys, key.PublicKey)
   207  	}
   208  	return EpochCommit{
   209  		Counter:            enc.Counter,
   210  		ClusterQCs:         enc.ClusterQCs,
   211  		DKGGroupKey:        enc.DKGGroupKey.PublicKey,
   212  		DKGParticipantKeys: dkgKeys,
   213  	}
   214  }
   215  
   216  func (commit EpochCommit) MarshalJSON() ([]byte, error) {
   217  	return json.Marshal(encodableFromCommit(&commit))
   218  }
   219  
   220  func (commit *EpochCommit) UnmarshalJSON(b []byte) error {
   221  	var enc encodableCommit
   222  	err := json.Unmarshal(b, &enc)
   223  	if err != nil {
   224  		return err
   225  	}
   226  
   227  	*commit = commitFromEncodable(enc)
   228  	return nil
   229  }
   230  
   231  func (commit *EpochCommit) MarshalCBOR() ([]byte, error) {
   232  	return cbor.Marshal(encodableFromCommit(commit))
   233  }
   234  
   235  func (commit *EpochCommit) UnmarshalCBOR(b []byte) error {
   236  	var enc encodableCommit
   237  	err := cbor.Unmarshal(b, &enc)
   238  	if err != nil {
   239  		return err
   240  	}
   241  
   242  	*commit = commitFromEncodable(enc)
   243  	return nil
   244  }
   245  
   246  func (commit *EpochCommit) MarshalMsgpack() ([]byte, error) {
   247  	return msgpack.Marshal(encodableFromCommit(commit))
   248  }
   249  
   250  func (commit *EpochCommit) UnmarshalMsgpack(b []byte) error {
   251  	var enc encodableCommit
   252  	err := msgpack.Unmarshal(b, &enc)
   253  	if err != nil {
   254  		return err
   255  	}
   256  	*commit = commitFromEncodable(enc)
   257  	return nil
   258  }
   259  
   260  // EncodeRLP encodes the commit as RLP. The RLP encoding needs to be handled
   261  // differently from JSON/msgpack, because it does not handle custom encoders
   262  // within map types.
   263  // NOTE: DecodeRLP is not needed, as this is only used for hashing.
   264  func (commit *EpochCommit) EncodeRLP(w io.Writer) error {
   265  	rlpEncodable := struct {
   266  		Counter            uint64
   267  		ClusterQCs         []ClusterQCVoteData
   268  		DKGGroupKey        []byte
   269  		DKGParticipantKeys [][]byte
   270  	}{
   271  		Counter:            commit.Counter,
   272  		ClusterQCs:         commit.ClusterQCs,
   273  		DKGGroupKey:        commit.DKGGroupKey.Encode(),
   274  		DKGParticipantKeys: make([][]byte, 0, len(commit.DKGParticipantKeys)),
   275  	}
   276  	for _, key := range commit.DKGParticipantKeys {
   277  		rlpEncodable.DKGParticipantKeys = append(rlpEncodable.DKGParticipantKeys, key.Encode())
   278  	}
   279  
   280  	return rlp.Encode(w, rlpEncodable)
   281  }
   282  
   283  // ID returns the hash of the event contents.
   284  func (commit *EpochCommit) ID() Identifier {
   285  	return MakeID(commit)
   286  }
   287  
   288  func (commit *EpochCommit) EqualTo(other *EpochCommit) bool {
   289  	if commit.Counter != other.Counter {
   290  		return false
   291  	}
   292  	if len(commit.ClusterQCs) != len(other.ClusterQCs) {
   293  		return false
   294  	}
   295  	for i, qc := range commit.ClusterQCs {
   296  		if !qc.EqualTo(&other.ClusterQCs[i]) {
   297  			return false
   298  		}
   299  	}
   300  	if (commit.DKGGroupKey == nil && other.DKGGroupKey != nil) ||
   301  		(commit.DKGGroupKey != nil && other.DKGGroupKey == nil) {
   302  		return false
   303  	}
   304  	if commit.DKGGroupKey != nil && other.DKGGroupKey != nil && !commit.DKGGroupKey.Equals(other.DKGGroupKey) {
   305  		return false
   306  	}
   307  	if len(commit.DKGParticipantKeys) != len(other.DKGParticipantKeys) {
   308  		return false
   309  	}
   310  
   311  	for i, key := range commit.DKGParticipantKeys {
   312  		if !key.Equals(other.DKGParticipantKeys[i]) {
   313  			return false
   314  		}
   315  	}
   316  
   317  	return true
   318  }
   319  
   320  // ToDKGParticipantLookup constructs a DKG participant lookup from an identity
   321  // list and a key list. The identity list must be EXACTLY the same (order and
   322  // contents) as that used when initializing the corresponding DKG instance.
   323  func ToDKGParticipantLookup(participants IdentitySkeletonList, keys []crypto.PublicKey) (map[Identifier]DKGParticipant, error) {
   324  	if len(participants) != len(keys) {
   325  		return nil, fmt.Errorf("participant list (len=%d) does not match key list (len=%d)", len(participants), len(keys))
   326  	}
   327  
   328  	lookup := make(map[Identifier]DKGParticipant, len(participants))
   329  	for i := 0; i < len(participants); i++ {
   330  		part := participants[i]
   331  		key := keys[i]
   332  		lookup[part.NodeID] = DKGParticipant{
   333  			Index:    uint(i),
   334  			KeyShare: key,
   335  		}
   336  	}
   337  	return lookup, nil
   338  }
   339  
   340  type DKGParticipant struct {
   341  	Index    uint
   342  	KeyShare crypto.PublicKey
   343  }
   344  
   345  type encodableDKGParticipant struct {
   346  	Index    uint
   347  	KeyShare encodable.RandomBeaconPubKey
   348  }
   349  
   350  func encodableFromDKGParticipant(part DKGParticipant) encodableDKGParticipant {
   351  	return encodableDKGParticipant{
   352  		Index:    part.Index,
   353  		KeyShare: encodable.RandomBeaconPubKey{PublicKey: part.KeyShare},
   354  	}
   355  }
   356  
   357  func dkgParticipantFromEncodable(enc encodableDKGParticipant) DKGParticipant {
   358  	return DKGParticipant{
   359  		Index:    enc.Index,
   360  		KeyShare: enc.KeyShare.PublicKey,
   361  	}
   362  }
   363  
   364  func (part DKGParticipant) MarshalJSON() ([]byte, error) {
   365  	enc := encodableFromDKGParticipant(part)
   366  	return json.Marshal(enc)
   367  }
   368  
   369  func (part *DKGParticipant) UnmarshalJSON(b []byte) error {
   370  	var enc encodableDKGParticipant
   371  	err := json.Unmarshal(b, &enc)
   372  	if err != nil {
   373  		return err
   374  	}
   375  
   376  	*part = dkgParticipantFromEncodable(enc)
   377  	return nil
   378  }
   379  
   380  func (part DKGParticipant) MarshalCBOR() ([]byte, error) {
   381  	enc := encodableFromDKGParticipant(part)
   382  	return cbor.Marshal(enc)
   383  }
   384  
   385  func (part *DKGParticipant) UnmarshalCBOR(b []byte) error {
   386  	var enc encodableDKGParticipant
   387  	err := cbor.Unmarshal(b, &enc)
   388  	if err != nil {
   389  		return err
   390  	}
   391  
   392  	*part = dkgParticipantFromEncodable(enc)
   393  	return nil
   394  }
   395  
   396  func (part DKGParticipant) MarshalMsgpack() ([]byte, error) {
   397  	return msgpack.Marshal(encodableFromDKGParticipant(part))
   398  }
   399  
   400  func (part *DKGParticipant) UnmarshalMsgpack(b []byte) error {
   401  	var enc encodableDKGParticipant
   402  	err := msgpack.Unmarshal(b, &enc)
   403  	if err != nil {
   404  		return err
   405  	}
   406  	*part = dkgParticipantFromEncodable(enc)
   407  	return nil
   408  }
   409  
   410  func (part DKGParticipant) EncodeRLP(w io.Writer) error {
   411  	return rlp.Encode(w, encodableFromDKGParticipant(part))
   412  }
   413  
   414  // EventIDs is a container for IDs of epoch service events.
   415  type EventIDs struct {
   416  	// SetupID is the ID of the EpochSetup event for the respective Epoch
   417  	SetupID Identifier
   418  	// CommitID is the ID of the EpochCommit event for the respective Epoch
   419  	CommitID Identifier
   420  }
   421  
   422  // ID returns hash of the event IDs.
   423  func (e *EventIDs) ID() Identifier {
   424  	return MakeID(e)
   425  }