github.com/koko1123/flow-go-1@v0.29.6/model/convert/service_event.go (about)

     1  package convert
     2  
     3  import (
     4  	"encoding/hex"
     5  	"fmt"
     6  
     7  	"github.com/onflow/cadence"
     8  	"github.com/onflow/cadence/encoding/json"
     9  
    10  	"github.com/onflow/flow-go/crypto"
    11  	"github.com/koko1123/flow-go-1/fvm/systemcontracts"
    12  	"github.com/koko1123/flow-go-1/model/flow"
    13  	"github.com/koko1123/flow-go-1/model/flow/assignment"
    14  	"github.com/koko1123/flow-go-1/model/flow/order"
    15  )
    16  
    17  // ServiceEvent converts a service event encoded as the generic flow.Event
    18  // type to a flow.ServiceEvent type for use within protocol software and protocol
    19  // state. This acts as the conversion from the Cadence type to the flow-go type.
    20  func ServiceEvent(chainID flow.ChainID, event flow.Event) (*flow.ServiceEvent, error) {
    21  
    22  	events, err := systemcontracts.ServiceEventsForChain(chainID)
    23  	if err != nil {
    24  		return nil, fmt.Errorf("could not get service event info: %w", err)
    25  	}
    26  
    27  	// depending on type of service event construct Go type
    28  	switch event.Type {
    29  	case events.EpochSetup.EventType():
    30  		return convertServiceEventEpochSetup(event)
    31  	case events.EpochCommit.EventType():
    32  		return convertServiceEventEpochCommit(event)
    33  	default:
    34  		return nil, fmt.Errorf("invalid event type: %s", event.Type)
    35  	}
    36  }
    37  
    38  // convertServiceEventEpochSetup converts a service event encoded as the generic
    39  // flow.Event type to a ServiceEvent type for an EpochSetup event
    40  func convertServiceEventEpochSetup(event flow.Event) (*flow.ServiceEvent, error) {
    41  
    42  	// decode bytes using jsoncdc
    43  	payload, err := json.Decode(nil, event.Payload)
    44  	if err != nil {
    45  		return nil, fmt.Errorf("could not unmarshal event payload: %w", err)
    46  	}
    47  
    48  	// parse cadence types to required fields
    49  	setup := new(flow.EpochSetup)
    50  
    51  	// NOTE: variable names prefixed with cdc represent cadence types
    52  	cdcEvent, ok := payload.(cadence.Event)
    53  	if !ok {
    54  		return nil, invalidCadenceTypeError("payload", payload, cadence.Event{})
    55  	}
    56  
    57  	if len(cdcEvent.Fields) < 9 {
    58  		return nil, fmt.Errorf("insufficient fields in EpochSetup event (%d < 9)", len(cdcEvent.Fields))
    59  	}
    60  
    61  	// extract simple fields
    62  	counter, ok := cdcEvent.Fields[0].(cadence.UInt64)
    63  	if !ok {
    64  		return nil, invalidCadenceTypeError("counter", cdcEvent.Fields[0], cadence.UInt64(0))
    65  	}
    66  	setup.Counter = uint64(counter)
    67  	firstView, ok := cdcEvent.Fields[2].(cadence.UInt64)
    68  	if !ok {
    69  		return nil, invalidCadenceTypeError("firstView", cdcEvent.Fields[2], cadence.UInt64(0))
    70  	}
    71  	setup.FirstView = uint64(firstView)
    72  	finalView, ok := cdcEvent.Fields[3].(cadence.UInt64)
    73  	if !ok {
    74  		return nil, invalidCadenceTypeError("finalView", cdcEvent.Fields[3], cadence.UInt64(0))
    75  	}
    76  	setup.FinalView = uint64(finalView)
    77  	randomSrcHex, ok := cdcEvent.Fields[5].(cadence.String)
    78  	if !ok {
    79  		return nil, invalidCadenceTypeError("randomSource", cdcEvent.Fields[5], cadence.String(""))
    80  	}
    81  	// Cadence's unsafeRandom().toString() produces a string of variable length.
    82  	// Here we pad it with enough 0s to meet the required length.
    83  	paddedRandomSrcHex := fmt.Sprintf("%0*s", 2*flow.EpochSetupRandomSourceLength, string(randomSrcHex))
    84  	setup.RandomSource, err = hex.DecodeString(paddedRandomSrcHex)
    85  	if err != nil {
    86  		return nil, fmt.Errorf("could not decode random source hex (%v): %w", paddedRandomSrcHex, err)
    87  	}
    88  
    89  	dkgPhase1FinalView, ok := cdcEvent.Fields[6].(cadence.UInt64)
    90  	if !ok {
    91  		return nil, invalidCadenceTypeError("dkgPhase1FinalView", cdcEvent.Fields[6], cadence.UInt64(0))
    92  	}
    93  	setup.DKGPhase1FinalView = uint64(dkgPhase1FinalView)
    94  	dkgPhase2FinalView, ok := cdcEvent.Fields[7].(cadence.UInt64)
    95  	if !ok {
    96  		return nil, invalidCadenceTypeError("dkgPhase2FinalView", cdcEvent.Fields[7], cadence.UInt64(0))
    97  	}
    98  	setup.DKGPhase2FinalView = uint64(dkgPhase2FinalView)
    99  	dkgPhase3FinalView, ok := cdcEvent.Fields[8].(cadence.UInt64)
   100  	if !ok {
   101  		return nil, invalidCadenceTypeError("dkgPhase3FinalView", cdcEvent.Fields[8], cadence.UInt64(0))
   102  	}
   103  	setup.DKGPhase3FinalView = uint64(dkgPhase3FinalView)
   104  
   105  	// parse cluster assignments
   106  	cdcClusters, ok := cdcEvent.Fields[4].(cadence.Array)
   107  	if !ok {
   108  		return nil, invalidCadenceTypeError("clusters", cdcEvent.Fields[4], cadence.Array{})
   109  	}
   110  	setup.Assignments, err = convertClusterAssignments(cdcClusters.Values)
   111  	if err != nil {
   112  		return nil, fmt.Errorf("could not convert cluster assignments: %w", err)
   113  	}
   114  
   115  	// parse epoch participants
   116  	cdcParticipants, ok := cdcEvent.Fields[1].(cadence.Array)
   117  	if !ok {
   118  		return nil, invalidCadenceTypeError("participants", cdcEvent.Fields[1], cadence.Array{})
   119  	}
   120  	setup.Participants, err = convertParticipants(cdcParticipants.Values)
   121  	if err != nil {
   122  		return nil, fmt.Errorf("could not convert participants: %w", err)
   123  	}
   124  
   125  	// construct the service event
   126  	serviceEvent := &flow.ServiceEvent{
   127  		Type:  flow.ServiceEventSetup,
   128  		Event: setup,
   129  	}
   130  
   131  	return serviceEvent, nil
   132  }
   133  
   134  // convertServiceEventEpochCommit converts a service event encoded as the generic
   135  // flow.Event type to a ServiceEvent type for an EpochCommit event
   136  func convertServiceEventEpochCommit(event flow.Event) (*flow.ServiceEvent, error) {
   137  
   138  	// decode bytes using jsoncdc
   139  	payload, err := json.Decode(nil, event.Payload)
   140  	if err != nil {
   141  		return nil, fmt.Errorf("could not unmarshal event payload: %w", err)
   142  	}
   143  
   144  	// parse cadence types to Go types
   145  	commit := new(flow.EpochCommit)
   146  	commit.Counter = uint64(payload.(cadence.Event).Fields[0].(cadence.UInt64))
   147  
   148  	// parse cluster qc votes
   149  	cdcClusterQCVotes := payload.(cadence.Event).Fields[1].(cadence.Array).Values
   150  	commit.ClusterQCs, err = convertClusterQCVotes(cdcClusterQCVotes)
   151  	if err != nil {
   152  		return nil, fmt.Errorf("could not convert cluster qc votes: %w", err)
   153  	}
   154  
   155  	// parse DKG group key and participants
   156  	// Note: this is read in the same order as `DKGClient.SubmitResult` ie. with the group public key first followed by individual keys
   157  	// https://github.com/koko1123/flow-go-1/blob/feature/dkg/module/dkg/client.go#L182-L183
   158  	cdcDKGKeys := payload.(cadence.Event).Fields[2].(cadence.Array).Values
   159  	dkgGroupKey, dkgParticipantKeys, err := convertDKGKeys(cdcDKGKeys)
   160  	if err != nil {
   161  		return nil, fmt.Errorf("could not convert DKG keys: %w", err)
   162  	}
   163  
   164  	commit.DKGGroupKey = dkgGroupKey
   165  	commit.DKGParticipantKeys = dkgParticipantKeys
   166  
   167  	// create the service event
   168  	serviceEvent := &flow.ServiceEvent{
   169  		Type:  flow.ServiceEventCommit,
   170  		Event: commit,
   171  	}
   172  
   173  	return serviceEvent, nil
   174  }
   175  
   176  // convertClusterAssignments converts the Cadence representation of cluster
   177  // assignments included in the EpochSetup into the protocol AssignmentList
   178  // representation.
   179  func convertClusterAssignments(cdcClusters []cadence.Value) (flow.AssignmentList, error) {
   180  
   181  	// ensure we don't have duplicate cluster indices
   182  	indices := make(map[uint]struct{})
   183  
   184  	// parse cluster assignments to Go types
   185  	identifierLists := make([]flow.IdentifierList, len(cdcClusters))
   186  	for _, value := range cdcClusters {
   187  
   188  		cdcCluster, ok := value.(cadence.Struct)
   189  		if !ok {
   190  			return nil, invalidCadenceTypeError("cluster", cdcCluster, cadence.Struct{})
   191  		}
   192  
   193  		expectedFields := 2
   194  		if len(cdcCluster.Fields) < expectedFields {
   195  			return nil, fmt.Errorf("insufficient fields (%d < %d)", len(cdcCluster.Fields), expectedFields)
   196  		}
   197  
   198  		// ensure cluster index is valid
   199  		clusterIndex, ok := cdcCluster.Fields[0].(cadence.UInt16)
   200  		if !ok {
   201  			return nil, invalidCadenceTypeError("clusterIndex", cdcCluster.Fields[0], cadence.UInt16(0))
   202  		}
   203  		if int(clusterIndex) >= len(cdcClusters) {
   204  			return nil, fmt.Errorf("invalid cdcCluster index (%d) outside range [0,%d]", clusterIndex, len(cdcClusters)-1)
   205  		}
   206  		_, dup := indices[uint(clusterIndex)]
   207  		if dup {
   208  			return nil, fmt.Errorf("duplicate cdcCluster index (%d)", clusterIndex)
   209  		}
   210  
   211  		// read weights to retrieve node IDs of cdcCluster members
   212  		weightsByNodeID, ok := cdcCluster.Fields[1].(cadence.Dictionary)
   213  		if !ok {
   214  			return nil, invalidCadenceTypeError("clusterWeights", cdcCluster.Fields[1], cadence.Dictionary{})
   215  		}
   216  
   217  		for _, pair := range weightsByNodeID.Pairs {
   218  
   219  			nodeIDString, ok := pair.Key.(cadence.String)
   220  			if !ok {
   221  				return nil, invalidCadenceTypeError("clusterWeights.nodeID", pair.Key, cadence.String(""))
   222  			}
   223  			nodeID, err := flow.HexStringToIdentifier(string(nodeIDString))
   224  			if err != nil {
   225  				return nil, fmt.Errorf("could not convert hex string to identifer: %w", err)
   226  			}
   227  
   228  			identifierLists[clusterIndex] = append(identifierLists[clusterIndex], nodeID)
   229  		}
   230  	}
   231  
   232  	// sort identifier lists in Canonical order
   233  	assignments := assignment.FromIdentifierLists(identifierLists)
   234  
   235  	return assignments, nil
   236  }
   237  
   238  // convertParticipants converts the network participants specified in the
   239  // EpochSetup event into an IdentityList.
   240  func convertParticipants(cdcParticipants []cadence.Value) (flow.IdentityList, error) {
   241  
   242  	participants := make(flow.IdentityList, 0, len(cdcParticipants))
   243  	var err error
   244  
   245  	for _, value := range cdcParticipants {
   246  
   247  		cdcNodeInfoStruct, ok := value.(cadence.Struct)
   248  		if !ok {
   249  			return nil, invalidCadenceTypeError("cdcNodeInfoFields", value, cadence.Struct{})
   250  		}
   251  		cdcNodeInfoFields := cdcNodeInfoStruct.Fields
   252  
   253  		expectedFields := 14
   254  		if len(cdcNodeInfoFields) < expectedFields {
   255  			return nil, fmt.Errorf("insufficient fields (%d < %d)", len(cdcNodeInfoFields), expectedFields)
   256  		}
   257  
   258  		// create and assign fields to identity from cadence Struct
   259  		identity := new(flow.Identity)
   260  		role, ok := cdcNodeInfoFields[1].(cadence.UInt8)
   261  		if !ok {
   262  			return nil, invalidCadenceTypeError("nodeInfo.role", cdcNodeInfoFields[1], cadence.UInt8(0))
   263  		}
   264  		identity.Role = flow.Role(role)
   265  		if !identity.Role.Valid() {
   266  			return nil, fmt.Errorf("invalid role %d", role)
   267  		}
   268  
   269  		address, ok := cdcNodeInfoFields[2].(cadence.String)
   270  		if !ok {
   271  			return nil, invalidCadenceTypeError("nodeInfo.address", cdcNodeInfoFields[2], cadence.String(""))
   272  		}
   273  		identity.Address = string(address)
   274  
   275  		initialWeight, ok := cdcNodeInfoFields[13].(cadence.UInt64)
   276  		if !ok {
   277  			return nil, invalidCadenceTypeError("nodeInfo.initialWeight", cdcNodeInfoFields[13], cadence.UInt64(0))
   278  		}
   279  		identity.Weight = uint64(initialWeight)
   280  
   281  		// convert nodeID string into identifier
   282  		nodeIDHex, ok := cdcNodeInfoFields[0].(cadence.String)
   283  		if !ok {
   284  			return nil, invalidCadenceTypeError("nodeInfo.id", cdcNodeInfoFields[0], cadence.String(""))
   285  		}
   286  		identity.NodeID, err = flow.HexStringToIdentifier(string(nodeIDHex))
   287  		if err != nil {
   288  			return nil, fmt.Errorf("could not convert hex string to identifer: %w", err)
   289  		}
   290  
   291  		// parse to PublicKey the networking key hex string
   292  		networkKeyHex, ok := cdcNodeInfoFields[3].(cadence.String)
   293  		if !ok {
   294  			return nil, invalidCadenceTypeError("nodeInfo.networkKey", cdcNodeInfoFields[3], cadence.String(""))
   295  		}
   296  		networkKeyBytes, err := hex.DecodeString(string(networkKeyHex))
   297  		if err != nil {
   298  			return nil, fmt.Errorf("could not decode network public key into bytes: %w", err)
   299  		}
   300  		identity.NetworkPubKey, err = crypto.DecodePublicKey(crypto.ECDSAP256, networkKeyBytes)
   301  		if err != nil {
   302  			return nil, fmt.Errorf("could not decode network public key: %w", err)
   303  		}
   304  
   305  		// parse to PublicKey the staking key hex string
   306  		stakingKeyHex, ok := cdcNodeInfoFields[4].(cadence.String)
   307  		if !ok {
   308  			return nil, invalidCadenceTypeError("nodeInfo.stakingKey", cdcNodeInfoFields[4], cadence.String(""))
   309  		}
   310  		stakingKeyBytes, err := hex.DecodeString(string(stakingKeyHex))
   311  		if err != nil {
   312  			return nil, fmt.Errorf("could not decode staking public key into bytes: %w", err)
   313  		}
   314  		identity.StakingPubKey, err = crypto.DecodePublicKey(crypto.BLSBLS12381, stakingKeyBytes)
   315  		if err != nil {
   316  			return nil, fmt.Errorf("could not decode staking public key: %w", err)
   317  		}
   318  
   319  		participants = append(participants, identity)
   320  	}
   321  
   322  	participants = participants.Sort(order.Canonical)
   323  	return participants, nil
   324  }
   325  
   326  // convertClusterQCVotes converts raw cluster QC votes from the EpochCommit event
   327  // to a representation suitable for inclusion in the protocol state. Votes are
   328  // aggregated as part of this conversion.
   329  func convertClusterQCVotes(cdcClusterQCs []cadence.Value) ([]flow.ClusterQCVoteData, error) {
   330  
   331  	// avoid duplicate indices
   332  	indices := make(map[uint]struct{})
   333  	qcVoteDatas := make([]flow.ClusterQCVoteData, len(cdcClusterQCs))
   334  
   335  	// CAUTION: Votes are not validated prior to aggregation. This means a single
   336  	// invalid vote submission will result in a fully invalid QC for that cluster.
   337  	// Votes must be validated by the ClusterQC smart contract.
   338  
   339  	for _, cdcClusterQC := range cdcClusterQCs {
   340  		cdcClusterQCStruct, ok := cdcClusterQC.(cadence.Struct)
   341  		if !ok {
   342  			return nil, invalidCadenceTypeError("clusterQC", cdcClusterQC, cadence.Struct{})
   343  		}
   344  		cdcClusterQCFields := cdcClusterQCStruct.Fields
   345  
   346  		expectedFields := 4
   347  		if len(cdcClusterQCFields) < expectedFields {
   348  			return nil, fmt.Errorf("insufficient fields (%d < %d)", len(cdcClusterQCFields), expectedFields)
   349  		}
   350  
   351  		index, ok := cdcClusterQCFields[0].(cadence.UInt16)
   352  		if !ok {
   353  			return nil, invalidCadenceTypeError("clusterQC.index", cdcClusterQCFields[0], cadence.UInt16(0))
   354  		}
   355  		if int(index) >= len(cdcClusterQCs) {
   356  			return nil, fmt.Errorf("invalid index (%d) not in range [0,%d]", index, len(cdcClusterQCs))
   357  		}
   358  		_, dup := indices[uint(index)]
   359  		if dup {
   360  			return nil, fmt.Errorf("duplicate cluster QC index (%d)", index)
   361  		}
   362  
   363  		cdcVoterIDs, ok := cdcClusterQCFields[3].(cadence.Array)
   364  		if !ok {
   365  			return nil, invalidCadenceTypeError("clusterQC.voterIDs", cdcClusterQCFields[2], cadence.Array{})
   366  		}
   367  
   368  		voterIDs := make([]flow.Identifier, 0, len(cdcVoterIDs.Values))
   369  		for _, cdcVoterID := range cdcVoterIDs.Values {
   370  			voterIDHex, ok := cdcVoterID.(cadence.String)
   371  			if !ok {
   372  				return nil, invalidCadenceTypeError("clusterQC[i].voterID", cdcVoterID, cadence.String(""))
   373  			}
   374  			voterID, err := flow.HexStringToIdentifier(string(voterIDHex))
   375  			if err != nil {
   376  				return nil, fmt.Errorf("could not convert voter ID from hex: %w", err)
   377  			}
   378  			voterIDs = append(voterIDs, voterID)
   379  		}
   380  
   381  		// gather all the vote signatures
   382  		cdcRawVotes := cdcClusterQCFields[1].(cadence.Array)
   383  		signatures := make([]crypto.Signature, 0, len(cdcRawVotes.Values))
   384  		for _, cdcRawVote := range cdcRawVotes.Values {
   385  			rawVoteHex, ok := cdcRawVote.(cadence.String)
   386  			if !ok {
   387  				return nil, invalidCadenceTypeError("clusterQC[i].vote", cdcRawVote, cadence.String(""))
   388  			}
   389  			rawVoteBytes, err := hex.DecodeString(string(rawVoteHex))
   390  			if err != nil {
   391  				return nil, fmt.Errorf("could not convert raw vote from hex: %w", err)
   392  			}
   393  			signatures = append(signatures, rawVoteBytes)
   394  		}
   395  		// Aggregate BLS signatures
   396  		aggregatedSignature, err := crypto.AggregateBLSSignatures(signatures)
   397  		if err != nil {
   398  			return nil, fmt.Errorf("cluster qc vote aggregation failed: %w", err)
   399  		}
   400  
   401  		// set the fields on the QC vote data object
   402  		qcVoteDatas[int(index)] = flow.ClusterQCVoteData{
   403  			SigData:  aggregatedSignature,
   404  			VoterIDs: voterIDs,
   405  		}
   406  	}
   407  
   408  	return qcVoteDatas, nil
   409  }
   410  
   411  // convertDKGKeys converts hex-encoded DKG public keys as received by the DKG
   412  // smart contract into crypto.PublicKey representations suitable for inclusion
   413  // in the protocol state.
   414  func convertDKGKeys(cdcDKGKeys []cadence.Value) (groupKey crypto.PublicKey, participantKeys []crypto.PublicKey, err error) {
   415  
   416  	hexDKGKeys := make([]string, 0, len(cdcDKGKeys))
   417  	for _, value := range cdcDKGKeys {
   418  		keyHex, ok := value.(cadence.String)
   419  		if !ok {
   420  			return nil, nil, invalidCadenceTypeError("dkgKey", value, cadence.String(""))
   421  		}
   422  		hexDKGKeys = append(hexDKGKeys, string(keyHex))
   423  	}
   424  
   425  	// pop first element - group public key hex string
   426  	groupPubKeyHex := hexDKGKeys[0]
   427  	hexDKGKeys = hexDKGKeys[1:]
   428  
   429  	// decode group public key
   430  	groupKeyBytes, err := hex.DecodeString(groupPubKeyHex)
   431  	if err != nil {
   432  		return nil, nil, fmt.Errorf("could not decode group public key into bytes: %w", err)
   433  	}
   434  	groupKey, err = crypto.DecodePublicKey(crypto.BLSBLS12381, groupKeyBytes)
   435  	if err != nil {
   436  		return nil, nil, fmt.Errorf("could not decode group public key: %w", err)
   437  	}
   438  
   439  	// decode individual public keys
   440  	dkgParticipantKeys := make([]crypto.PublicKey, 0, len(hexDKGKeys))
   441  	for _, pubKeyString := range hexDKGKeys {
   442  
   443  		pubKeyBytes, err := hex.DecodeString(pubKeyString)
   444  		if err != nil {
   445  			return nil, nil, fmt.Errorf("could not decode individual public key into bytes: %w", err)
   446  		}
   447  		pubKey, err := crypto.DecodePublicKey(crypto.BLSBLS12381, pubKeyBytes)
   448  		if err != nil {
   449  			return nil, nil, fmt.Errorf("could not decode dkg public key: %w", err)
   450  		}
   451  		dkgParticipantKeys = append(dkgParticipantKeys, pubKey)
   452  	}
   453  
   454  	return groupKey, dkgParticipantKeys, nil
   455  }
   456  
   457  func invalidCadenceTypeError(fieldName string, actualType, expectedType cadence.Value) error {
   458  	return fmt.Errorf("invalid Cadence type for field %s (got=%s, expected=%s)",
   459  		fieldName,
   460  		actualType.Type().ID(),
   461  		expectedType.Type().ID())
   462  }