github.com/onflow/flow-go@v0.33.17/state/protocol/inmem/epoch.go (about)

     1  package inmem
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/onflow/flow-go/model/encodable"
     7  	"github.com/onflow/flow-go/model/flow"
     8  	"github.com/onflow/flow-go/model/flow/factory"
     9  	"github.com/onflow/flow-go/model/flow/filter"
    10  	"github.com/onflow/flow-go/module/signature"
    11  	"github.com/onflow/flow-go/state/cluster"
    12  	"github.com/onflow/flow-go/state/protocol"
    13  	"github.com/onflow/flow-go/state/protocol/invalid"
    14  )
    15  
    16  // Epoch is a memory-backed implementation of protocol.Epoch.
    17  type Epoch struct {
    18  	enc EncodableEpoch
    19  }
    20  
    21  var _ protocol.Epoch = (*Epoch)(nil)
    22  
    23  func (e Epoch) Encodable() EncodableEpoch {
    24  	return e.enc
    25  }
    26  
    27  func (e Epoch) Counter() (uint64, error)            { return e.enc.Counter, nil }
    28  func (e Epoch) FirstView() (uint64, error)          { return e.enc.FirstView, nil }
    29  func (e Epoch) DKGPhase1FinalView() (uint64, error) { return e.enc.DKGPhase1FinalView, nil }
    30  func (e Epoch) DKGPhase2FinalView() (uint64, error) { return e.enc.DKGPhase2FinalView, nil }
    31  func (e Epoch) DKGPhase3FinalView() (uint64, error) { return e.enc.DKGPhase3FinalView, nil }
    32  func (e Epoch) FinalView() (uint64, error)          { return e.enc.FinalView, nil }
    33  func (e Epoch) InitialIdentities() (flow.IdentityList, error) {
    34  	return e.enc.InitialIdentities, nil
    35  }
    36  func (e Epoch) RandomSource() ([]byte, error) {
    37  	return e.enc.RandomSource, nil
    38  }
    39  
    40  func (e Epoch) Clustering() (flow.ClusterList, error) {
    41  	return e.enc.Clustering, nil
    42  }
    43  
    44  func (e Epoch) DKG() (protocol.DKG, error) {
    45  	if e.enc.DKG != nil {
    46  		return DKG{*e.enc.DKG}, nil
    47  	}
    48  	return nil, protocol.ErrNextEpochNotCommitted
    49  }
    50  
    51  func (e Epoch) Cluster(i uint) (protocol.Cluster, error) {
    52  	if e.enc.Clusters == nil {
    53  		return nil, protocol.ErrNextEpochNotCommitted
    54  	}
    55  
    56  	if i >= uint(len(e.enc.Clusters)) {
    57  		return nil, fmt.Errorf("no cluster with index %d: %w", i, protocol.ErrClusterNotFound)
    58  	}
    59  	return Cluster{e.enc.Clusters[i]}, nil
    60  }
    61  
    62  func (e Epoch) ClusterByChainID(chainID flow.ChainID) (protocol.Cluster, error) {
    63  	if e.enc.Clusters == nil {
    64  		return nil, protocol.ErrNextEpochNotCommitted
    65  	}
    66  
    67  	for _, cluster := range e.enc.Clusters {
    68  		if cluster.RootBlock.Header.ChainID == chainID {
    69  			return Cluster{cluster}, nil
    70  		}
    71  	}
    72  	chainIDs := make([]string, 0, len(e.enc.Clusters))
    73  	for _, cluster := range e.enc.Clusters {
    74  		chainIDs = append(chainIDs, string(cluster.RootBlock.Header.ChainID))
    75  	}
    76  	return nil, fmt.Errorf("no cluster with the given chain ID %v, available chainIDs %v: %w", chainID, chainIDs, protocol.ErrClusterNotFound)
    77  }
    78  
    79  func (e Epoch) FinalHeight() (uint64, error) {
    80  	if e.enc.FinalHeight != nil {
    81  		return *e.enc.FinalHeight, nil
    82  	}
    83  	return 0, protocol.ErrEpochTransitionNotFinalized
    84  }
    85  
    86  func (e Epoch) FirstHeight() (uint64, error) {
    87  	if e.enc.FirstHeight != nil {
    88  		return *e.enc.FirstHeight, nil
    89  	}
    90  	return 0, protocol.ErrEpochTransitionNotFinalized
    91  }
    92  
    93  type Epochs struct {
    94  	enc EncodableEpochs
    95  }
    96  
    97  var _ protocol.EpochQuery = (*Epochs)(nil)
    98  
    99  func (eq Epochs) Previous() protocol.Epoch {
   100  	if eq.enc.Previous != nil {
   101  		return Epoch{*eq.enc.Previous}
   102  	}
   103  	return invalid.NewEpoch(protocol.ErrNoPreviousEpoch)
   104  }
   105  func (eq Epochs) Current() protocol.Epoch {
   106  	return Epoch{eq.enc.Current}
   107  }
   108  func (eq Epochs) Next() protocol.Epoch {
   109  	if eq.enc.Next != nil {
   110  		return Epoch{*eq.enc.Next}
   111  	}
   112  	return invalid.NewEpoch(protocol.ErrNextEpochNotSetup)
   113  }
   114  
   115  // setupEpoch is an implementation of protocol.Epoch backed by an EpochSetup
   116  // service event. This is used for converting service events to inmem.Epoch.
   117  type setupEpoch struct {
   118  	// EpochSetup service event
   119  	setupEvent *flow.EpochSetup
   120  }
   121  
   122  func (es *setupEpoch) Counter() (uint64, error) {
   123  	return es.setupEvent.Counter, nil
   124  }
   125  
   126  func (es *setupEpoch) FirstView() (uint64, error) {
   127  	return es.setupEvent.FirstView, nil
   128  }
   129  
   130  func (es *setupEpoch) DKGPhase1FinalView() (uint64, error) {
   131  	return es.setupEvent.DKGPhase1FinalView, nil
   132  }
   133  
   134  func (es *setupEpoch) DKGPhase2FinalView() (uint64, error) {
   135  	return es.setupEvent.DKGPhase2FinalView, nil
   136  }
   137  
   138  func (es *setupEpoch) DKGPhase3FinalView() (uint64, error) {
   139  	return es.setupEvent.DKGPhase3FinalView, nil
   140  }
   141  
   142  func (es *setupEpoch) FinalView() (uint64, error) {
   143  	return es.setupEvent.FinalView, nil
   144  }
   145  
   146  func (es *setupEpoch) RandomSource() ([]byte, error) {
   147  	return es.setupEvent.RandomSource, nil
   148  }
   149  
   150  func (es *setupEpoch) InitialIdentities() (flow.IdentityList, error) {
   151  	identities := es.setupEvent.Participants.Filter(filter.Any)
   152  	return identities, nil
   153  }
   154  
   155  func (es *setupEpoch) Clustering() (flow.ClusterList, error) {
   156  	return ClusteringFromSetupEvent(es.setupEvent)
   157  }
   158  
   159  func ClusteringFromSetupEvent(setupEvent *flow.EpochSetup) (flow.ClusterList, error) {
   160  	collectorFilter := filter.HasRole(flow.RoleCollection)
   161  	clustering, err := factory.NewClusterList(setupEvent.Assignments, setupEvent.Participants.Filter(collectorFilter))
   162  	if err != nil {
   163  		return nil, fmt.Errorf("failed to generate ClusterList from collector identities: %w", err)
   164  	}
   165  	return clustering, nil
   166  }
   167  
   168  func (es *setupEpoch) Cluster(_ uint) (protocol.Cluster, error) {
   169  	return nil, protocol.ErrNextEpochNotCommitted
   170  }
   171  
   172  func (es *setupEpoch) ClusterByChainID(_ flow.ChainID) (protocol.Cluster, error) {
   173  	return nil, protocol.ErrNextEpochNotCommitted
   174  }
   175  
   176  func (es *setupEpoch) DKG() (protocol.DKG, error) {
   177  	return nil, protocol.ErrNextEpochNotCommitted
   178  }
   179  
   180  func (es *setupEpoch) FirstHeight() (uint64, error) {
   181  	return 0, protocol.ErrEpochTransitionNotFinalized
   182  }
   183  
   184  func (es *setupEpoch) FinalHeight() (uint64, error) {
   185  	return 0, protocol.ErrEpochTransitionNotFinalized
   186  }
   187  
   188  // committedEpoch is an implementation of protocol.Epoch backed by an EpochSetup
   189  // and EpochCommit service event. This is used for converting service events to
   190  // inmem.Epoch.
   191  type committedEpoch struct {
   192  	setupEpoch
   193  	commitEvent *flow.EpochCommit
   194  }
   195  
   196  func (es *committedEpoch) Cluster(index uint) (protocol.Cluster, error) {
   197  
   198  	epochCounter := es.setupEvent.Counter
   199  
   200  	clustering, err := es.Clustering()
   201  	if err != nil {
   202  		return nil, fmt.Errorf("failed to generate clustering: %w", err)
   203  	}
   204  
   205  	members, ok := clustering.ByIndex(index)
   206  	if !ok {
   207  		return nil, fmt.Errorf("no cluster with index %d: %w", index, protocol.ErrClusterNotFound)
   208  	}
   209  
   210  	qcs := es.commitEvent.ClusterQCs
   211  	if uint(len(qcs)) <= index {
   212  		return nil, fmt.Errorf("internal data inconsistency: cannot get qc at index %d - epoch has %d clusters and %d cluster QCs",
   213  			index, len(clustering), len(qcs))
   214  	}
   215  	rootQCVoteData := qcs[index]
   216  
   217  	signerIndices, err := signature.EncodeSignersToIndices(members.NodeIDs(), rootQCVoteData.VoterIDs)
   218  	if err != nil {
   219  		return nil, fmt.Errorf("could not encode signer indices for rootQCVoteData.VoterIDs: %w", err)
   220  	}
   221  
   222  	rootBlock := cluster.CanonicalRootBlock(epochCounter, members)
   223  	rootQC := &flow.QuorumCertificate{
   224  		View:          rootBlock.Header.View,
   225  		BlockID:       rootBlock.ID(),
   226  		SignerIndices: signerIndices,
   227  		SigData:       rootQCVoteData.SigData,
   228  	}
   229  
   230  	cluster, err := ClusterFromEncodable(EncodableCluster{
   231  		Index:     index,
   232  		Counter:   epochCounter,
   233  		Members:   members,
   234  		RootBlock: rootBlock,
   235  		RootQC:    rootQC,
   236  	})
   237  	return cluster, err
   238  }
   239  
   240  func (es *committedEpoch) ClusterByChainID(chainID flow.ChainID) (protocol.Cluster, error) {
   241  	clustering, err := es.Clustering()
   242  	if err != nil {
   243  		return nil, fmt.Errorf("failed to generate clustering: %w", err)
   244  	}
   245  
   246  	for i, cl := range clustering {
   247  		if cluster.CanonicalClusterID(es.setupEvent.Counter, cl.NodeIDs()) == chainID {
   248  			cl, err := es.Cluster(uint(i))
   249  			if err != nil {
   250  				return nil, fmt.Errorf("could not retrieve known existing cluster (idx=%d, id=%s): %v", i, chainID, err)
   251  			}
   252  			return cl, nil
   253  		}
   254  	}
   255  	return nil, protocol.ErrClusterNotFound
   256  }
   257  
   258  func (es *committedEpoch) DKG() (protocol.DKG, error) {
   259  	// filter initial participants to valid DKG participants
   260  	participants := es.setupEvent.Participants.Filter(filter.IsValidDKGParticipant)
   261  	lookup, err := flow.ToDKGParticipantLookup(participants, es.commitEvent.DKGParticipantKeys)
   262  	if err != nil {
   263  		return nil, fmt.Errorf("could not construct dkg lookup: %w", err)
   264  	}
   265  
   266  	dkg, err := DKGFromEncodable(EncodableDKG{
   267  		GroupKey: encodable.RandomBeaconPubKey{
   268  			PublicKey: es.commitEvent.DKGGroupKey,
   269  		},
   270  		Participants: lookup,
   271  	})
   272  	return dkg, err
   273  }
   274  
   275  // startedEpoch represents an epoch (with counter N) that has started, but there is no _finalized_ transition
   276  // to the next epoch yet. Note that nodes can already be in views belonging to the _next_ Epoch, and it is
   277  // possible that there are already unfinalized blocks in that next epoch. However, without finalized blocks
   278  // in Epoch N+1, there is no definition of "last block" for Epoch N.
   279  //
   280  // startedEpoch has all the information of a committedEpoch, plus the epoch's first block height.
   281  type startedEpoch struct {
   282  	committedEpoch
   283  	firstHeight uint64
   284  }
   285  
   286  func (e *startedEpoch) FirstHeight() (uint64, error) {
   287  	return e.firstHeight, nil
   288  }
   289  
   290  // endedEpoch is an epoch which has ended (ie. the previous epoch). It has all the
   291  // information of a startedEpoch, plus the epoch's final block height.
   292  type endedEpoch struct {
   293  	startedEpoch
   294  	finalHeight uint64
   295  }
   296  
   297  func (e *endedEpoch) FinalHeight() (uint64, error) {
   298  	return e.finalHeight, nil
   299  }
   300  
   301  // NewSetupEpoch returns a memory-backed epoch implementation based on an
   302  // EpochSetup event. Epoch information available after the setup phase will
   303  // not be accessible in the resulting epoch instance.
   304  // No errors are expected during normal operations.
   305  func NewSetupEpoch(setupEvent *flow.EpochSetup) protocol.Epoch {
   306  	return &setupEpoch{
   307  		setupEvent: setupEvent,
   308  	}
   309  }
   310  
   311  // NewCommittedEpoch returns a memory-backed epoch implementation based on an
   312  // EpochSetup and EpochCommit events.
   313  // No errors are expected during normal operations.
   314  func NewCommittedEpoch(setupEvent *flow.EpochSetup, commitEvent *flow.EpochCommit) protocol.Epoch {
   315  	return &committedEpoch{
   316  		setupEpoch: setupEpoch{
   317  			setupEvent: setupEvent,
   318  		},
   319  		commitEvent: commitEvent,
   320  	}
   321  }
   322  
   323  // NewStartedEpoch returns a memory-backed epoch implementation based on an
   324  // EpochSetup and EpochCommit events, and the epoch's first block height.
   325  // No errors are expected during normal operations.
   326  func NewStartedEpoch(setupEvent *flow.EpochSetup, commitEvent *flow.EpochCommit, firstHeight uint64) protocol.Epoch {
   327  	return &startedEpoch{
   328  		committedEpoch: committedEpoch{
   329  			setupEpoch: setupEpoch{
   330  				setupEvent: setupEvent,
   331  			},
   332  			commitEvent: commitEvent,
   333  		},
   334  		firstHeight: firstHeight,
   335  	}
   336  }
   337  
   338  // NewEndedEpoch returns a memory-backed epoch implementation based on an
   339  // EpochSetup and EpochCommit events, and the epoch's final block height.
   340  // No errors are expected during normal operations.
   341  func NewEndedEpoch(setupEvent *flow.EpochSetup, commitEvent *flow.EpochCommit, firstHeight, finalHeight uint64) protocol.Epoch {
   342  	return &endedEpoch{
   343  		startedEpoch: startedEpoch{
   344  			committedEpoch: committedEpoch{
   345  				setupEpoch: setupEpoch{
   346  					setupEvent: setupEvent,
   347  				},
   348  				commitEvent: commitEvent,
   349  			},
   350  			firstHeight: firstHeight,
   351  		},
   352  		finalHeight: finalHeight,
   353  	}
   354  }