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  }