github.com/ImPedro29/bor@v0.2.7/consensus/bor/validator_set.go (about) 1 package bor 2 3 // Tendermint leader selection algorithm 4 5 import ( 6 "bytes" 7 "fmt" 8 "math" 9 "math/big" 10 "sort" 11 "strings" 12 13 "github.com/ethereum/go-ethereum/common" 14 "github.com/ethereum/go-ethereum/log" 15 ) 16 17 // MaxTotalVotingPower - the maximum allowed total voting power. 18 // It needs to be sufficiently small to, in all cases: 19 // 1. prevent clipping in incrementProposerPriority() 20 // 2. let (diff+diffMax-1) not overflow in IncrementProposerPriority() 21 // (Proof of 1 is tricky, left to the reader). 22 // It could be higher, but this is sufficiently large for our purposes, 23 // and leaves room for defensive purposes. 24 // PriorityWindowSizeFactor - is a constant that when multiplied with the total voting power gives 25 // the maximum allowed distance between validator priorities. 26 27 const ( 28 MaxTotalVotingPower = int64(math.MaxInt64) / 8 29 PriorityWindowSizeFactor = 2 30 ) 31 32 // ValidatorSet represent a set of *Validator at a given height. 33 // The validators can be fetched by address or index. 34 // The index is in order of .Address, so the indices are fixed 35 // for all rounds of a given blockchain height - ie. the validators 36 // are sorted by their address. 37 // On the other hand, the .ProposerPriority of each validator and 38 // the designated .GetProposer() of a set changes every round, 39 // upon calling .IncrementProposerPriority(). 40 // NOTE: Not goroutine-safe. 41 // NOTE: All get/set to validators should copy the value for safety. 42 type ValidatorSet struct { 43 // NOTE: persisted via reflect, must be exported. 44 Validators []*Validator `json:"validators"` 45 Proposer *Validator `json:"proposer"` 46 47 // cached (unexported) 48 totalVotingPower int64 49 } 50 51 // NewValidatorSet initializes a ValidatorSet by copying over the 52 // values from `valz`, a list of Validators. If valz is nil or empty, 53 // the new ValidatorSet will have an empty list of Validators. 54 // The addresses of validators in `valz` must be unique otherwise the 55 // function panics. 56 func NewValidatorSet(valz []*Validator) *ValidatorSet { 57 vals := &ValidatorSet{} 58 err := vals.updateWithChangeSet(valz, false) 59 if err != nil { 60 panic(fmt.Sprintf("cannot create validator set: %s", err)) 61 } 62 if len(valz) > 0 { 63 vals.IncrementProposerPriority(1) 64 } 65 return vals 66 } 67 68 // Nil or empty validator sets are invalid. 69 func (vals *ValidatorSet) IsNilOrEmpty() bool { 70 return vals == nil || len(vals.Validators) == 0 71 } 72 73 // Increment ProposerPriority and update the proposer on a copy, and return it. 74 func (vals *ValidatorSet) CopyIncrementProposerPriority(times int) *ValidatorSet { 75 copy := vals.Copy() 76 copy.IncrementProposerPriority(times) 77 return copy 78 } 79 80 // IncrementProposerPriority increments ProposerPriority of each validator and updates the 81 // proposer. Panics if validator set is empty. 82 // `times` must be positive. 83 func (vals *ValidatorSet) IncrementProposerPriority(times int) { 84 if vals.IsNilOrEmpty() { 85 panic("empty validator set") 86 } 87 if times <= 0 { 88 panic("Cannot call IncrementProposerPriority with non-positive times") 89 } 90 91 // Cap the difference between priorities to be proportional to 2*totalPower by 92 // re-normalizing priorities, i.e., rescale all priorities by multiplying with: 93 // 2*totalVotingPower/(maxPriority - minPriority) 94 diffMax := PriorityWindowSizeFactor * vals.TotalVotingPower() 95 vals.RescalePriorities(diffMax) 96 vals.shiftByAvgProposerPriority() 97 98 var proposer *Validator 99 // Call IncrementProposerPriority(1) times times. 100 for i := 0; i < times; i++ { 101 proposer = vals.incrementProposerPriority() 102 } 103 104 vals.Proposer = proposer 105 } 106 107 func (vals *ValidatorSet) RescalePriorities(diffMax int64) { 108 if vals.IsNilOrEmpty() { 109 panic("empty validator set") 110 } 111 // NOTE: This check is merely a sanity check which could be 112 // removed if all tests would init. voting power appropriately; 113 // i.e. diffMax should always be > 0 114 if diffMax <= 0 { 115 return 116 } 117 118 // Calculating ceil(diff/diffMax): 119 // Re-normalization is performed by dividing by an integer for simplicity. 120 // NOTE: This may make debugging priority issues easier as well. 121 diff := computeMaxMinPriorityDiff(vals) 122 ratio := (diff + diffMax - 1) / diffMax 123 if diff > diffMax { 124 for _, val := range vals.Validators { 125 val.ProposerPriority = val.ProposerPriority / ratio 126 } 127 } 128 } 129 130 func (vals *ValidatorSet) incrementProposerPriority() *Validator { 131 for _, val := range vals.Validators { 132 // Check for overflow for sum. 133 newPrio := safeAddClip(val.ProposerPriority, val.VotingPower) 134 val.ProposerPriority = newPrio 135 } 136 // Decrement the validator with most ProposerPriority. 137 mostest := vals.getValWithMostPriority() 138 // Mind the underflow. 139 mostest.ProposerPriority = safeSubClip(mostest.ProposerPriority, vals.TotalVotingPower()) 140 141 return mostest 142 } 143 144 // Should not be called on an empty validator set. 145 func (vals *ValidatorSet) computeAvgProposerPriority() int64 { 146 n := int64(len(vals.Validators)) 147 sum := big.NewInt(0) 148 for _, val := range vals.Validators { 149 sum.Add(sum, big.NewInt(val.ProposerPriority)) 150 } 151 avg := sum.Div(sum, big.NewInt(n)) 152 if avg.IsInt64() { 153 return avg.Int64() 154 } 155 156 // This should never happen: each val.ProposerPriority is in bounds of int64. 157 panic(fmt.Sprintf("Cannot represent avg ProposerPriority as an int64 %v", avg)) 158 } 159 160 // Compute the difference between the max and min ProposerPriority of that set. 161 func computeMaxMinPriorityDiff(vals *ValidatorSet) int64 { 162 if vals.IsNilOrEmpty() { 163 panic("empty validator set") 164 } 165 max := int64(math.MinInt64) 166 min := int64(math.MaxInt64) 167 for _, v := range vals.Validators { 168 if v.ProposerPriority < min { 169 min = v.ProposerPriority 170 } 171 if v.ProposerPriority > max { 172 max = v.ProposerPriority 173 } 174 } 175 diff := max - min 176 if diff < 0 { 177 return -1 * diff 178 } else { 179 return diff 180 } 181 } 182 183 func (vals *ValidatorSet) getValWithMostPriority() *Validator { 184 var res *Validator 185 for _, val := range vals.Validators { 186 res = res.Cmp(val) 187 } 188 return res 189 } 190 191 func (vals *ValidatorSet) shiftByAvgProposerPriority() { 192 if vals.IsNilOrEmpty() { 193 panic("empty validator set") 194 } 195 avgProposerPriority := vals.computeAvgProposerPriority() 196 for _, val := range vals.Validators { 197 val.ProposerPriority = safeSubClip(val.ProposerPriority, avgProposerPriority) 198 } 199 } 200 201 // Makes a copy of the validator list. 202 func validatorListCopy(valsList []*Validator) []*Validator { 203 if valsList == nil { 204 return nil 205 } 206 valsCopy := make([]*Validator, len(valsList)) 207 for i, val := range valsList { 208 valsCopy[i] = val.Copy() 209 } 210 return valsCopy 211 } 212 213 // Copy each validator into a new ValidatorSet. 214 func (vals *ValidatorSet) Copy() *ValidatorSet { 215 return &ValidatorSet{ 216 Validators: validatorListCopy(vals.Validators), 217 Proposer: vals.Proposer, 218 totalVotingPower: vals.totalVotingPower, 219 } 220 } 221 222 // HasAddress returns true if address given is in the validator set, false - 223 // otherwise. 224 func (vals *ValidatorSet) HasAddress(address []byte) bool { 225 idx := sort.Search(len(vals.Validators), func(i int) bool { 226 return bytes.Compare(address, vals.Validators[i].Address.Bytes()) <= 0 227 }) 228 return idx < len(vals.Validators) && bytes.Equal(vals.Validators[idx].Address.Bytes(), address) 229 } 230 231 // GetByAddress returns an index of the validator with address and validator 232 // itself if found. Otherwise, -1 and nil are returned. 233 func (vals *ValidatorSet) GetByAddress(address common.Address) (index int, val *Validator) { 234 idx := sort.Search(len(vals.Validators), func(i int) bool { 235 return bytes.Compare(address.Bytes(), vals.Validators[i].Address.Bytes()) <= 0 236 }) 237 if idx < len(vals.Validators) && bytes.Equal(vals.Validators[idx].Address.Bytes(), address.Bytes()) { 238 return idx, vals.Validators[idx].Copy() 239 } 240 return -1, nil 241 } 242 243 // GetByIndex returns the validator's address and validator itself by index. 244 // It returns nil values if index is less than 0 or greater or equal to 245 // len(ValidatorSet.Validators). 246 func (vals *ValidatorSet) GetByIndex(index int) (address []byte, val *Validator) { 247 if index < 0 || index >= len(vals.Validators) { 248 return nil, nil 249 } 250 val = vals.Validators[index] 251 return val.Address.Bytes(), val.Copy() 252 } 253 254 // Size returns the length of the validator set. 255 func (vals *ValidatorSet) Size() int { 256 return len(vals.Validators) 257 } 258 259 // Force recalculation of the set's total voting power. 260 func (vals *ValidatorSet) updateTotalVotingPower() error { 261 262 sum := int64(0) 263 for _, val := range vals.Validators { 264 // mind overflow 265 sum = safeAddClip(sum, val.VotingPower) 266 if sum > MaxTotalVotingPower { 267 return &TotalVotingPowerExceededError{sum, vals.Validators} 268 } 269 } 270 vals.totalVotingPower = sum 271 return nil 272 } 273 274 // TotalVotingPower returns the sum of the voting powers of all validators. 275 // It recomputes the total voting power if required. 276 func (vals *ValidatorSet) TotalVotingPower() int64 { 277 if vals.totalVotingPower == 0 { 278 log.Info("invoking updateTotalVotingPower before returning it") 279 if err := vals.updateTotalVotingPower(); err != nil { 280 // Can/should we do better? 281 panic(err) 282 } 283 } 284 return vals.totalVotingPower 285 } 286 287 // GetProposer returns the current proposer. If the validator set is empty, nil 288 // is returned. 289 func (vals *ValidatorSet) GetProposer() (proposer *Validator) { 290 if len(vals.Validators) == 0 { 291 return nil 292 } 293 if vals.Proposer == nil { 294 vals.Proposer = vals.findProposer() 295 } 296 return vals.Proposer.Copy() 297 } 298 299 func (vals *ValidatorSet) findProposer() *Validator { 300 var proposer *Validator 301 for _, val := range vals.Validators { 302 if proposer == nil || !bytes.Equal(val.Address.Bytes(), proposer.Address.Bytes()) { 303 proposer = proposer.Cmp(val) 304 } 305 } 306 return proposer 307 } 308 309 // Hash returns the Merkle root hash build using validators (as leaves) in the 310 // set. 311 // func (vals *ValidatorSet) Hash() []byte { 312 // if len(vals.Validators) == 0 { 313 // return nil 314 // } 315 // bzs := make([][]byte, len(vals.Validators)) 316 // for i, val := range vals.Validators { 317 // bzs[i] = val.Bytes() 318 // } 319 // return merkle.SimpleHashFromByteSlices(bzs) 320 // } 321 322 // Iterate will run the given function over the set. 323 func (vals *ValidatorSet) Iterate(fn func(index int, val *Validator) bool) { 324 for i, val := range vals.Validators { 325 stop := fn(i, val.Copy()) 326 if stop { 327 break 328 } 329 } 330 } 331 332 // Checks changes against duplicates, splits the changes in updates and removals, sorts them by address. 333 // 334 // Returns: 335 // updates, removals - the sorted lists of updates and removals 336 // err - non-nil if duplicate entries or entries with negative voting power are seen 337 // 338 // No changes are made to 'origChanges'. 339 func processChanges(origChanges []*Validator) (updates, removals []*Validator, err error) { 340 // Make a deep copy of the changes and sort by address. 341 changes := validatorListCopy(origChanges) 342 sort.Sort(ValidatorsByAddress(changes)) 343 344 removals = make([]*Validator, 0, len(changes)) 345 updates = make([]*Validator, 0, len(changes)) 346 var prevAddr common.Address 347 348 // Scan changes by address and append valid validators to updates or removals lists. 349 for _, valUpdate := range changes { 350 if bytes.Equal(valUpdate.Address.Bytes(), prevAddr.Bytes()) { 351 err = fmt.Errorf("duplicate entry %v in %v", valUpdate, changes) 352 return nil, nil, err 353 } 354 if valUpdate.VotingPower < 0 { 355 err = fmt.Errorf("voting power can't be negative: %v", valUpdate) 356 return nil, nil, err 357 } 358 if valUpdate.VotingPower > MaxTotalVotingPower { 359 err = fmt.Errorf("to prevent clipping/ overflow, voting power can't be higher than %v: %v ", 360 MaxTotalVotingPower, valUpdate) 361 return nil, nil, err 362 } 363 if valUpdate.VotingPower == 0 { 364 removals = append(removals, valUpdate) 365 } else { 366 updates = append(updates, valUpdate) 367 } 368 prevAddr = valUpdate.Address 369 } 370 return updates, removals, err 371 } 372 373 // Verifies a list of updates against a validator set, making sure the allowed 374 // total voting power would not be exceeded if these updates would be applied to the set. 375 // 376 // Returns: 377 // updatedTotalVotingPower - the new total voting power if these updates would be applied 378 // numNewValidators - number of new validators 379 // err - non-nil if the maximum allowed total voting power would be exceeded 380 // 381 // 'updates' should be a list of proper validator changes, i.e. they have been verified 382 // by processChanges for duplicates and invalid values. 383 // No changes are made to the validator set 'vals'. 384 func verifyUpdates(updates []*Validator, vals *ValidatorSet) (updatedTotalVotingPower int64, numNewValidators int, err error) { 385 386 updatedTotalVotingPower = vals.TotalVotingPower() 387 388 for _, valUpdate := range updates { 389 address := valUpdate.Address 390 _, val := vals.GetByAddress(address) 391 if val == nil { 392 // New validator, add its voting power the the total. 393 updatedTotalVotingPower += valUpdate.VotingPower 394 numNewValidators++ 395 } else { 396 // Updated validator, add the difference in power to the total. 397 updatedTotalVotingPower += valUpdate.VotingPower - val.VotingPower 398 } 399 overflow := updatedTotalVotingPower > MaxTotalVotingPower 400 if overflow { 401 err = fmt.Errorf( 402 "failed to add/update validator %v, total voting power would exceed the max allowed %v", 403 valUpdate, MaxTotalVotingPower) 404 return 0, 0, err 405 } 406 } 407 408 return updatedTotalVotingPower, numNewValidators, nil 409 } 410 411 // Computes the proposer priority for the validators not present in the set based on 'updatedTotalVotingPower'. 412 // Leaves unchanged the priorities of validators that are changed. 413 // 414 // 'updates' parameter must be a list of unique validators to be added or updated. 415 // No changes are made to the validator set 'vals'. 416 func computeNewPriorities(updates []*Validator, vals *ValidatorSet, updatedTotalVotingPower int64) { 417 418 for _, valUpdate := range updates { 419 address := valUpdate.Address 420 _, val := vals.GetByAddress(address) 421 if val == nil { 422 // add val 423 // Set ProposerPriority to -C*totalVotingPower (with C ~= 1.125) to make sure validators can't 424 // un-bond and then re-bond to reset their (potentially previously negative) ProposerPriority to zero. 425 // 426 // Contract: updatedVotingPower < MaxTotalVotingPower to ensure ProposerPriority does 427 // not exceed the bounds of int64. 428 // 429 // Compute ProposerPriority = -1.125*totalVotingPower == -(updatedVotingPower + (updatedVotingPower >> 3)). 430 valUpdate.ProposerPriority = -(updatedTotalVotingPower + (updatedTotalVotingPower >> 3)) 431 } else { 432 valUpdate.ProposerPriority = val.ProposerPriority 433 } 434 } 435 436 } 437 438 // Merges the vals' validator list with the updates list. 439 // When two elements with same address are seen, the one from updates is selected. 440 // Expects updates to be a list of updates sorted by address with no duplicates or errors, 441 // must have been validated with verifyUpdates() and priorities computed with computeNewPriorities(). 442 func (vals *ValidatorSet) applyUpdates(updates []*Validator) { 443 444 existing := vals.Validators 445 merged := make([]*Validator, len(existing)+len(updates)) 446 i := 0 447 448 for len(existing) > 0 && len(updates) > 0 { 449 if bytes.Compare(existing[0].Address.Bytes(), updates[0].Address.Bytes()) < 0 { // unchanged validator 450 merged[i] = existing[0] 451 existing = existing[1:] 452 } else { 453 // Apply add or update. 454 merged[i] = updates[0] 455 if bytes.Equal(existing[0].Address.Bytes(), updates[0].Address.Bytes()) { 456 // Validator is present in both, advance existing. 457 existing = existing[1:] 458 } 459 updates = updates[1:] 460 } 461 i++ 462 } 463 464 // Add the elements which are left. 465 for j := 0; j < len(existing); j++ { 466 merged[i] = existing[j] 467 i++ 468 } 469 // OR add updates which are left. 470 for j := 0; j < len(updates); j++ { 471 merged[i] = updates[j] 472 i++ 473 } 474 475 vals.Validators = merged[:i] 476 } 477 478 // Checks that the validators to be removed are part of the validator set. 479 // No changes are made to the validator set 'vals'. 480 func verifyRemovals(deletes []*Validator, vals *ValidatorSet) error { 481 482 for _, valUpdate := range deletes { 483 address := valUpdate.Address 484 _, val := vals.GetByAddress(address) 485 if val == nil { 486 return fmt.Errorf("failed to find validator %X to remove", address) 487 } 488 } 489 if len(deletes) > len(vals.Validators) { 490 panic("more deletes than validators") 491 } 492 return nil 493 } 494 495 // Removes the validators specified in 'deletes' from validator set 'vals'. 496 // Should not fail as verification has been done before. 497 func (vals *ValidatorSet) applyRemovals(deletes []*Validator) { 498 499 existing := vals.Validators 500 501 merged := make([]*Validator, len(existing)-len(deletes)) 502 i := 0 503 504 // Loop over deletes until we removed all of them. 505 for len(deletes) > 0 { 506 if bytes.Equal(existing[0].Address.Bytes(), deletes[0].Address.Bytes()) { 507 deletes = deletes[1:] 508 } else { // Leave it in the resulting slice. 509 merged[i] = existing[0] 510 i++ 511 } 512 existing = existing[1:] 513 } 514 515 // Add the elements which are left. 516 for j := 0; j < len(existing); j++ { 517 merged[i] = existing[j] 518 i++ 519 } 520 521 vals.Validators = merged[:i] 522 } 523 524 // Main function used by UpdateWithChangeSet() and NewValidatorSet(). 525 // If 'allowDeletes' is false then delete operations (identified by validators with voting power 0) 526 // are not allowed and will trigger an error if present in 'changes'. 527 // The 'allowDeletes' flag is set to false by NewValidatorSet() and to true by UpdateWithChangeSet(). 528 func (vals *ValidatorSet) updateWithChangeSet(changes []*Validator, allowDeletes bool) error { 529 530 if len(changes) <= 0 { 531 return nil 532 } 533 534 // Check for duplicates within changes, split in 'updates' and 'deletes' lists (sorted). 535 updates, deletes, err := processChanges(changes) 536 if err != nil { 537 return err 538 } 539 540 if !allowDeletes && len(deletes) != 0 { 541 return fmt.Errorf("cannot process validators with voting power 0: %v", deletes) 542 } 543 544 // Verify that applying the 'deletes' against 'vals' will not result in error. 545 if err := verifyRemovals(deletes, vals); err != nil { 546 return err 547 } 548 549 // Verify that applying the 'updates' against 'vals' will not result in error. 550 updatedTotalVotingPower, numNewValidators, err := verifyUpdates(updates, vals) 551 if err != nil { 552 return err 553 } 554 555 // Check that the resulting set will not be empty. 556 if numNewValidators == 0 && len(vals.Validators) == len(deletes) { 557 return fmt.Errorf("applying the validator changes would result in empty set") 558 } 559 560 // Compute the priorities for updates. 561 computeNewPriorities(updates, vals, updatedTotalVotingPower) 562 563 // Apply updates and removals. 564 vals.applyUpdates(updates) 565 vals.applyRemovals(deletes) 566 567 if err := vals.updateTotalVotingPower(); err != nil { 568 return err 569 } 570 571 // Scale and center. 572 vals.RescalePriorities(PriorityWindowSizeFactor * vals.TotalVotingPower()) 573 vals.shiftByAvgProposerPriority() 574 575 return nil 576 } 577 578 // UpdateWithChangeSet attempts to update the validator set with 'changes'. 579 // It performs the following steps: 580 // - validates the changes making sure there are no duplicates and splits them in updates and deletes 581 // - verifies that applying the changes will not result in errors 582 // - computes the total voting power BEFORE removals to ensure that in the next steps the priorities 583 // across old and newly added validators are fair 584 // - computes the priorities of new validators against the final set 585 // - applies the updates against the validator set 586 // - applies the removals against the validator set 587 // - performs scaling and centering of priority values 588 // If an error is detected during verification steps, it is returned and the validator set 589 // is not changed. 590 func (vals *ValidatorSet) UpdateWithChangeSet(changes []*Validator) error { 591 return vals.updateWithChangeSet(changes, true) 592 } 593 594 //----------------- 595 // ErrTooMuchChange 596 597 func IsErrTooMuchChange(err error) bool { 598 switch err.(type) { 599 case errTooMuchChange: 600 return true 601 default: 602 return false 603 } 604 } 605 606 type errTooMuchChange struct { 607 got int64 608 needed int64 609 } 610 611 func (e errTooMuchChange) Error() string { 612 return fmt.Sprintf("Invalid commit -- insufficient old voting power: got %v, needed %v", e.got, e.needed) 613 } 614 615 //---------------- 616 617 func (vals *ValidatorSet) String() string { 618 return vals.StringIndented("") 619 } 620 621 func (vals *ValidatorSet) StringIndented(indent string) string { 622 if vals == nil { 623 return "nil-ValidatorSet" 624 } 625 var valStrings []string 626 vals.Iterate(func(index int, val *Validator) bool { 627 valStrings = append(valStrings, val.String()) 628 return false 629 }) 630 return fmt.Sprintf(`ValidatorSet{ 631 %s Proposer: %v 632 %s Validators: 633 %s %v 634 %s}`, 635 indent, vals.GetProposer().String(), 636 indent, 637 indent, strings.Join(valStrings, "\n"+indent+" "), 638 indent) 639 640 } 641 642 //------------------------------------- 643 // Implements sort for sorting validators by address. 644 645 // Sort validators by address. 646 type ValidatorsByAddress []*Validator 647 648 func (valz ValidatorsByAddress) Len() int { 649 return len(valz) 650 } 651 652 func (valz ValidatorsByAddress) Less(i, j int) bool { 653 return bytes.Compare(valz[i].Address.Bytes(), valz[j].Address.Bytes()) == -1 654 } 655 656 func (valz ValidatorsByAddress) Swap(i, j int) { 657 it := valz[i] 658 valz[i] = valz[j] 659 valz[j] = it 660 } 661 662 /////////////////////////////////////////////////////////////////////////////// 663 // safe addition/subtraction 664 665 func safeAdd(a, b int64) (int64, bool) { 666 if b > 0 && a > math.MaxInt64-b { 667 return -1, true 668 } else if b < 0 && a < math.MinInt64-b { 669 return -1, true 670 } 671 return a + b, false 672 } 673 674 func safeSub(a, b int64) (int64, bool) { 675 if b > 0 && a < math.MinInt64+b { 676 return -1, true 677 } else if b < 0 && a > math.MaxInt64+b { 678 return -1, true 679 } 680 return a - b, false 681 } 682 683 func safeAddClip(a, b int64) int64 { 684 c, overflow := safeAdd(a, b) 685 if overflow { 686 if b < 0 { 687 return math.MinInt64 688 } 689 return math.MaxInt64 690 } 691 return c 692 } 693 694 func safeSubClip(a, b int64) int64 { 695 c, overflow := safeSub(a, b) 696 if overflow { 697 if b > 0 { 698 return math.MinInt64 699 } 700 return math.MaxInt64 701 } 702 return c 703 }