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

     1  package filter
     2  
     3  import (
     4  	"github.com/onflow/crypto"
     5  
     6  	"github.com/onflow/flow-go/model/flow"
     7  )
     8  
     9  // Adapt takes an IdentityFilter on the domain of IdentitySkeletons
    10  // and adapts the filter to the domain of full Identities. In other words, it converts
    11  // flow.IdentityFilter[flow.IdentitySkeleton] to flow.IdentityFilter[flow.Identity].
    12  func Adapt(f flow.IdentityFilter[flow.IdentitySkeleton]) flow.IdentityFilter[flow.Identity] {
    13  	return func(i *flow.Identity) bool {
    14  		return f(&i.IdentitySkeleton)
    15  	}
    16  }
    17  
    18  // Any will always be true.
    19  func Any(*flow.Identity) bool {
    20  	return true
    21  }
    22  
    23  // And combines two or more filters that all need to be true.
    24  func And[T flow.GenericIdentity](filters ...flow.IdentityFilter[T]) flow.IdentityFilter[T] {
    25  	return func(identity *T) bool {
    26  		for _, filter := range filters {
    27  			if !filter(identity) {
    28  				return false
    29  			}
    30  		}
    31  		return true
    32  	}
    33  }
    34  
    35  // Or combines two or more filters and only needs one of them to be true.
    36  func Or[T flow.GenericIdentity](filters ...flow.IdentityFilter[T]) flow.IdentityFilter[T] {
    37  	return func(identity *T) bool {
    38  		for _, filter := range filters {
    39  			if filter(identity) {
    40  				return true
    41  			}
    42  		}
    43  		return false
    44  	}
    45  }
    46  
    47  // Not returns a filter equivalent to the inverse of the input filter.
    48  func Not[T flow.GenericIdentity](filter flow.IdentityFilter[T]) flow.IdentityFilter[T] {
    49  	return func(identity *T) bool {
    50  		return !filter(identity)
    51  	}
    52  }
    53  
    54  // In returns a filter for identities within the input list. For an input identity i,
    55  // the filter returns true if and only if i ∈ list.
    56  // Caution: The filter solely operates on NodeIDs. Other identity fields are not compared.
    57  // This function is just a compact representation of `HasNodeID[T](list.NodeIDs()...)`
    58  // which behaves algorithmically the same way.
    59  func In[T flow.GenericIdentity](list flow.GenericIdentityList[T]) flow.IdentityFilter[T] {
    60  	return HasNodeID[T](list.NodeIDs()...)
    61  }
    62  
    63  // HasNodeID returns a filter that returns true for any identity with an ID
    64  // matching any of the inputs.
    65  func HasNodeID[T flow.GenericIdentity](nodeIDs ...flow.Identifier) flow.IdentityFilter[T] {
    66  	lookup := make(map[flow.Identifier]struct{})
    67  	for _, nodeID := range nodeIDs {
    68  		lookup[nodeID] = struct{}{}
    69  	}
    70  	return func(identity *T) bool {
    71  		_, ok := lookup[(*identity).GetNodeID()]
    72  		return ok
    73  	}
    74  }
    75  
    76  // HasNetworkingKey returns a filter that returns true for any identity with a
    77  // networking public key matching any of the inputs.
    78  func HasNetworkingKey(keys ...crypto.PublicKey) flow.IdentityFilter[flow.Identity] {
    79  	return func(identity *flow.Identity) bool {
    80  		for _, key := range keys {
    81  			if key.Equals(identity.NetworkPubKey) {
    82  				return true
    83  			}
    84  		}
    85  		return false
    86  	}
    87  }
    88  
    89  // HasInitialWeight returns a filter for nodes with non-zero initial weight.
    90  func HasInitialWeight[T flow.GenericIdentity](hasWeight bool) flow.IdentityFilter[T] {
    91  	return func(identity *T) bool {
    92  		return ((*identity).GetInitialWeight() > 0) == hasWeight
    93  	}
    94  }
    95  
    96  // HasParticipationStatus is a filter that returns true if the node epoch participation status matches the input.
    97  func HasParticipationStatus(status flow.EpochParticipationStatus) flow.IdentityFilter[flow.Identity] {
    98  	return func(identity *flow.Identity) bool {
    99  		return identity.EpochParticipationStatus == status
   100  	}
   101  }
   102  
   103  // HasRole returns a filter for nodes with one of the input roles.
   104  func HasRole[T flow.GenericIdentity](roles ...flow.Role) flow.IdentityFilter[T] {
   105  	lookup := make(map[flow.Role]struct{})
   106  	for _, role := range roles {
   107  		lookup[role] = struct{}{}
   108  	}
   109  	return func(identity *T) bool {
   110  		_, ok := lookup[(*identity).GetRole()]
   111  		return ok
   112  	}
   113  }
   114  
   115  // IsValidCurrentEpochParticipant is an identity filter for members of the
   116  // current epoch in good standing.
   117  // Effective it means that node is an active identity in current epoch and has not been ejected.
   118  var IsValidCurrentEpochParticipant = HasParticipationStatus(flow.EpochParticipationStatusActive)
   119  
   120  // IsValidCurrentEpochParticipantOrJoining is an identity filter for members of the current epoch or that are going to join in next epoch.
   121  var IsValidCurrentEpochParticipantOrJoining = Or(IsValidCurrentEpochParticipant, HasParticipationStatus(flow.EpochParticipationStatusJoining))
   122  
   123  // IsConsensusCommitteeMember is an identity filter for all members of the consensus committee.
   124  // Formally, a Node X is a Consensus Committee Member if and only if X is a consensus node with
   125  // positive initial weight. This is specified by the EpochSetup Event and remains static
   126  // throughout the epoch.
   127  var IsConsensusCommitteeMember = And(
   128  	HasRole[flow.IdentitySkeleton](flow.RoleConsensus),
   129  	HasInitialWeight[flow.IdentitySkeleton](true),
   130  )
   131  
   132  // IsVotingConsensusCommitteeMember is an identity filter for all members of
   133  // the consensus committee allowed to vote.
   134  // Formally, a Node X has authority to vote in the consensus process, if and only if
   135  //  1. Node X is an active member of the current epoch AND
   136  //  2. X is a consensus node with positive initial weight in the current Epoch. This
   137  //     is specified by the EpochSetup Event for the current epoch and remains static
   138  //     throughout the epoch.
   139  var IsVotingConsensusCommitteeMember = And[flow.Identity](
   140  	IsValidCurrentEpochParticipant,    // enforces 1.
   141  	Adapt(IsConsensusCommitteeMember), // enforces 2.
   142  )
   143  
   144  // IsValidDKGParticipant is an identity filter for all DKG participants. It is
   145  // equivalent to the filter for consensus committee members, as these are
   146  // the same group for now.
   147  var IsValidDKGParticipant = IsConsensusCommitteeMember
   148  
   149  // NotEjectedFilter is an identity filter for peers that are not ejected.
   150  var NotEjectedFilter = Not(HasParticipationStatus(flow.EpochParticipationStatusEjected))
   151  
   152  // HasWeightGreaterThanZero returns a filter for nodes with a weight greater than zero.
   153  func HasWeightGreaterThanZero[T flow.GenericIdentity](identity *T) bool {
   154  	return (*identity).GetInitialWeight() > 0
   155  }
   156  
   157  // IsValidProtocolParticipant is an identity filter for all valid protocol participants.
   158  // A protocol participant is considered valid if and only if the following are both true.
   159  // 1. The node is not ejected.
   160  // 2. The node has a weight greater than 0.
   161  var IsValidProtocolParticipant = And[flow.Identity](
   162  	NotEjectedFilter,                        // enforces 1
   163  	HasWeightGreaterThanZero[flow.Identity], // enforces 2
   164  )