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

     1  package flow
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"fmt"
     7  	"io"
     8  	"math"
     9  	"math/rand"
    10  	"regexp"
    11  	"strconv"
    12  
    13  	"golang.org/x/exp/slices"
    14  
    15  	"github.com/ethereum/go-ethereum/rlp"
    16  	"github.com/fxamacker/cbor/v2"
    17  	"github.com/pkg/errors"
    18  	"github.com/vmihailenco/msgpack"
    19  
    20  	"github.com/onflow/flow-go/crypto"
    21  )
    22  
    23  // DefaultInitialWeight is the default initial weight for a node identity.
    24  // It is equal to the default initial weight in the FlowIDTableStaking smart contract.
    25  const DefaultInitialWeight = 100
    26  
    27  // rxid is the regex for parsing node identity entries.
    28  var rxid = regexp.MustCompile(`^(collection|consensus|execution|verification|access)-([0-9a-fA-F]{64})@([\w\d]+|[\w\d][\w\d\-]*[\w\d](?:\.*[\w\d][\w\d\-]*[\w\d])*|[\w\d][\w\d\-]*[\w\d])(:[\d]+)?=(\d{1,20})$`)
    29  
    30  // Identity represents the public identity of one network participant (node).
    31  type Identity struct {
    32  	// NodeID uniquely identifies a particular node. A node's ID is fixed for
    33  	// the duration of that node's participation in the network.
    34  	NodeID Identifier
    35  	// Address is the network address where the node can be reached.
    36  	Address string
    37  	// Role is the node's role in the network and defines its abilities and
    38  	// responsibilities.
    39  	Role Role
    40  	// Weight represents the node's authority to perform certain tasks relative
    41  	// to other nodes. For example, in the consensus committee, the node's weight
    42  	// represents the weight assigned to its votes.
    43  	//
    44  	// A node's weight is distinct from its stake. Stake represents the quantity
    45  	// of FLOW tokens held by the network in escrow during the course of the node's
    46  	// participation in the network. The stake is strictly managed by the service
    47  	// account smart contracts.
    48  	//
    49  	// Nodes which are registered to join at the next epoch will appear in the
    50  	// identity table but are considered to have zero weight up until their first
    51  	// epoch begins. Likewise nodes which were registered in the previous epoch
    52  	// but have left at the most recent epoch boundary will appear in the identity
    53  	// table with zero weight.
    54  	Weight uint64
    55  	// Ejected represents whether a node has been permanently removed from the
    56  	// network. A node may be ejected for either:
    57  	// * committing one protocol felony
    58  	// * committing a series of protocol misdemeanours
    59  	Ejected       bool
    60  	StakingPubKey crypto.PublicKey
    61  	NetworkPubKey crypto.PublicKey
    62  }
    63  
    64  // ParseIdentity parses a string representation of an identity.
    65  func ParseIdentity(identity string) (*Identity, error) {
    66  
    67  	// use the regex to match the four parts of an identity
    68  	matches := rxid.FindStringSubmatch(identity)
    69  	if len(matches) != 6 {
    70  		return nil, errors.New("invalid identity string format")
    71  	}
    72  
    73  	// none of these will error as they are checked by the regex
    74  	var nodeID Identifier
    75  	nodeID, err := HexStringToIdentifier(matches[2])
    76  	if err != nil {
    77  		return nil, err
    78  	}
    79  	address := matches[3] + matches[4]
    80  	role, _ := ParseRole(matches[1])
    81  	weight, _ := strconv.ParseUint(matches[5], 10, 64)
    82  
    83  	// create the identity
    84  	iy := Identity{
    85  		NodeID:  nodeID,
    86  		Address: address,
    87  		Role:    role,
    88  		Weight:  weight,
    89  	}
    90  
    91  	return &iy, nil
    92  }
    93  
    94  // String returns a string representation of the identity.
    95  func (iy Identity) String() string {
    96  	return fmt.Sprintf("%s-%s@%s=%d", iy.Role, iy.NodeID.String(), iy.Address, iy.Weight)
    97  }
    98  
    99  // ID returns a unique identifier for the identity.
   100  func (iy Identity) ID() Identifier {
   101  	return iy.NodeID
   102  }
   103  
   104  // Checksum returns a checksum for the identity including mutable attributes.
   105  func (iy Identity) Checksum() Identifier {
   106  	return MakeID(iy)
   107  }
   108  
   109  type encodableIdentity struct {
   110  	NodeID        Identifier
   111  	Address       string `json:",omitempty"`
   112  	Role          Role
   113  	Weight        uint64
   114  	StakingPubKey []byte
   115  	NetworkPubKey []byte
   116  }
   117  
   118  // decodableIdentity provides backward-compatible decoding of old models
   119  // which use the Stake field in place of Weight.
   120  type decodableIdentity struct {
   121  	encodableIdentity
   122  	// Stake previously was used in place of the Weight field.
   123  	// Deprecated: supported in decoding for backward-compatibility
   124  	Stake uint64
   125  }
   126  
   127  func encodableFromIdentity(iy Identity) (encodableIdentity, error) {
   128  	ie := encodableIdentity{iy.NodeID, iy.Address, iy.Role, iy.Weight, nil, nil}
   129  	if iy.StakingPubKey != nil {
   130  		ie.StakingPubKey = iy.StakingPubKey.Encode()
   131  	}
   132  	if iy.NetworkPubKey != nil {
   133  		ie.NetworkPubKey = iy.NetworkPubKey.Encode()
   134  	}
   135  	return ie, nil
   136  }
   137  
   138  func (iy Identity) MarshalJSON() ([]byte, error) {
   139  	encodable, err := encodableFromIdentity(iy)
   140  	if err != nil {
   141  		return nil, fmt.Errorf("could not convert identity to encodable: %w", err)
   142  	}
   143  
   144  	data, err := json.Marshal(encodable)
   145  	if err != nil {
   146  		return nil, fmt.Errorf("could not encode json: %w", err)
   147  	}
   148  	return data, nil
   149  }
   150  
   151  func (iy Identity) MarshalCBOR() ([]byte, error) {
   152  	encodable, err := encodableFromIdentity(iy)
   153  	if err != nil {
   154  		return nil, fmt.Errorf("could not convert identity to encodable: %w", err)
   155  	}
   156  	data, err := cbor.Marshal(encodable)
   157  	if err != nil {
   158  		return nil, fmt.Errorf("could not encode cbor: %w", err)
   159  	}
   160  	return data, nil
   161  }
   162  
   163  func (iy Identity) MarshalMsgpack() ([]byte, error) {
   164  	encodable, err := encodableFromIdentity(iy)
   165  	if err != nil {
   166  		return nil, fmt.Errorf("could not convert to encodable: %w", err)
   167  	}
   168  	data, err := msgpack.Marshal(encodable)
   169  	if err != nil {
   170  		return nil, fmt.Errorf("could not encode msgpack: %w", err)
   171  	}
   172  	return data, nil
   173  }
   174  
   175  func (iy Identity) EncodeRLP(w io.Writer) error {
   176  	encodable, err := encodableFromIdentity(iy)
   177  	if err != nil {
   178  		return fmt.Errorf("could not convert to encodable: %w", err)
   179  	}
   180  	err = rlp.Encode(w, encodable)
   181  	if err != nil {
   182  		return fmt.Errorf("could not encode rlp: %w", err)
   183  	}
   184  	return nil
   185  }
   186  
   187  func identityFromEncodable(ie encodableIdentity, identity *Identity) error {
   188  	identity.NodeID = ie.NodeID
   189  	identity.Address = ie.Address
   190  	identity.Role = ie.Role
   191  	identity.Weight = ie.Weight
   192  	var err error
   193  	if ie.StakingPubKey != nil {
   194  		if identity.StakingPubKey, err = crypto.DecodePublicKey(crypto.BLSBLS12381, ie.StakingPubKey); err != nil {
   195  			return fmt.Errorf("could not decode staking key: %w", err)
   196  		}
   197  	}
   198  	if ie.NetworkPubKey != nil {
   199  		if identity.NetworkPubKey, err = crypto.DecodePublicKey(crypto.ECDSAP256, ie.NetworkPubKey); err != nil {
   200  			return fmt.Errorf("could not decode network key: %w", err)
   201  		}
   202  	}
   203  	return nil
   204  }
   205  
   206  func (iy *Identity) UnmarshalJSON(b []byte) error {
   207  	var decodable decodableIdentity
   208  	err := json.Unmarshal(b, &decodable)
   209  	if err != nil {
   210  		return fmt.Errorf("could not decode json: %w", err)
   211  	}
   212  	// compat: translate Stake fields to Weight
   213  	if decodable.Stake != 0 {
   214  		if decodable.Weight != 0 {
   215  			return fmt.Errorf("invalid identity with both Stake and Weight fields")
   216  		}
   217  		decodable.Weight = decodable.Stake
   218  	}
   219  	err = identityFromEncodable(decodable.encodableIdentity, iy)
   220  	if err != nil {
   221  		return fmt.Errorf("could not convert from encodable json: %w", err)
   222  	}
   223  	return nil
   224  }
   225  
   226  func (iy *Identity) UnmarshalCBOR(b []byte) error {
   227  	var encodable encodableIdentity
   228  	err := cbor.Unmarshal(b, &encodable)
   229  	if err != nil {
   230  		return fmt.Errorf("could not decode json: %w", err)
   231  	}
   232  	err = identityFromEncodable(encodable, iy)
   233  	if err != nil {
   234  		return fmt.Errorf("could not convert from encodable cbor: %w", err)
   235  	}
   236  	return nil
   237  }
   238  
   239  func (iy *Identity) UnmarshalMsgpack(b []byte) error {
   240  	var encodable encodableIdentity
   241  	err := msgpack.Unmarshal(b, &encodable)
   242  	if err != nil {
   243  		return fmt.Errorf("could not decode json: %w", err)
   244  	}
   245  	err = identityFromEncodable(encodable, iy)
   246  	if err != nil {
   247  		return fmt.Errorf("could not convert from encodable msgpack: %w", err)
   248  	}
   249  	return nil
   250  }
   251  
   252  func (iy *Identity) EqualTo(other *Identity) bool {
   253  	if iy.NodeID != other.NodeID {
   254  		return false
   255  	}
   256  	if iy.Address != other.Address {
   257  		return false
   258  	}
   259  	if iy.Role != other.Role {
   260  		return false
   261  	}
   262  	if iy.Weight != other.Weight {
   263  		return false
   264  	}
   265  	if iy.Ejected != other.Ejected {
   266  		return false
   267  	}
   268  	if (iy.StakingPubKey != nil && other.StakingPubKey == nil) ||
   269  		(iy.StakingPubKey == nil && other.StakingPubKey != nil) {
   270  		return false
   271  	}
   272  	if iy.StakingPubKey != nil && !iy.StakingPubKey.Equals(other.StakingPubKey) {
   273  		return false
   274  	}
   275  
   276  	if (iy.NetworkPubKey != nil && other.NetworkPubKey == nil) ||
   277  		(iy.NetworkPubKey == nil && other.NetworkPubKey != nil) {
   278  		return false
   279  	}
   280  	if iy.NetworkPubKey != nil && !iy.NetworkPubKey.Equals(other.NetworkPubKey) {
   281  		return false
   282  	}
   283  
   284  	return true
   285  }
   286  
   287  // IdentityFilter is a filter on identities.
   288  type IdentityFilter func(*Identity) bool
   289  
   290  // IdentityOrder is a sort for identities.
   291  type IdentityOrder func(*Identity, *Identity) bool
   292  
   293  // IdentityMapFunc is a modifier function for map operations for identities.
   294  // Identities are COPIED from the source slice.
   295  type IdentityMapFunc func(Identity) Identity
   296  
   297  // IdentityList is a list of nodes.
   298  type IdentityList []*Identity
   299  
   300  // Filter will apply a filter to the identity list.
   301  func (il IdentityList) Filter(filter IdentityFilter) IdentityList {
   302  	var dup IdentityList
   303  IDLoop:
   304  	for _, identity := range il {
   305  		if !filter(identity) {
   306  			continue IDLoop
   307  		}
   308  		dup = append(dup, identity)
   309  	}
   310  	return dup
   311  }
   312  
   313  // Map returns a new identity list with the map function f applied to a copy of
   314  // each identity.
   315  //
   316  // CAUTION: this relies on structure copy semantics. Map functions that modify
   317  // an object referenced by the input Identity structure will modify identities
   318  // in the source slice as well.
   319  func (il IdentityList) Map(f IdentityMapFunc) IdentityList {
   320  	dup := make(IdentityList, 0, len(il))
   321  	for _, identity := range il {
   322  		next := f(*identity)
   323  		dup = append(dup, &next)
   324  	}
   325  	return dup
   326  }
   327  
   328  // Copy returns a copy of the receiver. The resulting slice uses a different
   329  // backing array, meaning appends and insert operations on either slice are
   330  // guaranteed to only affect that slice.
   331  //
   332  // Copy should be used when modifying an existing identity list by either
   333  // appending new elements, re-ordering, or inserting new elements in an
   334  // existing index.
   335  func (il IdentityList) Copy() IdentityList {
   336  	dup := make(IdentityList, 0, len(il))
   337  
   338  	lenList := len(il)
   339  
   340  	// performance tests show this is faster than 'range'
   341  	for i := 0; i < lenList; i++ {
   342  		// copy the object
   343  		next := *(il[i])
   344  		dup = append(dup, &next)
   345  	}
   346  	return dup
   347  }
   348  
   349  // Selector returns an identity filter function that selects only identities
   350  // within this identity list.
   351  func (il IdentityList) Selector() IdentityFilter {
   352  
   353  	lookup := il.Lookup()
   354  	return func(identity *Identity) bool {
   355  		_, exists := lookup[identity.NodeID]
   356  		return exists
   357  	}
   358  }
   359  
   360  func (il IdentityList) Lookup() map[Identifier]*Identity {
   361  	lookup := make(map[Identifier]*Identity, len(il))
   362  	for _, identity := range il {
   363  		lookup[identity.NodeID] = identity
   364  	}
   365  	return lookup
   366  }
   367  
   368  // Sort will sort the list using the given ordering.  This is
   369  // not recommended for performance.  Expand the 'less' function
   370  // in place for best performance, and don't use this function.
   371  func (il IdentityList) Sort(less IdentityOrder) IdentityList {
   372  	dup := il.Copy()
   373  	slices.SortFunc(dup, less)
   374  	return dup
   375  }
   376  
   377  // Sorted returns whether the list is sorted by the input ordering.
   378  func (il IdentityList) Sorted(less IdentityOrder) bool {
   379  	return slices.IsSortedFunc(il, less)
   380  }
   381  
   382  // NodeIDs returns the NodeIDs of the nodes in the list.
   383  func (il IdentityList) NodeIDs() IdentifierList {
   384  	nodeIDs := make([]Identifier, 0, len(il))
   385  	for _, id := range il {
   386  		nodeIDs = append(nodeIDs, id.NodeID)
   387  	}
   388  	return nodeIDs
   389  }
   390  
   391  // PublicStakingKeys returns a list with the public staking keys (order preserving).
   392  func (il IdentityList) PublicStakingKeys() []crypto.PublicKey {
   393  	pks := make([]crypto.PublicKey, 0, len(il))
   394  	for _, id := range il {
   395  		pks = append(pks, id.StakingPubKey)
   396  	}
   397  	return pks
   398  }
   399  
   400  func (il IdentityList) Fingerprint() Identifier {
   401  	return MerkleRoot(GetIDs(il)...)
   402  }
   403  
   404  // TotalWeight returns the total weight of all given identities.
   405  func (il IdentityList) TotalWeight() uint64 {
   406  	var total uint64
   407  	for _, identity := range il {
   408  		total += identity.Weight
   409  	}
   410  	return total
   411  }
   412  
   413  // Count returns the count of identities.
   414  func (il IdentityList) Count() uint {
   415  	return uint(len(il))
   416  }
   417  
   418  // ByIndex returns the node at the given index.
   419  func (il IdentityList) ByIndex(index uint) (*Identity, bool) {
   420  	if index >= uint(len(il)) {
   421  		return nil, false
   422  	}
   423  	return il[int(index)], true
   424  }
   425  
   426  // ByNodeID gets a node from the list by node ID.
   427  func (il IdentityList) ByNodeID(nodeID Identifier) (*Identity, bool) {
   428  	for _, identity := range il {
   429  		if identity.NodeID == nodeID {
   430  			return identity, true
   431  		}
   432  	}
   433  	return nil, false
   434  }
   435  
   436  // ByNetworkingKey gets a node from the list by network public key.
   437  func (il IdentityList) ByNetworkingKey(key crypto.PublicKey) (*Identity, bool) {
   438  	for _, identity := range il {
   439  		if identity.NetworkPubKey.Equals(key) {
   440  			return identity, true
   441  		}
   442  	}
   443  	return nil, false
   444  }
   445  
   446  // Sample returns simple random sample from the `IdentityList`
   447  func (il IdentityList) Sample(size uint) IdentityList {
   448  	return il.sample(size, rand.Intn)
   449  }
   450  
   451  // DeterministicSample returns deterministic random sample from the `IdentityList` using the given seed
   452  func (il IdentityList) DeterministicSample(size uint, seed int64) IdentityList {
   453  	rng := rand.New(rand.NewSource(seed))
   454  	return il.sample(size, rng.Intn)
   455  }
   456  
   457  func (il IdentityList) sample(size uint, intn func(int) int) IdentityList {
   458  	n := uint(len(il))
   459  	if size > n {
   460  		size = n
   461  	}
   462  
   463  	dup := il.Copy()
   464  	for i := uint(0); i < size; i++ {
   465  		j := uint(intn(int(n - i)))
   466  		dup[i], dup[j+i] = dup[j+i], dup[i]
   467  	}
   468  	return dup[:size]
   469  }
   470  
   471  // DeterministicShuffle randomly and deterministically shuffles the identity
   472  // list, returning the shuffled list without modifying the receiver.
   473  func (il IdentityList) DeterministicShuffle(seed int64) IdentityList {
   474  	dup := il.Copy()
   475  	rng := rand.New(rand.NewSource(seed))
   476  	rng.Shuffle(len(il), func(i, j int) {
   477  		dup[i], dup[j] = dup[j], dup[i]
   478  	})
   479  	return dup
   480  }
   481  
   482  // SamplePct returns a random sample from the receiver identity list. The
   483  // sample contains `pct` percentage of the list. The sample is rounded up
   484  // if `pct>0`, so this will always select at least one identity.
   485  //
   486  // NOTE: The input must be between 0-1.
   487  func (il IdentityList) SamplePct(pct float64) IdentityList {
   488  	if pct <= 0 {
   489  		return IdentityList{}
   490  	}
   491  
   492  	count := float64(il.Count()) * pct
   493  	size := uint(math.Round(count))
   494  	// ensure we always select at least 1, for non-zero input
   495  	if size == 0 {
   496  		size = 1
   497  	}
   498  
   499  	return il.Sample(size)
   500  }
   501  
   502  // Union returns a new identity list containing every identity that occurs in
   503  // either `il`, or `other`, or both. There are no duplicates in the output,
   504  // where duplicates are identities with the same node ID.
   505  // The returned IdentityList is sorted
   506  func (il IdentityList) Union(other IdentityList) IdentityList {
   507  	maxLen := len(il) + len(other)
   508  
   509  	union := make(IdentityList, 0, maxLen)
   510  	set := make(map[Identifier]struct{}, maxLen)
   511  
   512  	for _, list := range []IdentityList{il, other} {
   513  		for _, id := range list {
   514  			if _, isDuplicate := set[id.NodeID]; !isDuplicate {
   515  				set[id.NodeID] = struct{}{}
   516  				union = append(union, id)
   517  			}
   518  		}
   519  	}
   520  
   521  	slices.SortFunc(union, func(a, b *Identity) bool {
   522  		return bytes.Compare(a.NodeID[:], b.NodeID[:]) < 0
   523  	})
   524  
   525  	return union
   526  }
   527  
   528  // EqualTo checks if the other list if the same, that it contains the same elements
   529  // in the same order
   530  func (il IdentityList) EqualTo(other IdentityList) bool {
   531  	return slices.EqualFunc(il, other, func(a, b *Identity) bool {
   532  		return a.EqualTo(b)
   533  	})
   534  }
   535  
   536  // Exists takes a previously sorted Identity list and searches it for the target value
   537  // This code is optimized, so the coding style will be different
   538  // target:  value to search for
   539  // CAUTION:  The identity list MUST be sorted prior to calling this method
   540  func (il IdentityList) Exists(target *Identity) bool {
   541  	return il.IdentifierExists(target.NodeID)
   542  }
   543  
   544  // IdentifierExists takes a previously sorted Identity list and searches it for the target value
   545  // target:  value to search for
   546  // CAUTION:  The identity list MUST be sorted prior to calling this method
   547  func (il IdentityList) IdentifierExists(target Identifier) bool {
   548  	_, ok := slices.BinarySearchFunc(il, &Identity{NodeID: target}, func(a, b *Identity) int {
   549  		return bytes.Compare(a.NodeID[:], b.NodeID[:])
   550  	})
   551  	return ok
   552  }
   553  
   554  // GetIndex returns the index of the identifier in the IdentityList and true
   555  // if the identifier is found.
   556  func (il IdentityList) GetIndex(target Identifier) (uint, bool) {
   557  	i := slices.IndexFunc(il, func(a *Identity) bool {
   558  		return a.NodeID == target
   559  	})
   560  	if i == -1 {
   561  		return 0, false
   562  	}
   563  	return uint(i), true
   564  }