github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/state/protocol/convert.go (about)

     1  package protocol
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/onflow/crypto"
     7  
     8  	"github.com/onflow/flow-go/model/flow"
     9  	"github.com/onflow/flow-go/model/flow/filter"
    10  	"github.com/onflow/flow-go/module/signature"
    11  )
    12  
    13  // ToEpochSetup converts an Epoch interface instance to the underlying concrete
    14  // epoch setup service event. The input must be a valid, set up epoch.
    15  // Error returns:
    16  // * protocol.ErrNoPreviousEpoch - if the epoch represents a previous epoch which does not exist.
    17  // * protocol.ErrNextEpochNotSetup - if the epoch represents a next epoch which has not been set up.
    18  // * state.ErrUnknownSnapshotReference - if the epoch is queried from an unresolvable snapshot.
    19  func ToEpochSetup(epoch Epoch) (*flow.EpochSetup, error) {
    20  	counter, err := epoch.Counter()
    21  	if err != nil {
    22  		return nil, fmt.Errorf("could not get epoch counter: %w", err)
    23  	}
    24  	firstView, err := epoch.FirstView()
    25  	if err != nil {
    26  		return nil, fmt.Errorf("could not get epoch first view: %w", err)
    27  	}
    28  	finalView, err := epoch.FinalView()
    29  	if err != nil {
    30  		return nil, fmt.Errorf("could not get epoch final view: %w", err)
    31  	}
    32  	dkgPhase1FinalView, dkgPhase2FinalView, dkgPhase3FinalView, err := DKGPhaseViews(epoch)
    33  	if err != nil {
    34  		return nil, fmt.Errorf("could not get epoch dkg final views: %w", err)
    35  	}
    36  	targetDuration, err := epoch.TargetDuration()
    37  	if err != nil {
    38  		return nil, fmt.Errorf("could not get target duration: %w", err)
    39  	}
    40  	targetEndTime, err := epoch.TargetEndTime()
    41  	if err != nil {
    42  		return nil, fmt.Errorf("could not get target end time: %w", err)
    43  	}
    44  	participants, err := epoch.InitialIdentities()
    45  	if err != nil {
    46  		return nil, fmt.Errorf("could not get epoch participants: %w", err)
    47  	}
    48  	clustering, err := epoch.Clustering()
    49  	if err != nil {
    50  		return nil, fmt.Errorf("could not get epoch clustering: %w", err)
    51  	}
    52  	assignments := clustering.Assignments()
    53  	randomSource, err := epoch.RandomSource()
    54  	if err != nil {
    55  		return nil, fmt.Errorf("could not get epoch random source: %w", err)
    56  	}
    57  
    58  	setup := &flow.EpochSetup{
    59  		Counter:            counter,
    60  		FirstView:          firstView,
    61  		DKGPhase1FinalView: dkgPhase1FinalView,
    62  		DKGPhase2FinalView: dkgPhase2FinalView,
    63  		DKGPhase3FinalView: dkgPhase3FinalView,
    64  		FinalView:          finalView,
    65  		Participants:       participants,
    66  		Assignments:        assignments,
    67  		RandomSource:       randomSource,
    68  		TargetDuration:     targetDuration,
    69  		TargetEndTime:      targetEndTime,
    70  	}
    71  	return setup, nil
    72  }
    73  
    74  // ToEpochCommit converts an Epoch interface instance to the underlying
    75  // concrete epoch commit service event. The epoch must have been committed.
    76  // Error returns:
    77  // * protocol.ErrNoPreviousEpoch - if the epoch represents a previous epoch which does not exist.
    78  // * protocol.ErrNextEpochNotSetup - if the epoch represents a next epoch which has not been set up.
    79  // * protocol.ErrNextEpochNotCommitted - if the epoch has not been committed.
    80  // * state.ErrUnknownSnapshotReference - if the epoch is queried from an unresolvable snapshot.
    81  func ToEpochCommit(epoch Epoch) (*flow.EpochCommit, error) {
    82  	counter, err := epoch.Counter()
    83  	if err != nil {
    84  		return nil, fmt.Errorf("could not get epoch counter: %w", err)
    85  	}
    86  	clustering, err := epoch.Clustering()
    87  	if err != nil {
    88  		return nil, fmt.Errorf("could not get epoch clustering: %w", err)
    89  	}
    90  	qcs := make([]*flow.QuorumCertificateWithSignerIDs, 0, len(clustering))
    91  	for i := range clustering {
    92  		cluster, err := epoch.Cluster(uint(i))
    93  		if err != nil {
    94  			return nil, fmt.Errorf("could not get epoch cluster (index=%d): %w", i, err)
    95  		}
    96  		qc := cluster.RootQC()
    97  		// TODO: double check cluster.Members returns canonical order
    98  		signerIDs, err := signature.DecodeSignerIndicesToIdentifiers(cluster.Members().NodeIDs(), qc.SignerIndices)
    99  		if err != nil {
   100  			return nil, fmt.Errorf("could not encode signer indices: %w", err)
   101  		}
   102  		qcs = append(qcs, &flow.QuorumCertificateWithSignerIDs{
   103  			View:      qc.View,
   104  			BlockID:   qc.BlockID,
   105  			SignerIDs: signerIDs,
   106  			SigData:   qc.SigData,
   107  		})
   108  	}
   109  
   110  	participants, err := epoch.InitialIdentities()
   111  	if err != nil {
   112  		return nil, fmt.Errorf("could not get epoch participants: %w", err)
   113  	}
   114  	dkg, err := epoch.DKG()
   115  	if err != nil {
   116  		return nil, fmt.Errorf("could not get epoch dkg: %w", err)
   117  	}
   118  	dkgParticipantKeys, err := GetDKGParticipantKeys(dkg, participants.Filter(filter.IsValidDKGParticipant))
   119  	if err != nil {
   120  		return nil, fmt.Errorf("could not get dkg participant keys: %w", err)
   121  	}
   122  
   123  	commit := &flow.EpochCommit{
   124  		Counter:            counter,
   125  		ClusterQCs:         flow.ClusterQCVoteDatasFromQCs(qcs),
   126  		DKGGroupKey:        dkg.GroupKey(),
   127  		DKGParticipantKeys: dkgParticipantKeys,
   128  	}
   129  	return commit, nil
   130  }
   131  
   132  // GetDKGParticipantKeys retrieves the canonically ordered list of DKG
   133  // participant keys from the DKG.
   134  // All errors indicate inconsistent or invalid inputs.
   135  // No errors are expected during normal operation.
   136  func GetDKGParticipantKeys(dkg DKG, participants flow.IdentitySkeletonList) ([]crypto.PublicKey, error) {
   137  
   138  	keys := make([]crypto.PublicKey, 0, len(participants))
   139  	for i, identity := range participants {
   140  
   141  		index, err := dkg.Index(identity.NodeID)
   142  		if err != nil {
   143  			return nil, fmt.Errorf("could not get index (node=%x): %w", identity.NodeID, err)
   144  		}
   145  		key, err := dkg.KeyShare(identity.NodeID)
   146  		if err != nil {
   147  			return nil, fmt.Errorf("could not get key share (node=%x): %w", identity.NodeID, err)
   148  		}
   149  		if uint(i) != index {
   150  			return nil, fmt.Errorf("participant list index (%d) does not match dkg index (%d)", i, index)
   151  		}
   152  
   153  		keys = append(keys, key)
   154  	}
   155  
   156  	return keys, nil
   157  }
   158  
   159  // ToDKGParticipantLookup computes the nodeID -> DKGParticipant lookup for a
   160  // DKG instance. The participants must exactly match the DKG instance configuration.
   161  // All errors indicate inconsistent or invalid inputs.
   162  // No errors are expected during normal operation.
   163  func ToDKGParticipantLookup(dkg DKG, participants flow.IdentitySkeletonList) (map[flow.Identifier]flow.DKGParticipant, error) {
   164  
   165  	lookup := make(map[flow.Identifier]flow.DKGParticipant)
   166  	for _, identity := range participants {
   167  
   168  		index, err := dkg.Index(identity.NodeID)
   169  		if err != nil {
   170  			return nil, fmt.Errorf("could not get index (node=%x): %w", identity.NodeID, err)
   171  		}
   172  		key, err := dkg.KeyShare(identity.NodeID)
   173  		if err != nil {
   174  			return nil, fmt.Errorf("could not get key share (node=%x): %w", identity.NodeID, err)
   175  		}
   176  
   177  		lookup[identity.NodeID] = flow.DKGParticipant{
   178  			Index:    index,
   179  			KeyShare: key,
   180  		}
   181  	}
   182  
   183  	return lookup, nil
   184  }
   185  
   186  // DKGPhaseViews returns the DKG final phase views for an epoch.
   187  // Error returns:
   188  // * protocol.ErrNoPreviousEpoch - if the epoch represents a previous epoch which does not exist.
   189  // * protocol.ErrNextEpochNotSetup - if the epoch represents a next epoch which has not been set up.
   190  // * protocol.ErrNextEpochNotCommitted - if the epoch has not been committed.
   191  // * state.ErrUnknownSnapshotReference - if the epoch is queried from an unresolvable snapshot.
   192  func DKGPhaseViews(epoch Epoch) (phase1FinalView uint64, phase2FinalView uint64, phase3FinalView uint64, err error) {
   193  	phase1FinalView, err = epoch.DKGPhase1FinalView()
   194  	if err != nil {
   195  		return
   196  	}
   197  	phase2FinalView, err = epoch.DKGPhase2FinalView()
   198  	if err != nil {
   199  		return
   200  	}
   201  	phase3FinalView, err = epoch.DKGPhase3FinalView()
   202  	if err != nil {
   203  		return
   204  	}
   205  	return
   206  }