github.com/koko1123/flow-go-1@v0.29.6/state/protocol/inmem/convert.go (about) 1 package inmem 2 3 import ( 4 "errors" 5 "fmt" 6 7 "github.com/koko1123/flow-go-1/model/encodable" 8 "github.com/koko1123/flow-go-1/model/flow" 9 "github.com/koko1123/flow-go-1/model/flow/filter" 10 "github.com/koko1123/flow-go-1/module/signature" 11 "github.com/koko1123/flow-go-1/state/protocol" 12 ) 13 14 // FromSnapshot generates a memory-backed snapshot from the input snapshot. 15 // Typically, this would be used to convert a database-backed snapshot to 16 // one that can easily be serialized to disk or to network. 17 // TODO error docs 18 func FromSnapshot(from protocol.Snapshot) (*Snapshot, error) { 19 20 var ( 21 snap EncodableSnapshot 22 err error 23 ) 24 25 // convert top-level fields 26 snap.Head, err = from.Head() 27 if err != nil { 28 return nil, fmt.Errorf("could not get head: %w", err) 29 } 30 snap.Identities, err = from.Identities(filter.Any) 31 if err != nil { 32 return nil, fmt.Errorf("could not get identities: %w", err) 33 } 34 snap.LatestResult, snap.LatestSeal, err = from.SealedResult() 35 if err != nil { 36 return nil, fmt.Errorf("could not get seal: %w", err) 37 } 38 39 snap.SealingSegment, err = from.SealingSegment() 40 if err != nil { 41 return nil, fmt.Errorf("could not get sealing segment: %w", err) 42 } 43 snap.QuorumCertificate, err = from.QuorumCertificate() 44 if err != nil { 45 return nil, fmt.Errorf("could not get qc: %w", err) 46 } 47 snap.Phase, err = from.Phase() 48 if err != nil { 49 return nil, fmt.Errorf("could not get phase: %w", err) 50 } 51 52 // convert epochs 53 previous, err := FromEpoch(from.Epochs().Previous()) 54 // it is possible for valid snapshots to have no previous epoch 55 if errors.Is(err, protocol.ErrNoPreviousEpoch) { 56 snap.Epochs.Previous = nil 57 } else if err != nil { 58 return nil, fmt.Errorf("could not get previous epoch: %w", err) 59 } else { 60 snap.Epochs.Previous = &previous.enc 61 } 62 63 current, err := FromEpoch(from.Epochs().Current()) 64 if err != nil { 65 return nil, fmt.Errorf("could not get current epoch: %w", err) 66 } 67 snap.Epochs.Current = current.enc 68 69 next, err := FromEpoch(from.Epochs().Next()) 70 // it is possible for valid snapshots to have no next epoch 71 if errors.Is(err, protocol.ErrNextEpochNotSetup) { 72 snap.Epochs.Next = nil 73 } else if err != nil { 74 return nil, fmt.Errorf("could not get next epoch: %w", err) 75 } else { 76 snap.Epochs.Next = &next.enc 77 } 78 79 // convert global state parameters 80 params, err := FromParams(from.Params()) 81 if err != nil { 82 return nil, fmt.Errorf("could not get params: %w", err) 83 } 84 snap.Params = params.enc 85 86 return &Snapshot{snap}, nil 87 } 88 89 // FromParams converts any protocol.GlobalParams to a memory-backed Params. 90 // TODO error docs 91 func FromParams(from protocol.GlobalParams) (*Params, error) { 92 93 var ( 94 params EncodableParams 95 err error 96 ) 97 98 params.ChainID, err = from.ChainID() 99 if err != nil { 100 return nil, fmt.Errorf("could not get chain id: %w", err) 101 } 102 params.SporkID, err = from.SporkID() 103 if err != nil { 104 return nil, fmt.Errorf("could not get spork id: %w", err) 105 } 106 params.ProtocolVersion, err = from.ProtocolVersion() 107 if err != nil { 108 return nil, fmt.Errorf("could not get protocol version: %w", err) 109 } 110 111 return &Params{params}, nil 112 } 113 114 // FromEpoch converts any protocol.Epoch to a memory-backed Epoch. 115 // Error returns: 116 // * protocol.ErrNoPreviousEpoch - if the epoch represents a previous epoch which does not exist. 117 // * protocol.ErrNextEpochNotSetup - if the epoch represents a next epoch which has not been set up. 118 // * state.ErrUnknownSnapshotReference - if the epoch is queried from an unresolvable snapshot. 119 func FromEpoch(from protocol.Epoch) (*Epoch, error) { 120 121 var ( 122 epoch EncodableEpoch 123 err error 124 ) 125 126 // convert top-level fields 127 epoch.Counter, err = from.Counter() 128 if err != nil { 129 return nil, fmt.Errorf("could not get counter: %w", err) 130 } 131 epoch.InitialIdentities, err = from.InitialIdentities() 132 if err != nil { 133 return nil, fmt.Errorf("could not get initial identities: %w", err) 134 } 135 epoch.FirstView, err = from.FirstView() 136 if err != nil { 137 return nil, fmt.Errorf("could not get first view: %w", err) 138 } 139 epoch.FinalView, err = from.FinalView() 140 if err != nil { 141 return nil, fmt.Errorf("could not get final view: %w", err) 142 } 143 epoch.RandomSource, err = from.RandomSource() 144 if err != nil { 145 return nil, fmt.Errorf("could not get random source: %w", err) 146 } 147 epoch.DKGPhase1FinalView, epoch.DKGPhase2FinalView, epoch.DKGPhase3FinalView, err = protocol.DKGPhaseViews(from) 148 if err != nil { 149 return nil, fmt.Errorf("could not get dkg final views") 150 } 151 clustering, err := from.Clustering() 152 if err != nil { 153 return nil, fmt.Errorf("could not get clustering: %w", err) 154 } 155 epoch.Clustering = clustering 156 157 // convert dkg 158 dkg, err := from.DKG() 159 // if this epoch hasn't been committed yet, return the epoch as-is 160 if errors.Is(err, protocol.ErrEpochNotCommitted) { 161 return &Epoch{epoch}, nil 162 } 163 if err != nil { 164 return nil, fmt.Errorf("could not get dkg: %w", err) 165 } 166 convertedDKG, err := FromDKG(dkg, epoch.InitialIdentities.Filter(filter.HasRole(flow.RoleConsensus))) 167 if err != nil { 168 return nil, err 169 } 170 epoch.DKG = &convertedDKG.enc 171 172 // convert clusters 173 for index := range clustering { 174 cluster, err := from.Cluster(uint(index)) 175 if err != nil { 176 return nil, fmt.Errorf("could not get cluster %d: %w", index, err) 177 } 178 convertedCluster, err := FromCluster(cluster) 179 if err != nil { 180 return nil, fmt.Errorf("could not convert cluster %d: %w", index, err) 181 } 182 epoch.Clusters = append(epoch.Clusters, convertedCluster.enc) 183 } 184 185 return &Epoch{epoch}, nil 186 } 187 188 // FromCluster converts any protocol.Cluster to a memory-backed Cluster. 189 // No errors are expected during normal operation. 190 func FromCluster(from protocol.Cluster) (*Cluster, error) { 191 cluster := EncodableCluster{ 192 Counter: from.EpochCounter(), 193 Index: from.Index(), 194 Members: from.Members(), 195 RootBlock: from.RootBlock(), 196 RootQC: from.RootQC(), 197 } 198 return &Cluster{cluster}, nil 199 } 200 201 // FromDKG converts any protocol.DKG to a memory-backed DKG. 202 // 203 // The given participant list must exactly match the DKG members. 204 // All errors indicate inconsistent or invalid inputs. 205 // No errors are expected during normal operation. 206 func FromDKG(from protocol.DKG, participants flow.IdentityList) (*DKG, error) { 207 var dkg EncodableDKG 208 dkg.GroupKey = encodable.RandomBeaconPubKey{PublicKey: from.GroupKey()} 209 210 lookup, err := protocol.ToDKGParticipantLookup(from, participants) 211 if err != nil { 212 return nil, fmt.Errorf("could not generate dkg participant lookup: %w", err) 213 } 214 dkg.Participants = lookup 215 216 return &DKG{dkg}, nil 217 } 218 219 // DKGFromEncodable returns a DKG backed by the given encodable representation. 220 func DKGFromEncodable(enc EncodableDKG) (*DKG, error) { 221 return &DKG{enc}, nil 222 } 223 224 // ClusterFromEncodable returns a Cluster backed by the given encodable representation. 225 func ClusterFromEncodable(enc EncodableCluster) (*Cluster, error) { 226 return &Cluster{enc}, nil 227 } 228 229 // SnapshotFromBootstrapState generates a protocol.Snapshot representing a 230 // root bootstrap state. This is used to bootstrap the protocol state for 231 // genesis or post-spork states. 232 func SnapshotFromBootstrapState(root *flow.Block, result *flow.ExecutionResult, seal *flow.Seal, qc *flow.QuorumCertificate) (*Snapshot, error) { 233 return SnapshotFromBootstrapStateWithProtocolVersion(root, result, seal, qc, flow.DefaultProtocolVersion) 234 } 235 236 // SnapshotFromBootstrapStateWithProtocolVersion is SnapshotFromBootstrapState 237 // with a caller-specified protocol version. 238 func SnapshotFromBootstrapStateWithProtocolVersion( 239 root *flow.Block, 240 result *flow.ExecutionResult, 241 seal *flow.Seal, 242 qc *flow.QuorumCertificate, 243 version uint, 244 ) (*Snapshot, error) { 245 246 setup, ok := result.ServiceEvents[0].Event.(*flow.EpochSetup) 247 if !ok { 248 return nil, fmt.Errorf("invalid setup event type (%T)", result.ServiceEvents[0].Event) 249 } 250 commit, ok := result.ServiceEvents[1].Event.(*flow.EpochCommit) 251 if !ok { 252 return nil, fmt.Errorf("invalid commit event type (%T)", result.ServiceEvents[1].Event) 253 } 254 255 clustering, err := ClusteringFromSetupEvent(setup) 256 if err != nil { 257 return nil, fmt.Errorf("setup event has invalid clustering: %w", err) 258 } 259 260 // sanity check the commit event has the same number of cluster QC as the number clusters 261 if len(clustering) != len(commit.ClusterQCs) { 262 return nil, fmt.Errorf("mismatching number of ClusterQCs, expect %v but got %v", 263 len(clustering), len(commit.ClusterQCs)) 264 } 265 266 // sanity check the QC in the commit event, which should be found in the identities in 267 // the setup event 268 for i, cluster := range clustering { 269 rootQCVoteData := commit.ClusterQCs[i] 270 _, err = signature.EncodeSignersToIndices(cluster.NodeIDs(), rootQCVoteData.VoterIDs) 271 if err != nil { 272 return nil, fmt.Errorf("mismatching cluster and qc: %w", err) 273 } 274 } 275 276 current, err := NewCommittedEpoch(setup, commit) 277 if err != nil { 278 return nil, fmt.Errorf("could not convert epoch: %w", err) 279 } 280 epochs := EncodableEpochs{ 281 Current: current.enc, 282 } 283 284 params := EncodableParams{ 285 ChainID: root.Header.ChainID, // chain ID must match the root block 286 SporkID: root.ID(), // use root block ID as the unique spork identifier 287 ProtocolVersion: version, // major software version for this spork 288 } 289 290 snap := SnapshotFromEncodable(EncodableSnapshot{ 291 Head: root.Header, 292 Identities: setup.Participants, 293 LatestSeal: seal, 294 LatestResult: result, 295 SealingSegment: &flow.SealingSegment{ 296 Blocks: []*flow.Block{root}, 297 ExecutionResults: flow.ExecutionResultList{result}, 298 LatestSeals: map[flow.Identifier]flow.Identifier{root.ID(): seal.ID()}, 299 FirstSeal: seal, 300 }, 301 QuorumCertificate: qc, 302 Phase: flow.EpochPhaseStaking, 303 Epochs: epochs, 304 Params: params, 305 }) 306 return snap, nil 307 }