github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/model/flow/identity_order.go (about)

     1  package flow
     2  
     3  // Canonical is a function that defines a weak strict ordering "<" for identities.
     4  // It returns:
     5  //   - a strict negative number if id1 < id2
     6  //   - a strict positive number if id2 < id1
     7  //   - zero if id1 and id2 are equal
     8  //
     9  // By definition, two identities (id1, id2) are in canonical order if id1's NodeID is lexicographically
    10  // _strictly_ smaller than id2's NodeID. The strictness is important, meaning that identities
    11  // with equal NodeIDs do not satisfy canonical ordering (order is irreflexive).
    12  // Hence, only a returned strictly negative value means the pair is in canonical order.
    13  // Use `IsCanonical` for canonical order checks.
    14  //
    15  // The current function is based on the identifiers bytes lexicographic comparison.
    16  func Canonical[T GenericIdentity](identity1 *T, identity2 *T) int {
    17  	return IdentifierCanonical((*identity1).GetNodeID(), (*identity2).GetNodeID())
    18  }
    19  
    20  // IsCanonical returns true if and only if the given Identities are in canonical order.
    21  //
    22  // By convention, two Identities (i1, i2) are in canonical order if i1's NodeID bytes
    23  // are lexicographically _strictly_ smaller than i2's NodeID bytes.
    24  //
    25  // The strictness is important, meaning that two identities with the same
    26  // NodeID do not satisfy the canonical order.
    27  // This also implies that the canonical order is irreflexive ((i,i) isn't in canonical order).
    28  func IsCanonical[T GenericIdentity](i1, i2 *T) bool {
    29  	return Canonical(i1, i2) < 0
    30  }
    31  
    32  // ByReferenceOrder return a function for sorting identities based on the order
    33  // of the given nodeIDs
    34  func ByReferenceOrder(nodeIDs []Identifier) func(*Identity, *Identity) int {
    35  	indices := make(map[Identifier]int)
    36  	for index, nodeID := range nodeIDs {
    37  		_, ok := indices[nodeID]
    38  		if ok {
    39  			panic("should never order by reference order with duplicate node IDs")
    40  		}
    41  		indices[nodeID] = index
    42  	}
    43  	return func(identity1 *Identity, identity2 *Identity) int {
    44  		return indices[identity1.NodeID] - indices[identity2.NodeID]
    45  	}
    46  }
    47  
    48  // IsIdentityListCanonical returns true if and only if the given IdentityList is
    49  // _strictly_ sorted with regards to the canonical order.
    50  //
    51  // The strictness is important here, meaning that a list with 2 successive entities
    52  // with equal NodeID isn't considered well sorted.
    53  func IsIdentityListCanonical[T GenericIdentity](il GenericIdentityList[T]) bool {
    54  	for i := 0; i < len(il)-1; i++ {
    55  		if !IsCanonical(il[i], il[i+1]) {
    56  			return false
    57  		}
    58  	}
    59  	return true
    60  }