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.

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