You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

629 lines
19 KiB

10 years ago
10 years ago
10 years ago
Normalize priorities to not exceed total voting power (#3049) * more proposer priority tests - test that we don't reset to zero when updating / adding - test that same power validators alternate * add another test to track / simulate similar behaviour as in #2960 * address some of Chris' review comments * address some more of Chris' review comments * temporarily pushing branch with the following changes: The total power might change if: - a validator is added - a validator is removed - a validator is updated Decrement the accums (of all validators) directly after any of these events (by the inverse of the change) * Fix 2960 by re-normalizing / scaling priorities to be in bounds of total power, additionally: - remove heap where it doesn't make sense - avg. only at the end of IncrementProposerPriority instead of each iteration - update (and slightly improve) TestAveragingInIncrementProposerPriorityWithVotingPower to reflect above changes * Fix 2960 by re-normalizing / scaling priorities to be in bounds of total power, additionally: - remove heap where it doesn't make sense - avg. only at the end of IncrementProposerPriority instead of each iteration - update (and slightly improve) TestAveragingInIncrementProposerPriorityWithVotingPower to reflect above changes * fix tests * add comment * update changelog pending & some minor changes * comment about division will floor the result & fix typo * Update TestLargeGenesisValidator: - remove TODO and increase large genesis validator's voting power accordingly * move changelog entry to P2P Protocol * Ceil instead of flooring when dividing & update test * quickly fix failing TestProposerPriorityDoesNotGetResetToZero: - divide by Ceil((maxPriority - minPriority) / 2*totalVotingPower) * fix typo: rename getValWitMostPriority -> getValWithMostPriority * test proposer frequencies * return absolute value for diff. keep testing * use for loop for div * cleanup, more tests * spellcheck * get rid of using floats: manually ceil where necessary * Remove float, simplify, fix tests to match chris's proof (#3157)
6 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
Normalize priorities to not exceed total voting power (#3049) * more proposer priority tests - test that we don't reset to zero when updating / adding - test that same power validators alternate * add another test to track / simulate similar behaviour as in #2960 * address some of Chris' review comments * address some more of Chris' review comments * temporarily pushing branch with the following changes: The total power might change if: - a validator is added - a validator is removed - a validator is updated Decrement the accums (of all validators) directly after any of these events (by the inverse of the change) * Fix 2960 by re-normalizing / scaling priorities to be in bounds of total power, additionally: - remove heap where it doesn't make sense - avg. only at the end of IncrementProposerPriority instead of each iteration - update (and slightly improve) TestAveragingInIncrementProposerPriorityWithVotingPower to reflect above changes * Fix 2960 by re-normalizing / scaling priorities to be in bounds of total power, additionally: - remove heap where it doesn't make sense - avg. only at the end of IncrementProposerPriority instead of each iteration - update (and slightly improve) TestAveragingInIncrementProposerPriorityWithVotingPower to reflect above changes * fix tests * add comment * update changelog pending & some minor changes * comment about division will floor the result & fix typo * Update TestLargeGenesisValidator: - remove TODO and increase large genesis validator's voting power accordingly * move changelog entry to P2P Protocol * Ceil instead of flooring when dividing & update test * quickly fix failing TestProposerPriorityDoesNotGetResetToZero: - divide by Ceil((maxPriority - minPriority) / 2*totalVotingPower) * fix typo: rename getValWitMostPriority -> getValWithMostPriority * test proposer frequencies * return absolute value for diff. keep testing * use for loop for div * cleanup, more tests * spellcheck * get rid of using floats: manually ceil where necessary * Remove float, simplify, fix tests to match chris's proof (#3157)
6 years ago
Normalize priorities to not exceed total voting power (#3049) * more proposer priority tests - test that we don't reset to zero when updating / adding - test that same power validators alternate * add another test to track / simulate similar behaviour as in #2960 * address some of Chris' review comments * address some more of Chris' review comments * temporarily pushing branch with the following changes: The total power might change if: - a validator is added - a validator is removed - a validator is updated Decrement the accums (of all validators) directly after any of these events (by the inverse of the change) * Fix 2960 by re-normalizing / scaling priorities to be in bounds of total power, additionally: - remove heap where it doesn't make sense - avg. only at the end of IncrementProposerPriority instead of each iteration - update (and slightly improve) TestAveragingInIncrementProposerPriorityWithVotingPower to reflect above changes * Fix 2960 by re-normalizing / scaling priorities to be in bounds of total power, additionally: - remove heap where it doesn't make sense - avg. only at the end of IncrementProposerPriority instead of each iteration - update (and slightly improve) TestAveragingInIncrementProposerPriorityWithVotingPower to reflect above changes * fix tests * add comment * update changelog pending & some minor changes * comment about division will floor the result & fix typo * Update TestLargeGenesisValidator: - remove TODO and increase large genesis validator's voting power accordingly * move changelog entry to P2P Protocol * Ceil instead of flooring when dividing & update test * quickly fix failing TestProposerPriorityDoesNotGetResetToZero: - divide by Ceil((maxPriority - minPriority) / 2*totalVotingPower) * fix typo: rename getValWitMostPriority -> getValWithMostPriority * test proposer frequencies * return absolute value for diff. keep testing * use for loop for div * cleanup, more tests * spellcheck * get rid of using floats: manually ceil where necessary * Remove float, simplify, fix tests to match chris's proof (#3157)
6 years ago
Normalize priorities to not exceed total voting power (#3049) * more proposer priority tests - test that we don't reset to zero when updating / adding - test that same power validators alternate * add another test to track / simulate similar behaviour as in #2960 * address some of Chris' review comments * address some more of Chris' review comments * temporarily pushing branch with the following changes: The total power might change if: - a validator is added - a validator is removed - a validator is updated Decrement the accums (of all validators) directly after any of these events (by the inverse of the change) * Fix 2960 by re-normalizing / scaling priorities to be in bounds of total power, additionally: - remove heap where it doesn't make sense - avg. only at the end of IncrementProposerPriority instead of each iteration - update (and slightly improve) TestAveragingInIncrementProposerPriorityWithVotingPower to reflect above changes * Fix 2960 by re-normalizing / scaling priorities to be in bounds of total power, additionally: - remove heap where it doesn't make sense - avg. only at the end of IncrementProposerPriority instead of each iteration - update (and slightly improve) TestAveragingInIncrementProposerPriorityWithVotingPower to reflect above changes * fix tests * add comment * update changelog pending & some minor changes * comment about division will floor the result & fix typo * Update TestLargeGenesisValidator: - remove TODO and increase large genesis validator's voting power accordingly * move changelog entry to P2P Protocol * Ceil instead of flooring when dividing & update test * quickly fix failing TestProposerPriorityDoesNotGetResetToZero: - divide by Ceil((maxPriority - minPriority) / 2*totalVotingPower) * fix typo: rename getValWitMostPriority -> getValWithMostPriority * test proposer frequencies * return absolute value for diff. keep testing * use for loop for div * cleanup, more tests * spellcheck * get rid of using floats: manually ceil where necessary * Remove float, simplify, fix tests to match chris's proof (#3157)
6 years ago
Normalize priorities to not exceed total voting power (#3049) * more proposer priority tests - test that we don't reset to zero when updating / adding - test that same power validators alternate * add another test to track / simulate similar behaviour as in #2960 * address some of Chris' review comments * address some more of Chris' review comments * temporarily pushing branch with the following changes: The total power might change if: - a validator is added - a validator is removed - a validator is updated Decrement the accums (of all validators) directly after any of these events (by the inverse of the change) * Fix 2960 by re-normalizing / scaling priorities to be in bounds of total power, additionally: - remove heap where it doesn't make sense - avg. only at the end of IncrementProposerPriority instead of each iteration - update (and slightly improve) TestAveragingInIncrementProposerPriorityWithVotingPower to reflect above changes * Fix 2960 by re-normalizing / scaling priorities to be in bounds of total power, additionally: - remove heap where it doesn't make sense - avg. only at the end of IncrementProposerPriority instead of each iteration - update (and slightly improve) TestAveragingInIncrementProposerPriorityWithVotingPower to reflect above changes * fix tests * add comment * update changelog pending & some minor changes * comment about division will floor the result & fix typo * Update TestLargeGenesisValidator: - remove TODO and increase large genesis validator's voting power accordingly * move changelog entry to P2P Protocol * Ceil instead of flooring when dividing & update test * quickly fix failing TestProposerPriorityDoesNotGetResetToZero: - divide by Ceil((maxPriority - minPriority) / 2*totalVotingPower) * fix typo: rename getValWitMostPriority -> getValWithMostPriority * test proposer frequencies * return absolute value for diff. keep testing * use for loop for div * cleanup, more tests * spellcheck * get rid of using floats: manually ceil where necessary * Remove float, simplify, fix tests to match chris's proof (#3157)
6 years ago
Normalize priorities to not exceed total voting power (#3049) * more proposer priority tests - test that we don't reset to zero when updating / adding - test that same power validators alternate * add another test to track / simulate similar behaviour as in #2960 * address some of Chris' review comments * address some more of Chris' review comments * temporarily pushing branch with the following changes: The total power might change if: - a validator is added - a validator is removed - a validator is updated Decrement the accums (of all validators) directly after any of these events (by the inverse of the change) * Fix 2960 by re-normalizing / scaling priorities to be in bounds of total power, additionally: - remove heap where it doesn't make sense - avg. only at the end of IncrementProposerPriority instead of each iteration - update (and slightly improve) TestAveragingInIncrementProposerPriorityWithVotingPower to reflect above changes * Fix 2960 by re-normalizing / scaling priorities to be in bounds of total power, additionally: - remove heap where it doesn't make sense - avg. only at the end of IncrementProposerPriority instead of each iteration - update (and slightly improve) TestAveragingInIncrementProposerPriorityWithVotingPower to reflect above changes * fix tests * add comment * update changelog pending & some minor changes * comment about division will floor the result & fix typo * Update TestLargeGenesisValidator: - remove TODO and increase large genesis validator's voting power accordingly * move changelog entry to P2P Protocol * Ceil instead of flooring when dividing & update test * quickly fix failing TestProposerPriorityDoesNotGetResetToZero: - divide by Ceil((maxPriority - minPriority) / 2*totalVotingPower) * fix typo: rename getValWitMostPriority -> getValWithMostPriority * test proposer frequencies * return absolute value for diff. keep testing * use for loop for div * cleanup, more tests * spellcheck * get rid of using floats: manually ceil where necessary * Remove float, simplify, fix tests to match chris's proof (#3157)
6 years ago
Normalize priorities to not exceed total voting power (#3049) * more proposer priority tests - test that we don't reset to zero when updating / adding - test that same power validators alternate * add another test to track / simulate similar behaviour as in #2960 * address some of Chris' review comments * address some more of Chris' review comments * temporarily pushing branch with the following changes: The total power might change if: - a validator is added - a validator is removed - a validator is updated Decrement the accums (of all validators) directly after any of these events (by the inverse of the change) * Fix 2960 by re-normalizing / scaling priorities to be in bounds of total power, additionally: - remove heap where it doesn't make sense - avg. only at the end of IncrementProposerPriority instead of each iteration - update (and slightly improve) TestAveragingInIncrementProposerPriorityWithVotingPower to reflect above changes * Fix 2960 by re-normalizing / scaling priorities to be in bounds of total power, additionally: - remove heap where it doesn't make sense - avg. only at the end of IncrementProposerPriority instead of each iteration - update (and slightly improve) TestAveragingInIncrementProposerPriorityWithVotingPower to reflect above changes * fix tests * add comment * update changelog pending & some minor changes * comment about division will floor the result & fix typo * Update TestLargeGenesisValidator: - remove TODO and increase large genesis validator's voting power accordingly * move changelog entry to P2P Protocol * Ceil instead of flooring when dividing & update test * quickly fix failing TestProposerPriorityDoesNotGetResetToZero: - divide by Ceil((maxPriority - minPriority) / 2*totalVotingPower) * fix typo: rename getValWitMostPriority -> getValWithMostPriority * test proposer frequencies * return absolute value for diff. keep testing * use for loop for div * cleanup, more tests * spellcheck * get rid of using floats: manually ceil where necessary * Remove float, simplify, fix tests to match chris's proof (#3157)
6 years ago
Normalize priorities to not exceed total voting power (#3049) * more proposer priority tests - test that we don't reset to zero when updating / adding - test that same power validators alternate * add another test to track / simulate similar behaviour as in #2960 * address some of Chris' review comments * address some more of Chris' review comments * temporarily pushing branch with the following changes: The total power might change if: - a validator is added - a validator is removed - a validator is updated Decrement the accums (of all validators) directly after any of these events (by the inverse of the change) * Fix 2960 by re-normalizing / scaling priorities to be in bounds of total power, additionally: - remove heap where it doesn't make sense - avg. only at the end of IncrementProposerPriority instead of each iteration - update (and slightly improve) TestAveragingInIncrementProposerPriorityWithVotingPower to reflect above changes * Fix 2960 by re-normalizing / scaling priorities to be in bounds of total power, additionally: - remove heap where it doesn't make sense - avg. only at the end of IncrementProposerPriority instead of each iteration - update (and slightly improve) TestAveragingInIncrementProposerPriorityWithVotingPower to reflect above changes * fix tests * add comment * update changelog pending & some minor changes * comment about division will floor the result & fix typo * Update TestLargeGenesisValidator: - remove TODO and increase large genesis validator's voting power accordingly * move changelog entry to P2P Protocol * Ceil instead of flooring when dividing & update test * quickly fix failing TestProposerPriorityDoesNotGetResetToZero: - divide by Ceil((maxPriority - minPriority) / 2*totalVotingPower) * fix typo: rename getValWitMostPriority -> getValWithMostPriority * test proposer frequencies * return absolute value for diff. keep testing * use for loop for div * cleanup, more tests * spellcheck * get rid of using floats: manually ceil where necessary * Remove float, simplify, fix tests to match chris's proof (#3157)
6 years ago
Normalize priorities to not exceed total voting power (#3049) * more proposer priority tests - test that we don't reset to zero when updating / adding - test that same power validators alternate * add another test to track / simulate similar behaviour as in #2960 * address some of Chris' review comments * address some more of Chris' review comments * temporarily pushing branch with the following changes: The total power might change if: - a validator is added - a validator is removed - a validator is updated Decrement the accums (of all validators) directly after any of these events (by the inverse of the change) * Fix 2960 by re-normalizing / scaling priorities to be in bounds of total power, additionally: - remove heap where it doesn't make sense - avg. only at the end of IncrementProposerPriority instead of each iteration - update (and slightly improve) TestAveragingInIncrementProposerPriorityWithVotingPower to reflect above changes * Fix 2960 by re-normalizing / scaling priorities to be in bounds of total power, additionally: - remove heap where it doesn't make sense - avg. only at the end of IncrementProposerPriority instead of each iteration - update (and slightly improve) TestAveragingInIncrementProposerPriorityWithVotingPower to reflect above changes * fix tests * add comment * update changelog pending & some minor changes * comment about division will floor the result & fix typo * Update TestLargeGenesisValidator: - remove TODO and increase large genesis validator's voting power accordingly * move changelog entry to P2P Protocol * Ceil instead of flooring when dividing & update test * quickly fix failing TestProposerPriorityDoesNotGetResetToZero: - divide by Ceil((maxPriority - minPriority) / 2*totalVotingPower) * fix typo: rename getValWitMostPriority -> getValWithMostPriority * test proposer frequencies * return absolute value for diff. keep testing * use for loop for div * cleanup, more tests * spellcheck * get rid of using floats: manually ceil where necessary * Remove float, simplify, fix tests to match chris's proof (#3157)
6 years ago
Normalize priorities to not exceed total voting power (#3049) * more proposer priority tests - test that we don't reset to zero when updating / adding - test that same power validators alternate * add another test to track / simulate similar behaviour as in #2960 * address some of Chris' review comments * address some more of Chris' review comments * temporarily pushing branch with the following changes: The total power might change if: - a validator is added - a validator is removed - a validator is updated Decrement the accums (of all validators) directly after any of these events (by the inverse of the change) * Fix 2960 by re-normalizing / scaling priorities to be in bounds of total power, additionally: - remove heap where it doesn't make sense - avg. only at the end of IncrementProposerPriority instead of each iteration - update (and slightly improve) TestAveragingInIncrementProposerPriorityWithVotingPower to reflect above changes * Fix 2960 by re-normalizing / scaling priorities to be in bounds of total power, additionally: - remove heap where it doesn't make sense - avg. only at the end of IncrementProposerPriority instead of each iteration - update (and slightly improve) TestAveragingInIncrementProposerPriorityWithVotingPower to reflect above changes * fix tests * add comment * update changelog pending & some minor changes * comment about division will floor the result & fix typo * Update TestLargeGenesisValidator: - remove TODO and increase large genesis validator's voting power accordingly * move changelog entry to P2P Protocol * Ceil instead of flooring when dividing & update test * quickly fix failing TestProposerPriorityDoesNotGetResetToZero: - divide by Ceil((maxPriority - minPriority) / 2*totalVotingPower) * fix typo: rename getValWitMostPriority -> getValWithMostPriority * test proposer frequencies * return absolute value for diff. keep testing * use for loop for div * cleanup, more tests * spellcheck * get rid of using floats: manually ceil where necessary * Remove float, simplify, fix tests to match chris's proof (#3157)
6 years ago
Normalize priorities to not exceed total voting power (#3049) * more proposer priority tests - test that we don't reset to zero when updating / adding - test that same power validators alternate * add another test to track / simulate similar behaviour as in #2960 * address some of Chris' review comments * address some more of Chris' review comments * temporarily pushing branch with the following changes: The total power might change if: - a validator is added - a validator is removed - a validator is updated Decrement the accums (of all validators) directly after any of these events (by the inverse of the change) * Fix 2960 by re-normalizing / scaling priorities to be in bounds of total power, additionally: - remove heap where it doesn't make sense - avg. only at the end of IncrementProposerPriority instead of each iteration - update (and slightly improve) TestAveragingInIncrementProposerPriorityWithVotingPower to reflect above changes * Fix 2960 by re-normalizing / scaling priorities to be in bounds of total power, additionally: - remove heap where it doesn't make sense - avg. only at the end of IncrementProposerPriority instead of each iteration - update (and slightly improve) TestAveragingInIncrementProposerPriorityWithVotingPower to reflect above changes * fix tests * add comment * update changelog pending & some minor changes * comment about division will floor the result & fix typo * Update TestLargeGenesisValidator: - remove TODO and increase large genesis validator's voting power accordingly * move changelog entry to P2P Protocol * Ceil instead of flooring when dividing & update test * quickly fix failing TestProposerPriorityDoesNotGetResetToZero: - divide by Ceil((maxPriority - minPriority) / 2*totalVotingPower) * fix typo: rename getValWitMostPriority -> getValWithMostPriority * test proposer frequencies * return absolute value for diff. keep testing * use for loop for div * cleanup, more tests * spellcheck * get rid of using floats: manually ceil where necessary * Remove float, simplify, fix tests to match chris's proof (#3157)
6 years ago
Normalize priorities to not exceed total voting power (#3049) * more proposer priority tests - test that we don't reset to zero when updating / adding - test that same power validators alternate * add another test to track / simulate similar behaviour as in #2960 * address some of Chris' review comments * address some more of Chris' review comments * temporarily pushing branch with the following changes: The total power might change if: - a validator is added - a validator is removed - a validator is updated Decrement the accums (of all validators) directly after any of these events (by the inverse of the change) * Fix 2960 by re-normalizing / scaling priorities to be in bounds of total power, additionally: - remove heap where it doesn't make sense - avg. only at the end of IncrementProposerPriority instead of each iteration - update (and slightly improve) TestAveragingInIncrementProposerPriorityWithVotingPower to reflect above changes * Fix 2960 by re-normalizing / scaling priorities to be in bounds of total power, additionally: - remove heap where it doesn't make sense - avg. only at the end of IncrementProposerPriority instead of each iteration - update (and slightly improve) TestAveragingInIncrementProposerPriorityWithVotingPower to reflect above changes * fix tests * add comment * update changelog pending & some minor changes * comment about division will floor the result & fix typo * Update TestLargeGenesisValidator: - remove TODO and increase large genesis validator's voting power accordingly * move changelog entry to P2P Protocol * Ceil instead of flooring when dividing & update test * quickly fix failing TestProposerPriorityDoesNotGetResetToZero: - divide by Ceil((maxPriority - minPriority) / 2*totalVotingPower) * fix typo: rename getValWitMostPriority -> getValWithMostPriority * test proposer frequencies * return absolute value for diff. keep testing * use for loop for div * cleanup, more tests * spellcheck * get rid of using floats: manually ceil where necessary * Remove float, simplify, fix tests to match chris's proof (#3157)
6 years ago
Normalize priorities to not exceed total voting power (#3049) * more proposer priority tests - test that we don't reset to zero when updating / adding - test that same power validators alternate * add another test to track / simulate similar behaviour as in #2960 * address some of Chris' review comments * address some more of Chris' review comments * temporarily pushing branch with the following changes: The total power might change if: - a validator is added - a validator is removed - a validator is updated Decrement the accums (of all validators) directly after any of these events (by the inverse of the change) * Fix 2960 by re-normalizing / scaling priorities to be in bounds of total power, additionally: - remove heap where it doesn't make sense - avg. only at the end of IncrementProposerPriority instead of each iteration - update (and slightly improve) TestAveragingInIncrementProposerPriorityWithVotingPower to reflect above changes * Fix 2960 by re-normalizing / scaling priorities to be in bounds of total power, additionally: - remove heap where it doesn't make sense - avg. only at the end of IncrementProposerPriority instead of each iteration - update (and slightly improve) TestAveragingInIncrementProposerPriorityWithVotingPower to reflect above changes * fix tests * add comment * update changelog pending & some minor changes * comment about division will floor the result & fix typo * Update TestLargeGenesisValidator: - remove TODO and increase large genesis validator's voting power accordingly * move changelog entry to P2P Protocol * Ceil instead of flooring when dividing & update test * quickly fix failing TestProposerPriorityDoesNotGetResetToZero: - divide by Ceil((maxPriority - minPriority) / 2*totalVotingPower) * fix typo: rename getValWitMostPriority -> getValWithMostPriority * test proposer frequencies * return absolute value for diff. keep testing * use for loop for div * cleanup, more tests * spellcheck * get rid of using floats: manually ceil where necessary * Remove float, simplify, fix tests to match chris's proof (#3157)
6 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
7 years ago
7 years ago
  1. package types
  2. import (
  3. "bytes"
  4. "fmt"
  5. "math"
  6. "math/big"
  7. "sort"
  8. "strings"
  9. "github.com/tendermint/tendermint/crypto/merkle"
  10. cmn "github.com/tendermint/tendermint/libs/common"
  11. )
  12. // The maximum allowed total voting power.
  13. // It needs to be sufficiently small to, in all cases::
  14. // 1. prevent clipping in incrementProposerPriority()
  15. // 2. let (diff+diffMax-1) not overflow in IncrementPropposerPriotity()
  16. // (Proof of 1 is tricky, left to the reader).
  17. // It could be higher, but this is sufficiently large for our purposes,
  18. // and leaves room for defensive purposes.
  19. const MaxTotalVotingPower = int64(math.MaxInt64) / 8
  20. // ValidatorSet represent a set of *Validator at a given height.
  21. // The validators can be fetched by address or index.
  22. // The index is in order of .Address, so the indices are fixed
  23. // for all rounds of a given blockchain height.
  24. // On the other hand, the .ProposerPriority of each validator and
  25. // the designated .GetProposer() of a set changes every round,
  26. // upon calling .IncrementProposerPriority().
  27. // NOTE: Not goroutine-safe.
  28. // NOTE: All get/set to validators should copy the value for safety.
  29. type ValidatorSet struct {
  30. // NOTE: persisted via reflect, must be exported.
  31. Validators []*Validator `json:"validators"`
  32. Proposer *Validator `json:"proposer"`
  33. // cached (unexported)
  34. totalVotingPower int64
  35. }
  36. // NewValidatorSet initializes a ValidatorSet by copying over the
  37. // values from `valz`, a list of Validators. If valz is nil or empty,
  38. // the new ValidatorSet will have an empty list of Validators.
  39. func NewValidatorSet(valz []*Validator) *ValidatorSet {
  40. validators := make([]*Validator, len(valz))
  41. for i, val := range valz {
  42. validators[i] = val.Copy()
  43. }
  44. sort.Sort(ValidatorsByAddress(validators))
  45. vals := &ValidatorSet{
  46. Validators: validators,
  47. }
  48. if len(valz) > 0 {
  49. vals.IncrementProposerPriority(1)
  50. }
  51. return vals
  52. }
  53. // Nil or empty validator sets are invalid.
  54. func (vals *ValidatorSet) IsNilOrEmpty() bool {
  55. return vals == nil || len(vals.Validators) == 0
  56. }
  57. // Increment ProposerPriority and update the proposer on a copy, and return it.
  58. func (vals *ValidatorSet) CopyIncrementProposerPriority(times int) *ValidatorSet {
  59. copy := vals.Copy()
  60. copy.IncrementProposerPriority(times)
  61. return copy
  62. }
  63. // IncrementProposerPriority increments ProposerPriority of each validator and updates the
  64. // proposer. Panics if validator set is empty.
  65. // `times` must be positive.
  66. func (vals *ValidatorSet) IncrementProposerPriority(times int) {
  67. if times <= 0 {
  68. panic("Cannot call IncrementProposerPriority with non-positive times")
  69. }
  70. // Cap the difference between priorities to be proportional to 2*totalPower by
  71. // re-normalizing priorities, i.e., rescale all priorities by multiplying with:
  72. // 2*totalVotingPower/(maxPriority - minPriority)
  73. diffMax := 2 * vals.TotalVotingPower()
  74. vals.RescalePriorities(diffMax)
  75. var proposer *Validator
  76. // call IncrementProposerPriority(1) times times:
  77. for i := 0; i < times; i++ {
  78. proposer = vals.incrementProposerPriority()
  79. }
  80. vals.shiftByAvgProposerPriority()
  81. vals.Proposer = proposer
  82. }
  83. func (vals *ValidatorSet) RescalePriorities(diffMax int64) {
  84. // NOTE: This check is merely a sanity check which could be
  85. // removed if all tests would init. voting power appropriately;
  86. // i.e. diffMax should always be > 0
  87. if diffMax <= 0 {
  88. return
  89. }
  90. // Caculating ceil(diff/diffMax):
  91. // Re-normalization is performed by dividing by an integer for simplicity.
  92. // NOTE: This may make debugging priority issues easier as well.
  93. diff := computeMaxMinPriorityDiff(vals)
  94. ratio := (diff + diffMax - 1) / diffMax
  95. if ratio > 1 {
  96. for _, val := range vals.Validators {
  97. val.ProposerPriority /= ratio
  98. }
  99. }
  100. }
  101. func (vals *ValidatorSet) incrementProposerPriority() *Validator {
  102. for _, val := range vals.Validators {
  103. // Check for overflow for sum.
  104. newPrio := safeAddClip(val.ProposerPriority, val.VotingPower)
  105. val.ProposerPriority = newPrio
  106. }
  107. // Decrement the validator with most ProposerPriority:
  108. mostest := vals.getValWithMostPriority()
  109. // mind underflow
  110. mostest.ProposerPriority = safeSubClip(mostest.ProposerPriority, vals.TotalVotingPower())
  111. return mostest
  112. }
  113. // should not be called on an empty validator set
  114. func (vals *ValidatorSet) computeAvgProposerPriority() int64 {
  115. n := int64(len(vals.Validators))
  116. sum := big.NewInt(0)
  117. for _, val := range vals.Validators {
  118. sum.Add(sum, big.NewInt(val.ProposerPriority))
  119. }
  120. avg := sum.Div(sum, big.NewInt(n))
  121. if avg.IsInt64() {
  122. return avg.Int64()
  123. }
  124. // this should never happen: each val.ProposerPriority is in bounds of int64
  125. panic(fmt.Sprintf("Cannot represent avg ProposerPriority as an int64 %v", avg))
  126. }
  127. // compute the difference between the max and min ProposerPriority of that set
  128. func computeMaxMinPriorityDiff(vals *ValidatorSet) int64 {
  129. max := int64(math.MinInt64)
  130. min := int64(math.MaxInt64)
  131. for _, v := range vals.Validators {
  132. if v.ProposerPriority < min {
  133. min = v.ProposerPriority
  134. }
  135. if v.ProposerPriority > max {
  136. max = v.ProposerPriority
  137. }
  138. }
  139. diff := max - min
  140. if diff < 0 {
  141. return -1 * diff
  142. } else {
  143. return diff
  144. }
  145. }
  146. func (vals *ValidatorSet) getValWithMostPriority() *Validator {
  147. var res *Validator
  148. for _, val := range vals.Validators {
  149. res = res.CompareProposerPriority(val)
  150. }
  151. return res
  152. }
  153. func (vals *ValidatorSet) shiftByAvgProposerPriority() {
  154. avgProposerPriority := vals.computeAvgProposerPriority()
  155. for _, val := range vals.Validators {
  156. val.ProposerPriority = safeSubClip(val.ProposerPriority, avgProposerPriority)
  157. }
  158. }
  159. // Copy each validator into a new ValidatorSet
  160. func (vals *ValidatorSet) Copy() *ValidatorSet {
  161. validators := make([]*Validator, len(vals.Validators))
  162. for i, val := range vals.Validators {
  163. // NOTE: must copy, since IncrementProposerPriority updates in place.
  164. validators[i] = val.Copy()
  165. }
  166. return &ValidatorSet{
  167. Validators: validators,
  168. Proposer: vals.Proposer,
  169. totalVotingPower: vals.totalVotingPower,
  170. }
  171. }
  172. // HasAddress returns true if address given is in the validator set, false -
  173. // otherwise.
  174. func (vals *ValidatorSet) HasAddress(address []byte) bool {
  175. idx := sort.Search(len(vals.Validators), func(i int) bool {
  176. return bytes.Compare(address, vals.Validators[i].Address) <= 0
  177. })
  178. return idx < len(vals.Validators) && bytes.Equal(vals.Validators[idx].Address, address)
  179. }
  180. // GetByAddress returns an index of the validator with address and validator
  181. // itself if found. Otherwise, -1 and nil are returned.
  182. func (vals *ValidatorSet) GetByAddress(address []byte) (index int, val *Validator) {
  183. idx := sort.Search(len(vals.Validators), func(i int) bool {
  184. return bytes.Compare(address, vals.Validators[i].Address) <= 0
  185. })
  186. if idx < len(vals.Validators) && bytes.Equal(vals.Validators[idx].Address, address) {
  187. return idx, vals.Validators[idx].Copy()
  188. }
  189. return -1, nil
  190. }
  191. // GetByIndex returns the validator's address and validator itself by index.
  192. // It returns nil values if index is less than 0 or greater or equal to
  193. // len(ValidatorSet.Validators).
  194. func (vals *ValidatorSet) GetByIndex(index int) (address []byte, val *Validator) {
  195. if index < 0 || index >= len(vals.Validators) {
  196. return nil, nil
  197. }
  198. val = vals.Validators[index]
  199. return val.Address, val.Copy()
  200. }
  201. // Size returns the length of the validator set.
  202. func (vals *ValidatorSet) Size() int {
  203. return len(vals.Validators)
  204. }
  205. // TotalVotingPower returns the sum of the voting powers of all validators.
  206. func (vals *ValidatorSet) TotalVotingPower() int64 {
  207. if vals.totalVotingPower == 0 {
  208. sum := int64(0)
  209. for _, val := range vals.Validators {
  210. // mind overflow
  211. sum = safeAddClip(sum, val.VotingPower)
  212. }
  213. if sum > MaxTotalVotingPower {
  214. panic(fmt.Sprintf(
  215. "Total voting power should be guarded to not exceed %v; got: %v",
  216. MaxTotalVotingPower,
  217. sum))
  218. }
  219. vals.totalVotingPower = sum
  220. }
  221. return vals.totalVotingPower
  222. }
  223. // GetProposer returns the current proposer. If the validator set is empty, nil
  224. // is returned.
  225. func (vals *ValidatorSet) GetProposer() (proposer *Validator) {
  226. if len(vals.Validators) == 0 {
  227. return nil
  228. }
  229. if vals.Proposer == nil {
  230. vals.Proposer = vals.findProposer()
  231. }
  232. return vals.Proposer.Copy()
  233. }
  234. func (vals *ValidatorSet) findProposer() *Validator {
  235. var proposer *Validator
  236. for _, val := range vals.Validators {
  237. if proposer == nil || !bytes.Equal(val.Address, proposer.Address) {
  238. proposer = proposer.CompareProposerPriority(val)
  239. }
  240. }
  241. return proposer
  242. }
  243. // Hash returns the Merkle root hash build using validators (as leaves) in the
  244. // set.
  245. func (vals *ValidatorSet) Hash() []byte {
  246. if len(vals.Validators) == 0 {
  247. return nil
  248. }
  249. bzs := make([][]byte, len(vals.Validators))
  250. for i, val := range vals.Validators {
  251. bzs[i] = val.Bytes()
  252. }
  253. return merkle.SimpleHashFromByteSlices(bzs)
  254. }
  255. // Add adds val to the validator set and returns true. It returns false if val
  256. // is already in the set.
  257. func (vals *ValidatorSet) Add(val *Validator) (added bool) {
  258. val = val.Copy()
  259. idx := sort.Search(len(vals.Validators), func(i int) bool {
  260. return bytes.Compare(val.Address, vals.Validators[i].Address) <= 0
  261. })
  262. if idx >= len(vals.Validators) {
  263. vals.Validators = append(vals.Validators, val)
  264. // Invalidate cache
  265. vals.Proposer = nil
  266. vals.totalVotingPower = 0
  267. return true
  268. } else if bytes.Equal(vals.Validators[idx].Address, val.Address) {
  269. return false
  270. } else {
  271. newValidators := make([]*Validator, len(vals.Validators)+1)
  272. copy(newValidators[:idx], vals.Validators[:idx])
  273. newValidators[idx] = val
  274. copy(newValidators[idx+1:], vals.Validators[idx:])
  275. vals.Validators = newValidators
  276. // Invalidate cache
  277. vals.Proposer = nil
  278. vals.totalVotingPower = 0
  279. return true
  280. }
  281. }
  282. // Update updates the ValidatorSet by copying in the val.
  283. // If the val is not found, it returns false; otherwise,
  284. // it returns true. The val.ProposerPriority field is ignored
  285. // and unchanged by this method.
  286. func (vals *ValidatorSet) Update(val *Validator) (updated bool) {
  287. index, sameVal := vals.GetByAddress(val.Address)
  288. if sameVal == nil {
  289. return false
  290. }
  291. // Overwrite the ProposerPriority so it doesn't change.
  292. // During block execution, the val passed in here comes
  293. // from ABCI via PB2TM.ValidatorUpdates. Since ABCI
  294. // doesn't know about ProposerPriority, PB2TM.ValidatorUpdates
  295. // uses the default value of 0, which would cause issues for
  296. // proposer selection every time a validator's voting power changes.
  297. val.ProposerPriority = sameVal.ProposerPriority
  298. vals.Validators[index] = val.Copy()
  299. // Invalidate cache
  300. vals.Proposer = nil
  301. vals.totalVotingPower = 0
  302. return true
  303. }
  304. // Remove deletes the validator with address. It returns the validator removed
  305. // and true. If returns nil and false if validator is not present in the set.
  306. func (vals *ValidatorSet) Remove(address []byte) (val *Validator, removed bool) {
  307. idx := sort.Search(len(vals.Validators), func(i int) bool {
  308. return bytes.Compare(address, vals.Validators[i].Address) <= 0
  309. })
  310. if idx >= len(vals.Validators) || !bytes.Equal(vals.Validators[idx].Address, address) {
  311. return nil, false
  312. }
  313. removedVal := vals.Validators[idx]
  314. newValidators := vals.Validators[:idx]
  315. if idx+1 < len(vals.Validators) {
  316. newValidators = append(newValidators, vals.Validators[idx+1:]...)
  317. }
  318. vals.Validators = newValidators
  319. // Invalidate cache
  320. vals.Proposer = nil
  321. vals.totalVotingPower = 0
  322. return removedVal, true
  323. }
  324. // Iterate will run the given function over the set.
  325. func (vals *ValidatorSet) Iterate(fn func(index int, val *Validator) bool) {
  326. for i, val := range vals.Validators {
  327. stop := fn(i, val.Copy())
  328. if stop {
  329. break
  330. }
  331. }
  332. }
  333. // Verify that +2/3 of the set had signed the given signBytes.
  334. func (vals *ValidatorSet) VerifyCommit(chainID string, blockID BlockID, height int64, commit *Commit) error {
  335. if err := commit.ValidateBasic(); err != nil {
  336. return err
  337. }
  338. if vals.Size() != len(commit.Precommits) {
  339. return fmt.Errorf("Invalid commit -- wrong set size: %v vs %v", vals.Size(), len(commit.Precommits))
  340. }
  341. if height != commit.Height() {
  342. return fmt.Errorf("Invalid commit -- wrong height: %v vs %v", height, commit.Height())
  343. }
  344. if !blockID.Equals(commit.BlockID) {
  345. return fmt.Errorf("Invalid commit -- wrong block id: want %v got %v",
  346. blockID, commit.BlockID)
  347. }
  348. talliedVotingPower := int64(0)
  349. for idx, precommit := range commit.Precommits {
  350. if precommit == nil {
  351. continue // OK, some precommits can be missing.
  352. }
  353. _, val := vals.GetByIndex(idx)
  354. // Validate signature.
  355. precommitSignBytes := commit.VoteSignBytes(chainID, precommit)
  356. if !val.PubKey.VerifyBytes(precommitSignBytes, precommit.Signature) {
  357. return fmt.Errorf("Invalid commit -- invalid signature: %v", precommit)
  358. }
  359. // Good precommit!
  360. if blockID.Equals(precommit.BlockID) {
  361. talliedVotingPower += val.VotingPower
  362. } else {
  363. // It's OK that the BlockID doesn't match. We include stray
  364. // precommits to measure validator availability.
  365. }
  366. }
  367. if talliedVotingPower > vals.TotalVotingPower()*2/3 {
  368. return nil
  369. }
  370. return errTooMuchChange{talliedVotingPower, vals.TotalVotingPower()*2/3 + 1}
  371. }
  372. // VerifyFutureCommit will check to see if the set would be valid with a different
  373. // validator set.
  374. //
  375. // vals is the old validator set that we know. Over 2/3 of the power in old
  376. // signed this block.
  377. //
  378. // In Tendermint, 1/3 of the voting power can halt or fork the chain, but 1/3
  379. // can't make arbitrary state transitions. You still need > 2/3 Byzantine to
  380. // make arbitrary state transitions.
  381. //
  382. // To preserve this property in the light client, we also require > 2/3 of the
  383. // old vals to sign the future commit at H, that way we preserve the property
  384. // that if they weren't being truthful about the validator set at H (block hash
  385. // -> vals hash) or about the app state (block hash -> app hash) we can slash
  386. // > 2/3. Otherwise, the lite client isn't providing the same security
  387. // guarantees.
  388. //
  389. // Even if we added a slashing condition that if you sign a block header with
  390. // the wrong validator set, then we would only need > 1/3 of signatures from
  391. // the old vals on the new commit, it wouldn't be sufficient because the new
  392. // vals can be arbitrary and commit some arbitrary app hash.
  393. //
  394. // newSet is the validator set that signed this block. Only votes from new are
  395. // sufficient for 2/3 majority in the new set as well, for it to be a valid
  396. // commit.
  397. //
  398. // NOTE: This doesn't check whether the commit is a future commit, because the
  399. // current height isn't part of the ValidatorSet. Caller must check that the
  400. // commit height is greater than the height for this validator set.
  401. func (vals *ValidatorSet) VerifyFutureCommit(newSet *ValidatorSet, chainID string,
  402. blockID BlockID, height int64, commit *Commit) error {
  403. oldVals := vals
  404. // Commit must be a valid commit for newSet.
  405. err := newSet.VerifyCommit(chainID, blockID, height, commit)
  406. if err != nil {
  407. return err
  408. }
  409. // Check old voting power.
  410. oldVotingPower := int64(0)
  411. seen := map[int]bool{}
  412. round := commit.Round()
  413. for idx, precommit := range commit.Precommits {
  414. if precommit == nil {
  415. continue
  416. }
  417. if precommit.Height != height {
  418. return cmn.NewError("Blocks don't match - %d vs %d", round, precommit.Round)
  419. }
  420. if precommit.Round != round {
  421. return cmn.NewError("Invalid commit -- wrong round: %v vs %v", round, precommit.Round)
  422. }
  423. if precommit.Type != PrecommitType {
  424. return cmn.NewError("Invalid commit -- not precommit @ index %v", idx)
  425. }
  426. // See if this validator is in oldVals.
  427. idx, val := oldVals.GetByAddress(precommit.ValidatorAddress)
  428. if val == nil || seen[idx] {
  429. continue // missing or double vote...
  430. }
  431. seen[idx] = true
  432. // Validate signature.
  433. precommitSignBytes := commit.VoteSignBytes(chainID, precommit)
  434. if !val.PubKey.VerifyBytes(precommitSignBytes, precommit.Signature) {
  435. return cmn.NewError("Invalid commit -- invalid signature: %v", precommit)
  436. }
  437. // Good precommit!
  438. if blockID.Equals(precommit.BlockID) {
  439. oldVotingPower += val.VotingPower
  440. } else {
  441. // It's OK that the BlockID doesn't match. We include stray
  442. // precommits to measure validator availability.
  443. }
  444. }
  445. if oldVotingPower <= oldVals.TotalVotingPower()*2/3 {
  446. return errTooMuchChange{oldVotingPower, oldVals.TotalVotingPower()*2/3 + 1}
  447. }
  448. return nil
  449. }
  450. //-----------------
  451. // ErrTooMuchChange
  452. func IsErrTooMuchChange(err error) bool {
  453. switch err_ := err.(type) {
  454. case cmn.Error:
  455. _, ok := err_.Data().(errTooMuchChange)
  456. return ok
  457. case errTooMuchChange:
  458. return true
  459. default:
  460. return false
  461. }
  462. }
  463. type errTooMuchChange struct {
  464. got int64
  465. needed int64
  466. }
  467. func (e errTooMuchChange) Error() string {
  468. return fmt.Sprintf("Invalid commit -- insufficient old voting power: got %v, needed %v", e.got, e.needed)
  469. }
  470. //----------------
  471. func (vals *ValidatorSet) String() string {
  472. return vals.StringIndented("")
  473. }
  474. // String
  475. func (vals *ValidatorSet) StringIndented(indent string) string {
  476. if vals == nil {
  477. return "nil-ValidatorSet"
  478. }
  479. var valStrings []string
  480. vals.Iterate(func(index int, val *Validator) bool {
  481. valStrings = append(valStrings, val.String())
  482. return false
  483. })
  484. return fmt.Sprintf(`ValidatorSet{
  485. %s Proposer: %v
  486. %s Validators:
  487. %s %v
  488. %s}`,
  489. indent, vals.GetProposer().String(),
  490. indent,
  491. indent, strings.Join(valStrings, "\n"+indent+" "),
  492. indent)
  493. }
  494. //-------------------------------------
  495. // Implements sort for sorting validators by address.
  496. // Sort validators by address
  497. type ValidatorsByAddress []*Validator
  498. func (valz ValidatorsByAddress) Len() int {
  499. return len(valz)
  500. }
  501. func (valz ValidatorsByAddress) Less(i, j int) bool {
  502. return bytes.Compare(valz[i].Address, valz[j].Address) == -1
  503. }
  504. func (valz ValidatorsByAddress) Swap(i, j int) {
  505. it := valz[i]
  506. valz[i] = valz[j]
  507. valz[j] = it
  508. }
  509. //----------------------------------------
  510. // For testing
  511. // RandValidatorSet returns a randomized validator set, useful for testing.
  512. // NOTE: PrivValidator are in order.
  513. // UNSTABLE
  514. func RandValidatorSet(numValidators int, votingPower int64) (*ValidatorSet, []PrivValidator) {
  515. valz := make([]*Validator, numValidators)
  516. privValidators := make([]PrivValidator, numValidators)
  517. for i := 0; i < numValidators; i++ {
  518. val, privValidator := RandValidator(false, votingPower)
  519. valz[i] = val
  520. privValidators[i] = privValidator
  521. }
  522. vals := NewValidatorSet(valz)
  523. sort.Sort(PrivValidatorsByAddress(privValidators))
  524. return vals, privValidators
  525. }
  526. ///////////////////////////////////////////////////////////////////////////////
  527. // Safe addition/subtraction
  528. func safeAdd(a, b int64) (int64, bool) {
  529. if b > 0 && a > math.MaxInt64-b {
  530. return -1, true
  531. } else if b < 0 && a < math.MinInt64-b {
  532. return -1, true
  533. }
  534. return a + b, false
  535. }
  536. func safeSub(a, b int64) (int64, bool) {
  537. if b > 0 && a < math.MinInt64+b {
  538. return -1, true
  539. } else if b < 0 && a > math.MaxInt64+b {
  540. return -1, true
  541. }
  542. return a - b, false
  543. }
  544. func safeAddClip(a, b int64) int64 {
  545. c, overflow := safeAdd(a, b)
  546. if overflow {
  547. if b < 0 {
  548. return math.MinInt64
  549. }
  550. return math.MaxInt64
  551. }
  552. return c
  553. }
  554. func safeSubClip(a, b int64) int64 {
  555. c, overflow := safeSub(a, b)
  556. if overflow {
  557. if b > 0 {
  558. return math.MinInt64
  559. }
  560. return math.MaxInt64
  561. }
  562. return c
  563. }