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