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

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