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 }