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  }