github.com/onflow/flow-go@v0.33.17/model/flow/factory/cluster_list.go (about)

     1  package factory
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/onflow/flow-go/model/flow"
     7  )
     8  
     9  // NewClusterList creates a new cluster list based on the given cluster assignment
    10  // and the provided list of identities.
    11  //
    12  // The caller must ensure the following prerequisites:
    13  //   - each assignment contains identities ordered in canonical order
    14  //   - every collector has a unique NodeID, i.e. there are no two elements in `collectors` with the same NodeID
    15  //
    16  // These prerequisites ensures that each cluster in the returned cluster list is ordered in canonical order as well.
    17  // This function checks that the prerequisites are satisfied and errors otherwise.
    18  func NewClusterList(assignments flow.AssignmentList, collectors flow.IdentityList) (flow.ClusterList, error) {
    19  
    20  	// build a lookup for all the identities by node identifier
    21  	lookup := make(map[flow.Identifier]*flow.Identity)
    22  	for _, collector := range collectors {
    23  		lookup[collector.NodeID] = collector
    24  	}
    25  	if len(lookup) != len(collectors) {
    26  		return nil, fmt.Errorf("duplicate collector in list")
    27  	}
    28  
    29  	// replicate the identifier list but use identities instead
    30  	clusters := make(flow.ClusterList, 0, len(assignments))
    31  	for i, participants := range assignments {
    32  		cluster := make(flow.IdentityList, 0, len(participants))
    33  		if len(participants) == 0 {
    34  			return nil, fmt.Errorf("participants in assignment list is empty, cluster index %v", i)
    35  		}
    36  
    37  		// Check assignments is sorted in canonical order
    38  		prev := participants[0]
    39  
    40  		for i, participantID := range participants {
    41  			participant, found := lookup[participantID]
    42  			if !found {
    43  				return nil, fmt.Errorf("could not find collector identity (%x)", participantID)
    44  			}
    45  			cluster = append(cluster, participant)
    46  			delete(lookup, participantID)
    47  
    48  			if i > 0 {
    49  				if !flow.IsIdentifierCanonical(prev, participantID) {
    50  					return nil, fmt.Errorf("the assignments is not sorted in canonical order or there are duplicates in cluster index %v, prev %v, next %v",
    51  						i, prev, participantID)
    52  				}
    53  			}
    54  			prev = participantID
    55  		}
    56  
    57  		clusters = append(clusters, cluster)
    58  	}
    59  
    60  	// check that every collector was assigned
    61  	if len(lookup) != 0 {
    62  		return nil, fmt.Errorf("missing collector assignments (%s)", lookup)
    63  	}
    64  
    65  	return clusters, nil
    66  }