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 }