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.

1484 lines
44 KiB

types: prevent spurious validator power overflow warnings when changing the validator set (#4183) Fix for #4164 The general problem is that in certain conditions an overflow warning is issued when attempting to update a validator set even if the final set's total voting power is not over the maximum allowed. Root cause is that in verifyUpdates(), updates are verified wrt to total voting power in the order of validator address. It is then possible that a low address validator may increase its power such that the temporary total voting power count goes over MaxTotalVotingPower. Scenarios where removing and adding/ updating validators with high voting power, in the same update operation, cause the same false warning and the updates are not applied. Main changes to fix this are in verifyUpdate() that now does the verification starting with the decreases in power. It also takes into account the removals that are part of the update. ## Commits: * tests for overflow detection and prevention * test fix * more tests * fix the false overflow warnings and golint * scopelint warning fix * review comments * variant with using sort by amount of change in power * compute separately number new validators in update * types: use a switch in processChanges * more review comments * types: use HasAddress in numNewValidators * types: refactor verifyUpdates copy updates, sort them by delta and use resulting slice to calculate tvpAfterUpdatesBeforeRemovals. * remove unused structs * review comments * update changelog
5 years ago
types: prevent spurious validator power overflow warnings when changing the validator set (#4183) Fix for #4164 The general problem is that in certain conditions an overflow warning is issued when attempting to update a validator set even if the final set's total voting power is not over the maximum allowed. Root cause is that in verifyUpdates(), updates are verified wrt to total voting power in the order of validator address. It is then possible that a low address validator may increase its power such that the temporary total voting power count goes over MaxTotalVotingPower. Scenarios where removing and adding/ updating validators with high voting power, in the same update operation, cause the same false warning and the updates are not applied. Main changes to fix this are in verifyUpdate() that now does the verification starting with the decreases in power. It also takes into account the removals that are part of the update. ## Commits: * tests for overflow detection and prevention * test fix * more tests * fix the false overflow warnings and golint * scopelint warning fix * review comments * variant with using sort by amount of change in power * compute separately number new validators in update * types: use a switch in processChanges * more review comments * types: use HasAddress in numNewValidators * types: refactor verifyUpdates copy updates, sort them by delta and use resulting slice to calculate tvpAfterUpdatesBeforeRemovals. * remove unused structs * review comments * update changelog
5 years ago
types: prevent spurious validator power overflow warnings when changing the validator set (#4183) Fix for #4164 The general problem is that in certain conditions an overflow warning is issued when attempting to update a validator set even if the final set's total voting power is not over the maximum allowed. Root cause is that in verifyUpdates(), updates are verified wrt to total voting power in the order of validator address. It is then possible that a low address validator may increase its power such that the temporary total voting power count goes over MaxTotalVotingPower. Scenarios where removing and adding/ updating validators with high voting power, in the same update operation, cause the same false warning and the updates are not applied. Main changes to fix this are in verifyUpdate() that now does the verification starting with the decreases in power. It also takes into account the removals that are part of the update. ## Commits: * tests for overflow detection and prevention * test fix * more tests * fix the false overflow warnings and golint * scopelint warning fix * review comments * variant with using sort by amount of change in power * compute separately number new validators in update * types: use a switch in processChanges * more review comments * types: use HasAddress in numNewValidators * types: refactor verifyUpdates copy updates, sort them by delta and use resulting slice to calculate tvpAfterUpdatesBeforeRemovals. * remove unused structs * review comments * update changelog
5 years ago
types: prevent spurious validator power overflow warnings when changing the validator set (#4183) Fix for #4164 The general problem is that in certain conditions an overflow warning is issued when attempting to update a validator set even if the final set's total voting power is not over the maximum allowed. Root cause is that in verifyUpdates(), updates are verified wrt to total voting power in the order of validator address. It is then possible that a low address validator may increase its power such that the temporary total voting power count goes over MaxTotalVotingPower. Scenarios where removing and adding/ updating validators with high voting power, in the same update operation, cause the same false warning and the updates are not applied. Main changes to fix this are in verifyUpdate() that now does the verification starting with the decreases in power. It also takes into account the removals that are part of the update. ## Commits: * tests for overflow detection and prevention * test fix * more tests * fix the false overflow warnings and golint * scopelint warning fix * review comments * variant with using sort by amount of change in power * compute separately number new validators in update * types: use a switch in processChanges * more review comments * types: use HasAddress in numNewValidators * types: refactor verifyUpdates copy updates, sort them by delta and use resulting slice to calculate tvpAfterUpdatesBeforeRemovals. * remove unused structs * review comments * update changelog
5 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
types: prevent spurious validator power overflow warnings when changing the validator set (#4183) Fix for #4164 The general problem is that in certain conditions an overflow warning is issued when attempting to update a validator set even if the final set's total voting power is not over the maximum allowed. Root cause is that in verifyUpdates(), updates are verified wrt to total voting power in the order of validator address. It is then possible that a low address validator may increase its power such that the temporary total voting power count goes over MaxTotalVotingPower. Scenarios where removing and adding/ updating validators with high voting power, in the same update operation, cause the same false warning and the updates are not applied. Main changes to fix this are in verifyUpdate() that now does the verification starting with the decreases in power. It also takes into account the removals that are part of the update. ## Commits: * tests for overflow detection and prevention * test fix * more tests * fix the false overflow warnings and golint * scopelint warning fix * review comments * variant with using sort by amount of change in power * compute separately number new validators in update * types: use a switch in processChanges * more review comments * types: use HasAddress in numNewValidators * types: refactor verifyUpdates copy updates, sort them by delta and use resulting slice to calculate tvpAfterUpdatesBeforeRemovals. * remove unused structs * review comments * update changelog
5 years ago
types: prevent spurious validator power overflow warnings when changing the validator set (#4183) Fix for #4164 The general problem is that in certain conditions an overflow warning is issued when attempting to update a validator set even if the final set's total voting power is not over the maximum allowed. Root cause is that in verifyUpdates(), updates are verified wrt to total voting power in the order of validator address. It is then possible that a low address validator may increase its power such that the temporary total voting power count goes over MaxTotalVotingPower. Scenarios where removing and adding/ updating validators with high voting power, in the same update operation, cause the same false warning and the updates are not applied. Main changes to fix this are in verifyUpdate() that now does the verification starting with the decreases in power. It also takes into account the removals that are part of the update. ## Commits: * tests for overflow detection and prevention * test fix * more tests * fix the false overflow warnings and golint * scopelint warning fix * review comments * variant with using sort by amount of change in power * compute separately number new validators in update * types: use a switch in processChanges * more review comments * types: use HasAddress in numNewValidators * types: refactor verifyUpdates copy updates, sort them by delta and use resulting slice to calculate tvpAfterUpdatesBeforeRemovals. * remove unused structs * review comments * update changelog
5 years ago
types: prevent spurious validator power overflow warnings when changing the validator set (#4183) Fix for #4164 The general problem is that in certain conditions an overflow warning is issued when attempting to update a validator set even if the final set's total voting power is not over the maximum allowed. Root cause is that in verifyUpdates(), updates are verified wrt to total voting power in the order of validator address. It is then possible that a low address validator may increase its power such that the temporary total voting power count goes over MaxTotalVotingPower. Scenarios where removing and adding/ updating validators with high voting power, in the same update operation, cause the same false warning and the updates are not applied. Main changes to fix this are in verifyUpdate() that now does the verification starting with the decreases in power. It also takes into account the removals that are part of the update. ## Commits: * tests for overflow detection and prevention * test fix * more tests * fix the false overflow warnings and golint * scopelint warning fix * review comments * variant with using sort by amount of change in power * compute separately number new validators in update * types: use a switch in processChanges * more review comments * types: use HasAddress in numNewValidators * types: refactor verifyUpdates copy updates, sort them by delta and use resulting slice to calculate tvpAfterUpdatesBeforeRemovals. * remove unused structs * review comments * update changelog
5 years ago
types: prevent spurious validator power overflow warnings when changing the validator set (#4183) Fix for #4164 The general problem is that in certain conditions an overflow warning is issued when attempting to update a validator set even if the final set's total voting power is not over the maximum allowed. Root cause is that in verifyUpdates(), updates are verified wrt to total voting power in the order of validator address. It is then possible that a low address validator may increase its power such that the temporary total voting power count goes over MaxTotalVotingPower. Scenarios where removing and adding/ updating validators with high voting power, in the same update operation, cause the same false warning and the updates are not applied. Main changes to fix this are in verifyUpdate() that now does the verification starting with the decreases in power. It also takes into account the removals that are part of the update. ## Commits: * tests for overflow detection and prevention * test fix * more tests * fix the false overflow warnings and golint * scopelint warning fix * review comments * variant with using sort by amount of change in power * compute separately number new validators in update * types: use a switch in processChanges * more review comments * types: use HasAddress in numNewValidators * types: refactor verifyUpdates copy updates, sort them by delta and use resulting slice to calculate tvpAfterUpdatesBeforeRemovals. * remove unused structs * review comments * update changelog
5 years ago
types: prevent spurious validator power overflow warnings when changing the validator set (#4183) Fix for #4164 The general problem is that in certain conditions an overflow warning is issued when attempting to update a validator set even if the final set's total voting power is not over the maximum allowed. Root cause is that in verifyUpdates(), updates are verified wrt to total voting power in the order of validator address. It is then possible that a low address validator may increase its power such that the temporary total voting power count goes over MaxTotalVotingPower. Scenarios where removing and adding/ updating validators with high voting power, in the same update operation, cause the same false warning and the updates are not applied. Main changes to fix this are in verifyUpdate() that now does the verification starting with the decreases in power. It also takes into account the removals that are part of the update. ## Commits: * tests for overflow detection and prevention * test fix * more tests * fix the false overflow warnings and golint * scopelint warning fix * review comments * variant with using sort by amount of change in power * compute separately number new validators in update * types: use a switch in processChanges * more review comments * types: use HasAddress in numNewValidators * types: refactor verifyUpdates copy updates, sort them by delta and use resulting slice to calculate tvpAfterUpdatesBeforeRemovals. * remove unused structs * review comments * update changelog
5 years ago
types: prevent spurious validator power overflow warnings when changing the validator set (#4183) Fix for #4164 The general problem is that in certain conditions an overflow warning is issued when attempting to update a validator set even if the final set's total voting power is not over the maximum allowed. Root cause is that in verifyUpdates(), updates are verified wrt to total voting power in the order of validator address. It is then possible that a low address validator may increase its power such that the temporary total voting power count goes over MaxTotalVotingPower. Scenarios where removing and adding/ updating validators with high voting power, in the same update operation, cause the same false warning and the updates are not applied. Main changes to fix this are in verifyUpdate() that now does the verification starting with the decreases in power. It also takes into account the removals that are part of the update. ## Commits: * tests for overflow detection and prevention * test fix * more tests * fix the false overflow warnings and golint * scopelint warning fix * review comments * variant with using sort by amount of change in power * compute separately number new validators in update * types: use a switch in processChanges * more review comments * types: use HasAddress in numNewValidators * types: refactor verifyUpdates copy updates, sort them by delta and use resulting slice to calculate tvpAfterUpdatesBeforeRemovals. * remove unused structs * review comments * update changelog
5 years ago
types: prevent spurious validator power overflow warnings when changing the validator set (#4183) Fix for #4164 The general problem is that in certain conditions an overflow warning is issued when attempting to update a validator set even if the final set's total voting power is not over the maximum allowed. Root cause is that in verifyUpdates(), updates are verified wrt to total voting power in the order of validator address. It is then possible that a low address validator may increase its power such that the temporary total voting power count goes over MaxTotalVotingPower. Scenarios where removing and adding/ updating validators with high voting power, in the same update operation, cause the same false warning and the updates are not applied. Main changes to fix this are in verifyUpdate() that now does the verification starting with the decreases in power. It also takes into account the removals that are part of the update. ## Commits: * tests for overflow detection and prevention * test fix * more tests * fix the false overflow warnings and golint * scopelint warning fix * review comments * variant with using sort by amount of change in power * compute separately number new validators in update * types: use a switch in processChanges * more review comments * types: use HasAddress in numNewValidators * types: refactor verifyUpdates copy updates, sort them by delta and use resulting slice to calculate tvpAfterUpdatesBeforeRemovals. * remove unused structs * review comments * update changelog
5 years ago
types: prevent spurious validator power overflow warnings when changing the validator set (#4183) Fix for #4164 The general problem is that in certain conditions an overflow warning is issued when attempting to update a validator set even if the final set's total voting power is not over the maximum allowed. Root cause is that in verifyUpdates(), updates are verified wrt to total voting power in the order of validator address. It is then possible that a low address validator may increase its power such that the temporary total voting power count goes over MaxTotalVotingPower. Scenarios where removing and adding/ updating validators with high voting power, in the same update operation, cause the same false warning and the updates are not applied. Main changes to fix this are in verifyUpdate() that now does the verification starting with the decreases in power. It also takes into account the removals that are part of the update. ## Commits: * tests for overflow detection and prevention * test fix * more tests * fix the false overflow warnings and golint * scopelint warning fix * review comments * variant with using sort by amount of change in power * compute separately number new validators in update * types: use a switch in processChanges * more review comments * types: use HasAddress in numNewValidators * types: refactor verifyUpdates copy updates, sort them by delta and use resulting slice to calculate tvpAfterUpdatesBeforeRemovals. * remove unused structs * review comments * update changelog
5 years ago
types: prevent spurious validator power overflow warnings when changing the validator set (#4183) Fix for #4164 The general problem is that in certain conditions an overflow warning is issued when attempting to update a validator set even if the final set's total voting power is not over the maximum allowed. Root cause is that in verifyUpdates(), updates are verified wrt to total voting power in the order of validator address. It is then possible that a low address validator may increase its power such that the temporary total voting power count goes over MaxTotalVotingPower. Scenarios where removing and adding/ updating validators with high voting power, in the same update operation, cause the same false warning and the updates are not applied. Main changes to fix this are in verifyUpdate() that now does the verification starting with the decreases in power. It also takes into account the removals that are part of the update. ## Commits: * tests for overflow detection and prevention * test fix * more tests * fix the false overflow warnings and golint * scopelint warning fix * review comments * variant with using sort by amount of change in power * compute separately number new validators in update * types: use a switch in processChanges * more review comments * types: use HasAddress in numNewValidators * types: refactor verifyUpdates copy updates, sort them by delta and use resulting slice to calculate tvpAfterUpdatesBeforeRemovals. * remove unused structs * review comments * update changelog
5 years ago
types: prevent spurious validator power overflow warnings when changing the validator set (#4183) Fix for #4164 The general problem is that in certain conditions an overflow warning is issued when attempting to update a validator set even if the final set's total voting power is not over the maximum allowed. Root cause is that in verifyUpdates(), updates are verified wrt to total voting power in the order of validator address. It is then possible that a low address validator may increase its power such that the temporary total voting power count goes over MaxTotalVotingPower. Scenarios where removing and adding/ updating validators with high voting power, in the same update operation, cause the same false warning and the updates are not applied. Main changes to fix this are in verifyUpdate() that now does the verification starting with the decreases in power. It also takes into account the removals that are part of the update. ## Commits: * tests for overflow detection and prevention * test fix * more tests * fix the false overflow warnings and golint * scopelint warning fix * review comments * variant with using sort by amount of change in power * compute separately number new validators in update * types: use a switch in processChanges * more review comments * types: use HasAddress in numNewValidators * types: refactor verifyUpdates copy updates, sort them by delta and use resulting slice to calculate tvpAfterUpdatesBeforeRemovals. * remove unused structs * review comments * update changelog
5 years ago
types: prevent spurious validator power overflow warnings when changing the validator set (#4183) Fix for #4164 The general problem is that in certain conditions an overflow warning is issued when attempting to update a validator set even if the final set's total voting power is not over the maximum allowed. Root cause is that in verifyUpdates(), updates are verified wrt to total voting power in the order of validator address. It is then possible that a low address validator may increase its power such that the temporary total voting power count goes over MaxTotalVotingPower. Scenarios where removing and adding/ updating validators with high voting power, in the same update operation, cause the same false warning and the updates are not applied. Main changes to fix this are in verifyUpdate() that now does the verification starting with the decreases in power. It also takes into account the removals that are part of the update. ## Commits: * tests for overflow detection and prevention * test fix * more tests * fix the false overflow warnings and golint * scopelint warning fix * review comments * variant with using sort by amount of change in power * compute separately number new validators in update * types: use a switch in processChanges * more review comments * types: use HasAddress in numNewValidators * types: refactor verifyUpdates copy updates, sort them by delta and use resulting slice to calculate tvpAfterUpdatesBeforeRemovals. * remove unused structs * review comments * update changelog
5 years ago
types: prevent spurious validator power overflow warnings when changing the validator set (#4183) Fix for #4164 The general problem is that in certain conditions an overflow warning is issued when attempting to update a validator set even if the final set's total voting power is not over the maximum allowed. Root cause is that in verifyUpdates(), updates are verified wrt to total voting power in the order of validator address. It is then possible that a low address validator may increase its power such that the temporary total voting power count goes over MaxTotalVotingPower. Scenarios where removing and adding/ updating validators with high voting power, in the same update operation, cause the same false warning and the updates are not applied. Main changes to fix this are in verifyUpdate() that now does the verification starting with the decreases in power. It also takes into account the removals that are part of the update. ## Commits: * tests for overflow detection and prevention * test fix * more tests * fix the false overflow warnings and golint * scopelint warning fix * review comments * variant with using sort by amount of change in power * compute separately number new validators in update * types: use a switch in processChanges * more review comments * types: use HasAddress in numNewValidators * types: refactor verifyUpdates copy updates, sort them by delta and use resulting slice to calculate tvpAfterUpdatesBeforeRemovals. * remove unused structs * review comments * update changelog
5 years ago
  1. package types
  2. import (
  3. "bytes"
  4. "fmt"
  5. "math"
  6. "sort"
  7. "strings"
  8. "testing"
  9. "testing/quick"
  10. "time"
  11. "github.com/stretchr/testify/assert"
  12. "github.com/stretchr/testify/require"
  13. "github.com/tendermint/tendermint/crypto"
  14. "github.com/tendermint/tendermint/crypto/ed25519"
  15. tmmath "github.com/tendermint/tendermint/libs/math"
  16. tmrand "github.com/tendermint/tendermint/libs/rand"
  17. tmtime "github.com/tendermint/tendermint/types/time"
  18. )
  19. func TestValidatorSetBasic(t *testing.T) {
  20. // empty or nil validator lists are allowed,
  21. // but attempting to IncrementProposerPriority on them will panic.
  22. vset := NewValidatorSet([]*Validator{})
  23. assert.Panics(t, func() { vset.IncrementProposerPriority(1) })
  24. vset = NewValidatorSet(nil)
  25. assert.Panics(t, func() { vset.IncrementProposerPriority(1) })
  26. assert.EqualValues(t, vset, vset.Copy())
  27. assert.False(t, vset.HasAddress([]byte("some val")))
  28. idx, val := vset.GetByAddress([]byte("some val"))
  29. assert.Equal(t, -1, idx)
  30. assert.Nil(t, val)
  31. addr, val := vset.GetByIndex(-100)
  32. assert.Nil(t, addr)
  33. assert.Nil(t, val)
  34. addr, val = vset.GetByIndex(0)
  35. assert.Nil(t, addr)
  36. assert.Nil(t, val)
  37. addr, val = vset.GetByIndex(100)
  38. assert.Nil(t, addr)
  39. assert.Nil(t, val)
  40. assert.Zero(t, vset.Size())
  41. assert.Equal(t, int64(0), vset.TotalVotingPower())
  42. assert.Nil(t, vset.GetProposer())
  43. assert.Nil(t, vset.Hash())
  44. // add
  45. val = randValidator(vset.TotalVotingPower())
  46. assert.NoError(t, vset.UpdateWithChangeSet([]*Validator{val}))
  47. assert.True(t, vset.HasAddress(val.Address))
  48. idx, _ = vset.GetByAddress(val.Address)
  49. assert.Equal(t, 0, idx)
  50. addr, _ = vset.GetByIndex(0)
  51. assert.Equal(t, []byte(val.Address), addr)
  52. assert.Equal(t, 1, vset.Size())
  53. assert.Equal(t, val.VotingPower, vset.TotalVotingPower())
  54. assert.NotNil(t, vset.Hash())
  55. assert.NotPanics(t, func() { vset.IncrementProposerPriority(1) })
  56. assert.Equal(t, val.Address, vset.GetProposer().Address)
  57. // update
  58. val = randValidator(vset.TotalVotingPower())
  59. assert.NoError(t, vset.UpdateWithChangeSet([]*Validator{val}))
  60. _, val = vset.GetByAddress(val.Address)
  61. val.VotingPower += 100
  62. proposerPriority := val.ProposerPriority
  63. val.ProposerPriority = 0
  64. assert.NoError(t, vset.UpdateWithChangeSet([]*Validator{val}))
  65. _, val = vset.GetByAddress(val.Address)
  66. assert.Equal(t, proposerPriority, val.ProposerPriority)
  67. }
  68. func TestCopy(t *testing.T) {
  69. vset := randValidatorSet(10)
  70. vsetHash := vset.Hash()
  71. if len(vsetHash) == 0 {
  72. t.Fatalf("ValidatorSet had unexpected zero hash")
  73. }
  74. vsetCopy := vset.Copy()
  75. vsetCopyHash := vsetCopy.Hash()
  76. if !bytes.Equal(vsetHash, vsetCopyHash) {
  77. t.Fatalf("ValidatorSet copy had wrong hash. Orig: %X, Copy: %X", vsetHash, vsetCopyHash)
  78. }
  79. }
  80. // Test that IncrementProposerPriority requires positive times.
  81. func TestIncrementProposerPriorityPositiveTimes(t *testing.T) {
  82. vset := NewValidatorSet([]*Validator{
  83. newValidator([]byte("foo"), 1000),
  84. newValidator([]byte("bar"), 300),
  85. newValidator([]byte("baz"), 330),
  86. })
  87. assert.Panics(t, func() { vset.IncrementProposerPriority(-1) })
  88. assert.Panics(t, func() { vset.IncrementProposerPriority(0) })
  89. vset.IncrementProposerPriority(1)
  90. }
  91. func BenchmarkValidatorSetCopy(b *testing.B) {
  92. b.StopTimer()
  93. vset := NewValidatorSet([]*Validator{})
  94. for i := 0; i < 1000; i++ {
  95. privKey := ed25519.GenPrivKey()
  96. pubKey := privKey.PubKey()
  97. val := NewValidator(pubKey, 10)
  98. err := vset.UpdateWithChangeSet([]*Validator{val})
  99. if err != nil {
  100. panic("Failed to add validator")
  101. }
  102. }
  103. b.StartTimer()
  104. for i := 0; i < b.N; i++ {
  105. vset.Copy()
  106. }
  107. }
  108. //-------------------------------------------------------------------
  109. func TestProposerSelection1(t *testing.T) {
  110. vset := NewValidatorSet([]*Validator{
  111. newValidator([]byte("foo"), 1000),
  112. newValidator([]byte("bar"), 300),
  113. newValidator([]byte("baz"), 330),
  114. })
  115. var proposers []string
  116. for i := 0; i < 99; i++ {
  117. val := vset.GetProposer()
  118. proposers = append(proposers, string(val.Address))
  119. vset.IncrementProposerPriority(1)
  120. }
  121. expected := `foo baz foo bar foo foo baz foo bar foo foo baz foo foo bar foo baz foo foo bar` +
  122. ` foo foo baz foo bar foo foo baz foo bar foo foo baz foo foo bar foo baz foo foo bar` +
  123. ` foo baz foo foo bar foo baz foo foo bar foo baz foo foo foo baz bar foo foo foo baz` +
  124. ` foo bar foo foo baz foo bar foo foo baz foo bar foo foo baz foo bar foo foo baz foo` +
  125. ` foo bar foo baz foo foo bar foo baz foo foo bar foo baz foo foo`
  126. if expected != strings.Join(proposers, " ") {
  127. t.Errorf("expected sequence of proposers was\n%v\nbut got \n%v", expected, strings.Join(proposers, " "))
  128. }
  129. }
  130. func TestProposerSelection2(t *testing.T) {
  131. addr0 := []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
  132. addr1 := []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}
  133. addr2 := []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2}
  134. // when all voting power is same, we go in order of addresses
  135. val0, val1, val2 := newValidator(addr0, 100), newValidator(addr1, 100), newValidator(addr2, 100)
  136. valList := []*Validator{val0, val1, val2}
  137. vals := NewValidatorSet(valList)
  138. for i := 0; i < len(valList)*5; i++ {
  139. ii := (i) % len(valList)
  140. prop := vals.GetProposer()
  141. if !bytes.Equal(prop.Address, valList[ii].Address) {
  142. t.Fatalf("(%d): Expected %X. Got %X", i, valList[ii].Address, prop.Address)
  143. }
  144. vals.IncrementProposerPriority(1)
  145. }
  146. // One validator has more than the others, but not enough to propose twice in a row
  147. *val2 = *newValidator(addr2, 400)
  148. vals = NewValidatorSet(valList)
  149. // vals.IncrementProposerPriority(1)
  150. prop := vals.GetProposer()
  151. if !bytes.Equal(prop.Address, addr2) {
  152. t.Fatalf("Expected address with highest voting power to be first proposer. Got %X", prop.Address)
  153. }
  154. vals.IncrementProposerPriority(1)
  155. prop = vals.GetProposer()
  156. if !bytes.Equal(prop.Address, addr0) {
  157. t.Fatalf("Expected smallest address to be validator. Got %X", prop.Address)
  158. }
  159. // One validator has more than the others, and enough to be proposer twice in a row
  160. *val2 = *newValidator(addr2, 401)
  161. vals = NewValidatorSet(valList)
  162. prop = vals.GetProposer()
  163. if !bytes.Equal(prop.Address, addr2) {
  164. t.Fatalf("Expected address with highest voting power to be first proposer. Got %X", prop.Address)
  165. }
  166. vals.IncrementProposerPriority(1)
  167. prop = vals.GetProposer()
  168. if !bytes.Equal(prop.Address, addr2) {
  169. t.Fatalf("Expected address with highest voting power to be second proposer. Got %X", prop.Address)
  170. }
  171. vals.IncrementProposerPriority(1)
  172. prop = vals.GetProposer()
  173. if !bytes.Equal(prop.Address, addr0) {
  174. t.Fatalf("Expected smallest address to be validator. Got %X", prop.Address)
  175. }
  176. // each validator should be the proposer a proportional number of times
  177. val0, val1, val2 = newValidator(addr0, 4), newValidator(addr1, 5), newValidator(addr2, 3)
  178. valList = []*Validator{val0, val1, val2}
  179. propCount := make([]int, 3)
  180. vals = NewValidatorSet(valList)
  181. N := 1
  182. for i := 0; i < 120*N; i++ {
  183. prop := vals.GetProposer()
  184. ii := prop.Address[19]
  185. propCount[ii]++
  186. vals.IncrementProposerPriority(1)
  187. }
  188. if propCount[0] != 40*N {
  189. t.Fatalf(
  190. "Expected prop count for validator with 4/12 of voting power to be %d/%d. Got %d/%d",
  191. 40*N,
  192. 120*N,
  193. propCount[0],
  194. 120*N,
  195. )
  196. }
  197. if propCount[1] != 50*N {
  198. t.Fatalf(
  199. "Expected prop count for validator with 5/12 of voting power to be %d/%d. Got %d/%d",
  200. 50*N,
  201. 120*N,
  202. propCount[1],
  203. 120*N,
  204. )
  205. }
  206. if propCount[2] != 30*N {
  207. t.Fatalf(
  208. "Expected prop count for validator with 3/12 of voting power to be %d/%d. Got %d/%d",
  209. 30*N,
  210. 120*N,
  211. propCount[2],
  212. 120*N,
  213. )
  214. }
  215. }
  216. func TestProposerSelection3(t *testing.T) {
  217. vset := NewValidatorSet([]*Validator{
  218. newValidator([]byte("a"), 1),
  219. newValidator([]byte("b"), 1),
  220. newValidator([]byte("c"), 1),
  221. newValidator([]byte("d"), 1),
  222. })
  223. proposerOrder := make([]*Validator, 4)
  224. for i := 0; i < 4; i++ {
  225. proposerOrder[i] = vset.GetProposer()
  226. vset.IncrementProposerPriority(1)
  227. }
  228. // i for the loop
  229. // j for the times
  230. // we should go in order for ever, despite some IncrementProposerPriority with times > 1
  231. var i, j int
  232. for ; i < 10000; i++ {
  233. got := vset.GetProposer().Address
  234. expected := proposerOrder[j%4].Address
  235. if !bytes.Equal(got, expected) {
  236. t.Fatalf(fmt.Sprintf("vset.Proposer (%X) does not match expected proposer (%X) for (%d, %d)", got, expected, i, j))
  237. }
  238. // serialize, deserialize, check proposer
  239. b := vset.toBytes()
  240. vset.fromBytes(b)
  241. computed := vset.GetProposer() // findGetProposer()
  242. if i != 0 {
  243. if !bytes.Equal(got, computed.Address) {
  244. t.Fatalf(
  245. fmt.Sprintf(
  246. "vset.Proposer (%X) does not match computed proposer (%X) for (%d, %d)",
  247. got,
  248. computed.Address,
  249. i,
  250. j,
  251. ),
  252. )
  253. }
  254. }
  255. // times is usually 1
  256. times := 1
  257. mod := (tmrand.Int() % 5) + 1
  258. if tmrand.Int()%mod > 0 {
  259. // sometimes its up to 5
  260. times = (tmrand.Int() % 4) + 1
  261. }
  262. vset.IncrementProposerPriority(times)
  263. j += times
  264. }
  265. }
  266. func newValidator(address []byte, power int64) *Validator {
  267. return &Validator{Address: address, VotingPower: power}
  268. }
  269. func randPubKey() crypto.PubKey {
  270. var pubKey [32]byte
  271. copy(pubKey[:], tmrand.Bytes(32))
  272. return ed25519.PubKeyEd25519(pubKey)
  273. }
  274. func randValidator(totalVotingPower int64) *Validator {
  275. // this modulo limits the ProposerPriority/VotingPower to stay in the
  276. // bounds of MaxTotalVotingPower minus the already existing voting power:
  277. val := NewValidator(randPubKey(), int64(tmrand.Uint64()%uint64(MaxTotalVotingPower-totalVotingPower)))
  278. val.ProposerPriority = tmrand.Int64() % (MaxTotalVotingPower - totalVotingPower)
  279. return val
  280. }
  281. func randValidatorSet(numValidators int) *ValidatorSet {
  282. validators := make([]*Validator, numValidators)
  283. totalVotingPower := int64(0)
  284. for i := 0; i < numValidators; i++ {
  285. validators[i] = randValidator(totalVotingPower)
  286. totalVotingPower += validators[i].VotingPower
  287. }
  288. return NewValidatorSet(validators)
  289. }
  290. func (vals *ValidatorSet) toBytes() []byte {
  291. bz, err := cdc.MarshalBinaryLengthPrefixed(vals)
  292. if err != nil {
  293. panic(err)
  294. }
  295. return bz
  296. }
  297. func (vals *ValidatorSet) fromBytes(b []byte) {
  298. err := cdc.UnmarshalBinaryLengthPrefixed(b, &vals)
  299. if err != nil {
  300. // DATA HAS BEEN CORRUPTED OR THE SPEC HAS CHANGED
  301. panic(err)
  302. }
  303. }
  304. //-------------------------------------------------------------------
  305. func TestValidatorSetTotalVotingPowerPanicsOnOverflow(t *testing.T) {
  306. // NewValidatorSet calls IncrementProposerPriority which calls TotalVotingPower()
  307. // which should panic on overflows:
  308. shouldPanic := func() {
  309. NewValidatorSet([]*Validator{
  310. {Address: []byte("a"), VotingPower: math.MaxInt64, ProposerPriority: 0},
  311. {Address: []byte("b"), VotingPower: math.MaxInt64, ProposerPriority: 0},
  312. {Address: []byte("c"), VotingPower: math.MaxInt64, ProposerPriority: 0},
  313. })
  314. }
  315. assert.Panics(t, shouldPanic)
  316. }
  317. func TestAvgProposerPriority(t *testing.T) {
  318. // Create Validator set without calling IncrementProposerPriority:
  319. tcs := []struct {
  320. vs ValidatorSet
  321. want int64
  322. }{
  323. 0: {ValidatorSet{Validators: []*Validator{{ProposerPriority: 0}, {ProposerPriority: 0}, {ProposerPriority: 0}}}, 0},
  324. 1: {
  325. ValidatorSet{
  326. Validators: []*Validator{{ProposerPriority: math.MaxInt64}, {ProposerPriority: 0}, {ProposerPriority: 0}},
  327. }, math.MaxInt64 / 3,
  328. },
  329. 2: {
  330. ValidatorSet{
  331. Validators: []*Validator{{ProposerPriority: math.MaxInt64}, {ProposerPriority: 0}},
  332. }, math.MaxInt64 / 2,
  333. },
  334. 3: {
  335. ValidatorSet{
  336. Validators: []*Validator{{ProposerPriority: math.MaxInt64}, {ProposerPriority: math.MaxInt64}},
  337. }, math.MaxInt64,
  338. },
  339. 4: {
  340. ValidatorSet{
  341. Validators: []*Validator{{ProposerPriority: math.MinInt64}, {ProposerPriority: math.MinInt64}},
  342. }, math.MinInt64,
  343. },
  344. }
  345. for i, tc := range tcs {
  346. got := tc.vs.computeAvgProposerPriority()
  347. assert.Equal(t, tc.want, got, "test case: %v", i)
  348. }
  349. }
  350. func TestAveragingInIncrementProposerPriority(t *testing.T) {
  351. // Test that the averaging works as expected inside of IncrementProposerPriority.
  352. // Each validator comes with zero voting power which simplifies reasoning about
  353. // the expected ProposerPriority.
  354. tcs := []struct {
  355. vs ValidatorSet
  356. times int
  357. avg int64
  358. }{
  359. 0: {ValidatorSet{
  360. Validators: []*Validator{
  361. {Address: []byte("a"), ProposerPriority: 1},
  362. {Address: []byte("b"), ProposerPriority: 2},
  363. {Address: []byte("c"), ProposerPriority: 3}}},
  364. 1, 2},
  365. 1: {ValidatorSet{
  366. Validators: []*Validator{
  367. {Address: []byte("a"), ProposerPriority: 10},
  368. {Address: []byte("b"), ProposerPriority: -10},
  369. {Address: []byte("c"), ProposerPriority: 1}}},
  370. // this should average twice but the average should be 0 after the first iteration
  371. // (voting power is 0 -> no changes)
  372. 11, 1 / 3},
  373. 2: {ValidatorSet{
  374. Validators: []*Validator{
  375. {Address: []byte("a"), ProposerPriority: 100},
  376. {Address: []byte("b"), ProposerPriority: -10},
  377. {Address: []byte("c"), ProposerPriority: 1}}},
  378. 1, 91 / 3},
  379. }
  380. for i, tc := range tcs {
  381. // work on copy to have the old ProposerPriorities:
  382. newVset := tc.vs.CopyIncrementProposerPriority(tc.times)
  383. for _, val := range tc.vs.Validators {
  384. _, updatedVal := newVset.GetByAddress(val.Address)
  385. assert.Equal(t, updatedVal.ProposerPriority, val.ProposerPriority-tc.avg, "test case: %v", i)
  386. }
  387. }
  388. }
  389. func TestAveragingInIncrementProposerPriorityWithVotingPower(t *testing.T) {
  390. // Other than TestAveragingInIncrementProposerPriority this is a more complete test showing
  391. // how each ProposerPriority changes in relation to the validator's voting power respectively.
  392. // average is zero in each round:
  393. vp0 := int64(10)
  394. vp1 := int64(1)
  395. vp2 := int64(1)
  396. total := vp0 + vp1 + vp2
  397. avg := (vp0 + vp1 + vp2 - total) / 3
  398. vals := ValidatorSet{Validators: []*Validator{
  399. {Address: []byte{0}, ProposerPriority: 0, VotingPower: vp0},
  400. {Address: []byte{1}, ProposerPriority: 0, VotingPower: vp1},
  401. {Address: []byte{2}, ProposerPriority: 0, VotingPower: vp2}}}
  402. tcs := []struct {
  403. vals *ValidatorSet
  404. wantProposerPrioritys []int64
  405. times int
  406. wantProposer *Validator
  407. }{
  408. 0: {
  409. vals.Copy(),
  410. []int64{
  411. // Acumm+VotingPower-Avg:
  412. 0 + vp0 - total - avg, // mostest will be subtracted by total voting power (12)
  413. 0 + vp1,
  414. 0 + vp2},
  415. 1,
  416. vals.Validators[0]},
  417. 1: {
  418. vals.Copy(),
  419. []int64{
  420. (0 + vp0 - total) + vp0 - total - avg, // this will be mostest on 2nd iter, too
  421. (0 + vp1) + vp1,
  422. (0 + vp2) + vp2},
  423. 2,
  424. vals.Validators[0]}, // increment twice -> expect average to be subtracted twice
  425. 2: {
  426. vals.Copy(),
  427. []int64{
  428. 0 + 3*(vp0-total) - avg, // still mostest
  429. 0 + 3*vp1,
  430. 0 + 3*vp2},
  431. 3,
  432. vals.Validators[0]},
  433. 3: {
  434. vals.Copy(),
  435. []int64{
  436. 0 + 4*(vp0-total), // still mostest
  437. 0 + 4*vp1,
  438. 0 + 4*vp2},
  439. 4,
  440. vals.Validators[0]},
  441. 4: {
  442. vals.Copy(),
  443. []int64{
  444. 0 + 4*(vp0-total) + vp0, // 4 iters was mostest
  445. 0 + 5*vp1 - total, // now this val is mostest for the 1st time (hence -12==totalVotingPower)
  446. 0 + 5*vp2},
  447. 5,
  448. vals.Validators[1]},
  449. 5: {
  450. vals.Copy(),
  451. []int64{
  452. 0 + 6*vp0 - 5*total, // mostest again
  453. 0 + 6*vp1 - total, // mostest once up to here
  454. 0 + 6*vp2},
  455. 6,
  456. vals.Validators[0]},
  457. 6: {
  458. vals.Copy(),
  459. []int64{
  460. 0 + 7*vp0 - 6*total, // in 7 iters this val is mostest 6 times
  461. 0 + 7*vp1 - total, // in 7 iters this val is mostest 1 time
  462. 0 + 7*vp2},
  463. 7,
  464. vals.Validators[0]},
  465. 7: {
  466. vals.Copy(),
  467. []int64{
  468. 0 + 8*vp0 - 7*total, // mostest again
  469. 0 + 8*vp1 - total,
  470. 0 + 8*vp2},
  471. 8,
  472. vals.Validators[0]},
  473. 8: {
  474. vals.Copy(),
  475. []int64{
  476. 0 + 9*vp0 - 7*total,
  477. 0 + 9*vp1 - total,
  478. 0 + 9*vp2 - total}, // mostest
  479. 9,
  480. vals.Validators[2]},
  481. 9: {
  482. vals.Copy(),
  483. []int64{
  484. 0 + 10*vp0 - 8*total, // after 10 iters this is mostest again
  485. 0 + 10*vp1 - total, // after 6 iters this val is "mostest" once and not in between
  486. 0 + 10*vp2 - total}, // in between 10 iters this val is "mostest" once
  487. 10,
  488. vals.Validators[0]},
  489. 10: {
  490. vals.Copy(),
  491. []int64{
  492. 0 + 11*vp0 - 9*total,
  493. 0 + 11*vp1 - total, // after 6 iters this val is "mostest" once and not in between
  494. 0 + 11*vp2 - total}, // after 10 iters this val is "mostest" once
  495. 11,
  496. vals.Validators[0]},
  497. }
  498. for i, tc := range tcs {
  499. tc.vals.IncrementProposerPriority(tc.times)
  500. assert.Equal(t, tc.wantProposer.Address, tc.vals.GetProposer().Address,
  501. "test case: %v",
  502. i)
  503. for valIdx, val := range tc.vals.Validators {
  504. assert.Equal(t,
  505. tc.wantProposerPrioritys[valIdx],
  506. val.ProposerPriority,
  507. "test case: %v, validator: %v",
  508. i,
  509. valIdx)
  510. }
  511. }
  512. }
  513. func TestSafeAdd(t *testing.T) {
  514. f := func(a, b int64) bool {
  515. c, overflow := safeAdd(a, b)
  516. return overflow || (!overflow && c == a+b)
  517. }
  518. if err := quick.Check(f, nil); err != nil {
  519. t.Error(err)
  520. }
  521. }
  522. func TestSafeAddClip(t *testing.T) {
  523. assert.EqualValues(t, math.MaxInt64, safeAddClip(math.MaxInt64, 10))
  524. assert.EqualValues(t, math.MaxInt64, safeAddClip(math.MaxInt64, math.MaxInt64))
  525. assert.EqualValues(t, math.MinInt64, safeAddClip(math.MinInt64, -10))
  526. }
  527. func TestSafeSubClip(t *testing.T) {
  528. assert.EqualValues(t, math.MinInt64, safeSubClip(math.MinInt64, 10))
  529. assert.EqualValues(t, 0, safeSubClip(math.MinInt64, math.MinInt64))
  530. assert.EqualValues(t, math.MinInt64, safeSubClip(math.MinInt64, math.MaxInt64))
  531. assert.EqualValues(t, math.MaxInt64, safeSubClip(math.MaxInt64, -10))
  532. }
  533. //-------------------------------------------------------------------
  534. func TestValidatorSetVerifyCommit(t *testing.T) {
  535. privKey := ed25519.GenPrivKey()
  536. pubKey := privKey.PubKey()
  537. v1 := NewValidator(pubKey, 1000)
  538. vset := NewValidatorSet([]*Validator{v1})
  539. // good
  540. var (
  541. chainID = "mychainID"
  542. blockID = makeBlockIDRandom()
  543. height = int64(5)
  544. )
  545. vote := &Vote{
  546. ValidatorAddress: v1.Address,
  547. ValidatorIndex: 0,
  548. Height: height,
  549. Round: 0,
  550. Timestamp: tmtime.Now(),
  551. Type: PrecommitType,
  552. BlockID: blockID,
  553. }
  554. sig, err := privKey.Sign(vote.SignBytes(chainID))
  555. assert.NoError(t, err)
  556. vote.Signature = sig
  557. commit := NewCommit(vote.Height, vote.Round, blockID, []CommitSig{vote.CommitSig()})
  558. // bad
  559. var (
  560. badChainID = "notmychainID"
  561. badBlockID = BlockID{Hash: []byte("goodbye")}
  562. badHeight = height + 1
  563. badCommit = NewCommit(badHeight, 0, blockID, []CommitSig{{BlockIDFlag: BlockIDFlagAbsent}})
  564. )
  565. // test some error cases
  566. // TODO: test more cases!
  567. cases := []struct {
  568. chainID string
  569. blockID BlockID
  570. height int64
  571. commit *Commit
  572. }{
  573. {badChainID, blockID, height, commit},
  574. {chainID, badBlockID, height, commit},
  575. {chainID, blockID, badHeight, commit},
  576. {chainID, blockID, height, badCommit},
  577. }
  578. for i, c := range cases {
  579. err := vset.VerifyCommit(c.chainID, c.blockID, c.height, c.commit)
  580. assert.NotNil(t, err, i)
  581. }
  582. // test a good one
  583. err = vset.VerifyCommit(chainID, blockID, height, commit)
  584. assert.Nil(t, err)
  585. }
  586. func TestEmptySet(t *testing.T) {
  587. var valList []*Validator
  588. valSet := NewValidatorSet(valList)
  589. assert.Panics(t, func() { valSet.IncrementProposerPriority(1) })
  590. assert.Panics(t, func() { valSet.RescalePriorities(100) })
  591. assert.Panics(t, func() { valSet.shiftByAvgProposerPriority() })
  592. assert.Panics(t, func() { assert.Zero(t, computeMaxMinPriorityDiff(valSet)) })
  593. valSet.GetProposer()
  594. // Add to empty set
  595. v1 := newValidator([]byte("v1"), 100)
  596. v2 := newValidator([]byte("v2"), 100)
  597. valList = []*Validator{v1, v2}
  598. assert.NoError(t, valSet.UpdateWithChangeSet(valList))
  599. verifyValidatorSet(t, valSet)
  600. // Delete all validators from set
  601. v1 = newValidator([]byte("v1"), 0)
  602. v2 = newValidator([]byte("v2"), 0)
  603. delList := []*Validator{v1, v2}
  604. assert.Error(t, valSet.UpdateWithChangeSet(delList))
  605. // Attempt delete from empty set
  606. assert.Error(t, valSet.UpdateWithChangeSet(delList))
  607. }
  608. func TestUpdatesForNewValidatorSet(t *testing.T) {
  609. v1 := newValidator([]byte("v1"), 100)
  610. v2 := newValidator([]byte("v2"), 100)
  611. valList := []*Validator{v1, v2}
  612. valSet := NewValidatorSet(valList)
  613. verifyValidatorSet(t, valSet)
  614. // Verify duplicates are caught in NewValidatorSet() and it panics
  615. v111 := newValidator([]byte("v1"), 100)
  616. v112 := newValidator([]byte("v1"), 123)
  617. v113 := newValidator([]byte("v1"), 234)
  618. valList = []*Validator{v111, v112, v113}
  619. assert.Panics(t, func() { NewValidatorSet(valList) })
  620. // Verify set including validator with voting power 0 cannot be created
  621. v1 = newValidator([]byte("v1"), 0)
  622. v2 = newValidator([]byte("v2"), 22)
  623. v3 := newValidator([]byte("v3"), 33)
  624. valList = []*Validator{v1, v2, v3}
  625. assert.Panics(t, func() { NewValidatorSet(valList) })
  626. // Verify set including validator with negative voting power cannot be created
  627. v1 = newValidator([]byte("v1"), 10)
  628. v2 = newValidator([]byte("v2"), -20)
  629. v3 = newValidator([]byte("v3"), 30)
  630. valList = []*Validator{v1, v2, v3}
  631. assert.Panics(t, func() { NewValidatorSet(valList) })
  632. }
  633. type testVal struct {
  634. name string
  635. power int64
  636. }
  637. func permutation(valList []testVal) []testVal {
  638. if len(valList) == 0 {
  639. return nil
  640. }
  641. permList := make([]testVal, len(valList))
  642. perm := tmrand.Perm(len(valList))
  643. for i, v := range perm {
  644. permList[v] = valList[i]
  645. }
  646. return permList
  647. }
  648. func createNewValidatorList(testValList []testVal) []*Validator {
  649. valList := make([]*Validator, 0, len(testValList))
  650. for _, val := range testValList {
  651. valList = append(valList, newValidator([]byte(val.name), val.power))
  652. }
  653. return valList
  654. }
  655. func createNewValidatorSet(testValList []testVal) *ValidatorSet {
  656. return NewValidatorSet(createNewValidatorList(testValList))
  657. }
  658. func valSetTotalProposerPriority(valSet *ValidatorSet) int64 {
  659. sum := int64(0)
  660. for _, val := range valSet.Validators {
  661. // mind overflow
  662. sum = safeAddClip(sum, val.ProposerPriority)
  663. }
  664. return sum
  665. }
  666. func verifyValidatorSet(t *testing.T, valSet *ValidatorSet) {
  667. // verify that the capacity and length of validators is the same
  668. assert.Equal(t, len(valSet.Validators), cap(valSet.Validators))
  669. // verify that the set's total voting power has been updated
  670. tvp := valSet.totalVotingPower
  671. valSet.updateTotalVotingPower()
  672. expectedTvp := valSet.TotalVotingPower()
  673. assert.Equal(t, expectedTvp, tvp,
  674. "expected TVP %d. Got %d, valSet=%s", expectedTvp, tvp, valSet)
  675. // verify that validator priorities are centered
  676. valsCount := int64(len(valSet.Validators))
  677. tpp := valSetTotalProposerPriority(valSet)
  678. assert.True(t, tpp < valsCount && tpp > -valsCount,
  679. "expected total priority in (-%d, %d). Got %d", valsCount, valsCount, tpp)
  680. // verify that priorities are scaled
  681. dist := computeMaxMinPriorityDiff(valSet)
  682. assert.True(t, dist <= PriorityWindowSizeFactor*tvp,
  683. "expected priority distance < %d. Got %d", PriorityWindowSizeFactor*tvp, dist)
  684. }
  685. func toTestValList(valList []*Validator) []testVal {
  686. testList := make([]testVal, len(valList))
  687. for i, val := range valList {
  688. testList[i].name = string(val.Address)
  689. testList[i].power = val.VotingPower
  690. }
  691. return testList
  692. }
  693. func testValSet(nVals int, power int64) []testVal {
  694. vals := make([]testVal, nVals)
  695. for i := 0; i < nVals; i++ {
  696. vals[i] = testVal{fmt.Sprintf("v%d", i+1), power}
  697. }
  698. return vals
  699. }
  700. type valSetErrTestCase struct {
  701. startVals []testVal
  702. updateVals []testVal
  703. }
  704. func executeValSetErrTestCase(t *testing.T, idx int, tt valSetErrTestCase) {
  705. // create a new set and apply updates, keeping copies for the checks
  706. valSet := createNewValidatorSet(tt.startVals)
  707. valSetCopy := valSet.Copy()
  708. valList := createNewValidatorList(tt.updateVals)
  709. valListCopy := validatorListCopy(valList)
  710. err := valSet.UpdateWithChangeSet(valList)
  711. // for errors check the validator set has not been changed
  712. assert.Error(t, err, "test %d", idx)
  713. assert.Equal(t, valSet, valSetCopy, "test %v", idx)
  714. // check the parameter list has not changed
  715. assert.Equal(t, valList, valListCopy, "test %v", idx)
  716. }
  717. func TestValSetUpdatesDuplicateEntries(t *testing.T) {
  718. testCases := []valSetErrTestCase{
  719. // Duplicate entries in changes
  720. { // first entry is duplicated change
  721. testValSet(2, 10),
  722. []testVal{{"v1", 11}, {"v1", 22}},
  723. },
  724. { // second entry is duplicated change
  725. testValSet(2, 10),
  726. []testVal{{"v2", 11}, {"v2", 22}},
  727. },
  728. { // change duplicates are separated by a valid change
  729. testValSet(2, 10),
  730. []testVal{{"v1", 11}, {"v2", 22}, {"v1", 12}},
  731. },
  732. { // change duplicates are separated by a valid change
  733. testValSet(3, 10),
  734. []testVal{{"v1", 11}, {"v3", 22}, {"v1", 12}},
  735. },
  736. // Duplicate entries in remove
  737. { // first entry is duplicated remove
  738. testValSet(2, 10),
  739. []testVal{{"v1", 0}, {"v1", 0}},
  740. },
  741. { // second entry is duplicated remove
  742. testValSet(2, 10),
  743. []testVal{{"v2", 0}, {"v2", 0}},
  744. },
  745. { // remove duplicates are separated by a valid remove
  746. testValSet(2, 10),
  747. []testVal{{"v1", 0}, {"v2", 0}, {"v1", 0}},
  748. },
  749. { // remove duplicates are separated by a valid remove
  750. testValSet(3, 10),
  751. []testVal{{"v1", 0}, {"v3", 0}, {"v1", 0}},
  752. },
  753. { // remove and update same val
  754. testValSet(2, 10),
  755. []testVal{{"v1", 0}, {"v2", 20}, {"v1", 30}},
  756. },
  757. { // duplicate entries in removes + changes
  758. testValSet(2, 10),
  759. []testVal{{"v1", 0}, {"v2", 20}, {"v2", 30}, {"v1", 0}},
  760. },
  761. { // duplicate entries in removes + changes
  762. testValSet(3, 10),
  763. []testVal{{"v1", 0}, {"v3", 5}, {"v2", 20}, {"v2", 30}, {"v1", 0}},
  764. },
  765. }
  766. for i, tt := range testCases {
  767. executeValSetErrTestCase(t, i, tt)
  768. }
  769. }
  770. func TestValSetUpdatesOverflows(t *testing.T) {
  771. maxVP := MaxTotalVotingPower
  772. testCases := []valSetErrTestCase{
  773. { // single update leading to overflow
  774. testValSet(2, 10),
  775. []testVal{{"v1", math.MaxInt64}},
  776. },
  777. { // single update leading to overflow
  778. testValSet(2, 10),
  779. []testVal{{"v2", math.MaxInt64}},
  780. },
  781. { // add validator leading to overflow
  782. testValSet(1, maxVP),
  783. []testVal{{"v2", math.MaxInt64}},
  784. },
  785. { // add validator leading to exceed Max
  786. testValSet(1, maxVP-1),
  787. []testVal{{"v2", 5}},
  788. },
  789. { // add validator leading to exceed Max
  790. testValSet(2, maxVP/3),
  791. []testVal{{"v3", maxVP / 2}},
  792. },
  793. { // add validator leading to exceed Max
  794. testValSet(1, maxVP),
  795. []testVal{{"v2", maxVP}},
  796. },
  797. }
  798. for i, tt := range testCases {
  799. executeValSetErrTestCase(t, i, tt)
  800. }
  801. }
  802. func TestValSetUpdatesOtherErrors(t *testing.T) {
  803. testCases := []valSetErrTestCase{
  804. { // update with negative voting power
  805. testValSet(2, 10),
  806. []testVal{{"v1", -123}},
  807. },
  808. { // update with negative voting power
  809. testValSet(2, 10),
  810. []testVal{{"v2", -123}},
  811. },
  812. { // remove non-existing validator
  813. testValSet(2, 10),
  814. []testVal{{"v3", 0}},
  815. },
  816. { // delete all validators
  817. []testVal{{"v1", 10}, {"v2", 20}, {"v3", 30}},
  818. []testVal{{"v1", 0}, {"v2", 0}, {"v3", 0}},
  819. },
  820. }
  821. for i, tt := range testCases {
  822. executeValSetErrTestCase(t, i, tt)
  823. }
  824. }
  825. func TestValSetUpdatesBasicTestsExecute(t *testing.T) {
  826. valSetUpdatesBasicTests := []struct {
  827. startVals []testVal
  828. updateVals []testVal
  829. expectedVals []testVal
  830. }{
  831. { // no changes
  832. testValSet(2, 10),
  833. []testVal{},
  834. testValSet(2, 10),
  835. },
  836. { // voting power changes
  837. testValSet(2, 10),
  838. []testVal{{"v2", 22}, {"v1", 11}},
  839. []testVal{{"v2", 22}, {"v1", 11}},
  840. },
  841. { // add new validators
  842. []testVal{{"v2", 20}, {"v1", 10}},
  843. []testVal{{"v4", 40}, {"v3", 30}},
  844. []testVal{{"v4", 40}, {"v3", 30}, {"v2", 20}, {"v1", 10}},
  845. },
  846. { // add new validator to middle
  847. []testVal{{"v3", 20}, {"v1", 10}},
  848. []testVal{{"v2", 30}},
  849. []testVal{{"v2", 30}, {"v3", 20}, {"v1", 10}},
  850. },
  851. { // add new validator to beginning
  852. []testVal{{"v3", 20}, {"v2", 10}},
  853. []testVal{{"v1", 30}},
  854. []testVal{{"v1", 30}, {"v3", 20}, {"v2", 10}},
  855. },
  856. { // delete validators
  857. []testVal{{"v3", 30}, {"v2", 20}, {"v1", 10}},
  858. []testVal{{"v2", 0}},
  859. []testVal{{"v3", 30}, {"v1", 10}},
  860. },
  861. }
  862. for i, tt := range valSetUpdatesBasicTests {
  863. // create a new set and apply updates, keeping copies for the checks
  864. valSet := createNewValidatorSet(tt.startVals)
  865. valList := createNewValidatorList(tt.updateVals)
  866. err := valSet.UpdateWithChangeSet(valList)
  867. assert.NoError(t, err, "test %d", i)
  868. valListCopy := validatorListCopy(valSet.Validators)
  869. // check that the voting power in the set's validators is not changing if the voting power
  870. // is changed in the list of validators previously passed as parameter to UpdateWithChangeSet.
  871. // this is to make sure copies of the validators are made by UpdateWithChangeSet.
  872. if len(valList) > 0 {
  873. valList[0].VotingPower++
  874. assert.Equal(t, toTestValList(valListCopy), toTestValList(valSet.Validators), "test %v", i)
  875. }
  876. // check the final validator list is as expected and the set is properly scaled and centered.
  877. assert.Equal(t, tt.expectedVals, toTestValList(valSet.Validators), "test %v", i)
  878. verifyValidatorSet(t, valSet)
  879. }
  880. }
  881. // Test that different permutations of an update give the same result.
  882. func TestValSetUpdatesOrderIndependenceTestsExecute(t *testing.T) {
  883. // startVals - initial validators to create the set with
  884. // updateVals - a sequence of updates to be applied to the set.
  885. // updateVals is shuffled a number of times during testing to check for same resulting validator set.
  886. valSetUpdatesOrderTests := []struct {
  887. startVals []testVal
  888. updateVals []testVal
  889. }{
  890. 0: { // order of changes should not matter, the final validator sets should be the same
  891. []testVal{{"v4", 40}, {"v3", 30}, {"v2", 10}, {"v1", 10}},
  892. []testVal{{"v4", 44}, {"v3", 33}, {"v2", 22}, {"v1", 11}}},
  893. 1: { // order of additions should not matter
  894. []testVal{{"v2", 20}, {"v1", 10}},
  895. []testVal{{"v3", 30}, {"v4", 40}, {"v5", 50}, {"v6", 60}}},
  896. 2: { // order of removals should not matter
  897. []testVal{{"v4", 40}, {"v3", 30}, {"v2", 20}, {"v1", 10}},
  898. []testVal{{"v1", 0}, {"v3", 0}, {"v4", 0}}},
  899. 3: { // order of mixed operations should not matter
  900. []testVal{{"v4", 40}, {"v3", 30}, {"v2", 20}, {"v1", 10}},
  901. []testVal{{"v1", 0}, {"v3", 0}, {"v2", 22}, {"v5", 50}, {"v4", 44}}},
  902. }
  903. for i, tt := range valSetUpdatesOrderTests {
  904. // create a new set and apply updates
  905. valSet := createNewValidatorSet(tt.startVals)
  906. valSetCopy := valSet.Copy()
  907. valList := createNewValidatorList(tt.updateVals)
  908. assert.NoError(t, valSetCopy.UpdateWithChangeSet(valList))
  909. // save the result as expected for next updates
  910. valSetExp := valSetCopy.Copy()
  911. // perform at most 20 permutations on the updates and call UpdateWithChangeSet()
  912. n := len(tt.updateVals)
  913. maxNumPerms := tmmath.MinInt(20, n*n)
  914. for j := 0; j < maxNumPerms; j++ {
  915. // create a copy of original set and apply a random permutation of updates
  916. valSetCopy := valSet.Copy()
  917. valList := createNewValidatorList(permutation(tt.updateVals))
  918. // check there was no error and the set is properly scaled and centered.
  919. assert.NoError(t, valSetCopy.UpdateWithChangeSet(valList),
  920. "test %v failed for permutation %v", i, valList)
  921. verifyValidatorSet(t, valSetCopy)
  922. // verify the resulting test is same as the expected
  923. assert.Equal(t, valSetCopy, valSetExp,
  924. "test %v failed for permutation %v", i, valList)
  925. }
  926. }
  927. }
  928. // This tests the private function validator_set.go:applyUpdates() function, used only for additions and changes.
  929. // Should perform a proper merge of updatedVals and startVals
  930. func TestValSetApplyUpdatesTestsExecute(t *testing.T) {
  931. valSetUpdatesBasicTests := []struct {
  932. startVals []testVal
  933. updateVals []testVal
  934. expectedVals []testVal
  935. }{
  936. // additions
  937. 0: { // prepend
  938. []testVal{{"v4", 44}, {"v5", 55}},
  939. []testVal{{"v1", 11}},
  940. []testVal{{"v1", 11}, {"v4", 44}, {"v5", 55}}},
  941. 1: { // append
  942. []testVal{{"v4", 44}, {"v5", 55}},
  943. []testVal{{"v6", 66}},
  944. []testVal{{"v4", 44}, {"v5", 55}, {"v6", 66}}},
  945. 2: { // insert
  946. []testVal{{"v4", 44}, {"v6", 66}},
  947. []testVal{{"v5", 55}},
  948. []testVal{{"v4", 44}, {"v5", 55}, {"v6", 66}}},
  949. 3: { // insert multi
  950. []testVal{{"v4", 44}, {"v6", 66}, {"v9", 99}},
  951. []testVal{{"v5", 55}, {"v7", 77}, {"v8", 88}},
  952. []testVal{{"v4", 44}, {"v5", 55}, {"v6", 66}, {"v7", 77}, {"v8", 88}, {"v9", 99}}},
  953. // changes
  954. 4: { // head
  955. []testVal{{"v1", 111}, {"v2", 22}},
  956. []testVal{{"v1", 11}},
  957. []testVal{{"v1", 11}, {"v2", 22}}},
  958. 5: { // tail
  959. []testVal{{"v1", 11}, {"v2", 222}},
  960. []testVal{{"v2", 22}},
  961. []testVal{{"v1", 11}, {"v2", 22}}},
  962. 6: { // middle
  963. []testVal{{"v1", 11}, {"v2", 222}, {"v3", 33}},
  964. []testVal{{"v2", 22}},
  965. []testVal{{"v1", 11}, {"v2", 22}, {"v3", 33}}},
  966. 7: { // multi
  967. []testVal{{"v1", 111}, {"v2", 222}, {"v3", 333}},
  968. []testVal{{"v1", 11}, {"v2", 22}, {"v3", 33}},
  969. []testVal{{"v1", 11}, {"v2", 22}, {"v3", 33}}},
  970. // additions and changes
  971. 8: {
  972. []testVal{{"v1", 111}, {"v2", 22}},
  973. []testVal{{"v1", 11}, {"v3", 33}, {"v4", 44}},
  974. []testVal{{"v1", 11}, {"v2", 22}, {"v3", 33}, {"v4", 44}}},
  975. }
  976. for i, tt := range valSetUpdatesBasicTests {
  977. // create a new validator set with the start values
  978. valSet := createNewValidatorSet(tt.startVals)
  979. // applyUpdates() with the update values
  980. valList := createNewValidatorList(tt.updateVals)
  981. valSet.applyUpdates(valList)
  982. // check the new list of validators for proper merge
  983. assert.Equal(t, toTestValList(valSet.Validators), tt.expectedVals, "test %v", i)
  984. }
  985. }
  986. type testVSetCfg struct {
  987. name string
  988. startVals []testVal
  989. deletedVals []testVal
  990. updatedVals []testVal
  991. addedVals []testVal
  992. expectedVals []testVal
  993. wantErr bool
  994. }
  995. func randTestVSetCfg(t *testing.T, nBase, nAddMax int) testVSetCfg {
  996. if nBase <= 0 || nAddMax < 0 {
  997. panic(fmt.Sprintf("bad parameters %v %v", nBase, nAddMax))
  998. }
  999. const maxPower = 1000
  1000. var nOld, nDel, nChanged, nAdd int
  1001. nOld = int(tmrand.Uint()%uint(nBase)) + 1
  1002. if nBase-nOld > 0 {
  1003. nDel = int(tmrand.Uint() % uint(nBase-nOld))
  1004. }
  1005. nChanged = nBase - nOld - nDel
  1006. if nAddMax > 0 {
  1007. nAdd = tmrand.Int()%nAddMax + 1
  1008. }
  1009. cfg := testVSetCfg{}
  1010. cfg.startVals = make([]testVal, nBase)
  1011. cfg.deletedVals = make([]testVal, nDel)
  1012. cfg.addedVals = make([]testVal, nAdd)
  1013. cfg.updatedVals = make([]testVal, nChanged)
  1014. cfg.expectedVals = make([]testVal, nBase-nDel+nAdd)
  1015. for i := 0; i < nBase; i++ {
  1016. cfg.startVals[i] = testVal{fmt.Sprintf("v%d", i), int64(tmrand.Uint()%maxPower + 1)}
  1017. if i < nOld {
  1018. cfg.expectedVals[i] = cfg.startVals[i]
  1019. }
  1020. if i >= nOld && i < nOld+nChanged {
  1021. cfg.updatedVals[i-nOld] = testVal{fmt.Sprintf("v%d", i), int64(tmrand.Uint()%maxPower + 1)}
  1022. cfg.expectedVals[i] = cfg.updatedVals[i-nOld]
  1023. }
  1024. if i >= nOld+nChanged {
  1025. cfg.deletedVals[i-nOld-nChanged] = testVal{fmt.Sprintf("v%d", i), 0}
  1026. }
  1027. }
  1028. for i := nBase; i < nBase+nAdd; i++ {
  1029. cfg.addedVals[i-nBase] = testVal{fmt.Sprintf("v%d", i), int64(tmrand.Uint()%maxPower + 1)}
  1030. cfg.expectedVals[i-nDel] = cfg.addedVals[i-nBase]
  1031. }
  1032. sort.Sort(testValsByVotingPower(cfg.startVals))
  1033. sort.Sort(testValsByVotingPower(cfg.deletedVals))
  1034. sort.Sort(testValsByVotingPower(cfg.updatedVals))
  1035. sort.Sort(testValsByVotingPower(cfg.addedVals))
  1036. sort.Sort(testValsByVotingPower(cfg.expectedVals))
  1037. return cfg
  1038. }
  1039. func applyChangesToValSet(t *testing.T, wantErr bool, valSet *ValidatorSet, valsLists ...[]testVal) {
  1040. changes := make([]testVal, 0)
  1041. for _, valsList := range valsLists {
  1042. changes = append(changes, valsList...)
  1043. }
  1044. valList := createNewValidatorList(changes)
  1045. err := valSet.UpdateWithChangeSet(valList)
  1046. assert.Equal(t, wantErr, err != nil, "got error %v", err)
  1047. }
  1048. func TestValSetUpdatePriorityOrderTests(t *testing.T) {
  1049. const nMaxElections = 5000
  1050. testCases := []testVSetCfg{
  1051. 0: { // remove high power validator, keep old equal lower power validators
  1052. startVals: []testVal{{"v3", 1000}, {"v1", 1}, {"v2", 1}},
  1053. deletedVals: []testVal{{"v3", 0}},
  1054. updatedVals: []testVal{},
  1055. addedVals: []testVal{},
  1056. expectedVals: []testVal{{"v1", 1}, {"v2", 1}},
  1057. },
  1058. 1: { // remove high power validator, keep old different power validators
  1059. startVals: []testVal{{"v3", 1000}, {"v2", 10}, {"v1", 1}},
  1060. deletedVals: []testVal{{"v3", 0}},
  1061. updatedVals: []testVal{},
  1062. addedVals: []testVal{},
  1063. expectedVals: []testVal{{"v2", 10}, {"v1", 1}},
  1064. },
  1065. 2: { // remove high power validator, add new low power validators, keep old lower power
  1066. startVals: []testVal{{"v3", 1000}, {"v2", 2}, {"v1", 1}},
  1067. deletedVals: []testVal{{"v3", 0}},
  1068. updatedVals: []testVal{{"v2", 1}},
  1069. addedVals: []testVal{{"v5", 50}, {"v4", 40}},
  1070. expectedVals: []testVal{{"v5", 50}, {"v4", 40}, {"v1", 1}, {"v2", 1}},
  1071. },
  1072. // generate a configuration with 100 validators,
  1073. // randomly select validators for updates and deletes, and
  1074. // generate 10 new validators to be added
  1075. 3: randTestVSetCfg(t, 100, 10),
  1076. 4: randTestVSetCfg(t, 1000, 100),
  1077. 5: randTestVSetCfg(t, 10, 100),
  1078. 6: randTestVSetCfg(t, 100, 1000),
  1079. 7: randTestVSetCfg(t, 1000, 1000),
  1080. 8: randTestVSetCfg(t, 10000, 1000),
  1081. 9: randTestVSetCfg(t, 1000, 10000),
  1082. }
  1083. for _, cfg := range testCases {
  1084. // create a new validator set
  1085. valSet := createNewValidatorSet(cfg.startVals)
  1086. verifyValidatorSet(t, valSet)
  1087. // run election up to nMaxElections times, apply changes and verify that the priority order is correct
  1088. verifyValSetUpdatePriorityOrder(t, valSet, cfg, nMaxElections)
  1089. }
  1090. }
  1091. func verifyValSetUpdatePriorityOrder(t *testing.T, valSet *ValidatorSet, cfg testVSetCfg, nMaxElections int) {
  1092. // Run election up to nMaxElections times, sort validators by priorities
  1093. valSet.IncrementProposerPriority(tmrand.Int()%nMaxElections + 1)
  1094. origValsPriSorted := validatorListCopy(valSet.Validators)
  1095. sort.Sort(validatorsByPriority(origValsPriSorted))
  1096. // apply the changes, get the updated validators, sort by priorities
  1097. applyChangesToValSet(t, false, valSet, cfg.addedVals, cfg.updatedVals, cfg.deletedVals)
  1098. updatedValsPriSorted := validatorListCopy(valSet.Validators)
  1099. sort.Sort(validatorsByPriority(updatedValsPriSorted))
  1100. // basic checks
  1101. assert.Equal(t, cfg.expectedVals, toTestValList(valSet.Validators))
  1102. verifyValidatorSet(t, valSet)
  1103. // verify that the added validators have the smallest priority:
  1104. // - they should be at the beginning of valListNewPriority since it is sorted by priority
  1105. if len(cfg.addedVals) > 0 {
  1106. addedValsPriSlice := updatedValsPriSorted[:len(cfg.addedVals)]
  1107. sort.Sort(ValidatorsByVotingPower(addedValsPriSlice))
  1108. assert.Equal(t, cfg.addedVals, toTestValList(addedValsPriSlice))
  1109. // - and should all have the same priority
  1110. expectedPri := addedValsPriSlice[0].ProposerPriority
  1111. for _, val := range addedValsPriSlice[1:] {
  1112. assert.Equal(t, expectedPri, val.ProposerPriority)
  1113. }
  1114. }
  1115. }
  1116. func TestValSetUpdateOverflowRelated(t *testing.T) {
  1117. testCases := []testVSetCfg{
  1118. {
  1119. name: "1 no false overflow error messages for updates",
  1120. startVals: []testVal{{"v2", MaxTotalVotingPower - 1}, {"v1", 1}},
  1121. updatedVals: []testVal{{"v1", MaxTotalVotingPower - 1}, {"v2", 1}},
  1122. expectedVals: []testVal{{"v1", MaxTotalVotingPower - 1}, {"v2", 1}},
  1123. wantErr: false,
  1124. },
  1125. {
  1126. // this test shows that it is important to apply the updates in the order of the change in power
  1127. // i.e. apply first updates with decreases in power, v2 change in this case.
  1128. name: "2 no false overflow error messages for updates",
  1129. startVals: []testVal{{"v2", MaxTotalVotingPower - 1}, {"v1", 1}},
  1130. updatedVals: []testVal{{"v1", MaxTotalVotingPower/2 - 1}, {"v2", MaxTotalVotingPower / 2}},
  1131. expectedVals: []testVal{{"v2", MaxTotalVotingPower / 2}, {"v1", MaxTotalVotingPower/2 - 1}},
  1132. wantErr: false,
  1133. },
  1134. {
  1135. name: "3 no false overflow error messages for deletes",
  1136. startVals: []testVal{{"v1", MaxTotalVotingPower - 2}, {"v2", 1}, {"v3", 1}},
  1137. deletedVals: []testVal{{"v1", 0}},
  1138. addedVals: []testVal{{"v4", MaxTotalVotingPower - 2}},
  1139. expectedVals: []testVal{{"v4", MaxTotalVotingPower - 2}, {"v2", 1}, {"v3", 1}},
  1140. wantErr: false,
  1141. },
  1142. {
  1143. name: "4 no false overflow error messages for adds, updates and deletes",
  1144. startVals: []testVal{
  1145. {"v1", MaxTotalVotingPower / 4}, {"v2", MaxTotalVotingPower / 4},
  1146. {"v3", MaxTotalVotingPower / 4}, {"v4", MaxTotalVotingPower / 4}},
  1147. deletedVals: []testVal{{"v2", 0}},
  1148. updatedVals: []testVal{
  1149. {"v1", MaxTotalVotingPower/2 - 2}, {"v3", MaxTotalVotingPower/2 - 3}, {"v4", 2}},
  1150. addedVals: []testVal{{"v5", 3}},
  1151. expectedVals: []testVal{
  1152. {"v1", MaxTotalVotingPower/2 - 2}, {"v3", MaxTotalVotingPower/2 - 3}, {"v5", 3}, {"v4", 2}},
  1153. wantErr: false,
  1154. },
  1155. {
  1156. name: "5 check panic on overflow is prevented: update 8 validators with power int64(math.MaxInt64)/8",
  1157. startVals: []testVal{
  1158. {"v1", 1}, {"v2", 1}, {"v3", 1}, {"v4", 1}, {"v5", 1},
  1159. {"v6", 1}, {"v7", 1}, {"v8", 1}, {"v9", 1}},
  1160. updatedVals: []testVal{
  1161. {"v1", MaxTotalVotingPower}, {"v2", MaxTotalVotingPower}, {"v3", MaxTotalVotingPower},
  1162. {"v4", MaxTotalVotingPower}, {"v5", MaxTotalVotingPower}, {"v6", MaxTotalVotingPower},
  1163. {"v7", MaxTotalVotingPower}, {"v8", MaxTotalVotingPower}, {"v9", 8}},
  1164. expectedVals: []testVal{
  1165. {"v1", 1}, {"v2", 1}, {"v3", 1}, {"v4", 1}, {"v5", 1},
  1166. {"v6", 1}, {"v7", 1}, {"v8", 1}, {"v9", 1}},
  1167. wantErr: true,
  1168. },
  1169. }
  1170. for _, tt := range testCases {
  1171. tt := tt
  1172. t.Run(tt.name, func(t *testing.T) {
  1173. valSet := createNewValidatorSet(tt.startVals)
  1174. verifyValidatorSet(t, valSet)
  1175. // execute update and verify returned error is as expected
  1176. applyChangesToValSet(t, tt.wantErr, valSet, tt.addedVals, tt.updatedVals, tt.deletedVals)
  1177. // verify updated validator set is as expected
  1178. assert.Equal(t, tt.expectedVals, toTestValList(valSet.Validators))
  1179. verifyValidatorSet(t, valSet)
  1180. })
  1181. }
  1182. }
  1183. func TestVerifyCommitTrusting(t *testing.T) {
  1184. var (
  1185. blockID = makeBlockIDRandom()
  1186. voteSet, originalValset, vals = randVoteSet(1, 1, PrecommitType, 6, 1)
  1187. commit, err = MakeCommit(blockID, 1, 1, voteSet, vals, time.Now())
  1188. newValSet, _ = RandValidatorSet(2, 1)
  1189. )
  1190. require.NoError(t, err)
  1191. testCases := []struct {
  1192. valSet *ValidatorSet
  1193. err bool
  1194. }{
  1195. // good
  1196. 0: {
  1197. valSet: originalValset,
  1198. err: false,
  1199. },
  1200. // bad - no overlap between validator sets
  1201. 1: {
  1202. valSet: newValSet,
  1203. err: true,
  1204. },
  1205. // good - first two are different but the rest of the same -> >1/3
  1206. 2: {
  1207. valSet: NewValidatorSet(append(newValSet.Validators, originalValset.Validators...)),
  1208. err: false,
  1209. },
  1210. }
  1211. for _, tc := range testCases {
  1212. err = tc.valSet.VerifyCommitTrusting("test_chain_id", commit,
  1213. tmmath.Fraction{Numerator: 1, Denominator: 3})
  1214. if tc.err {
  1215. assert.Error(t, err)
  1216. } else {
  1217. assert.NoError(t, err)
  1218. }
  1219. }
  1220. }
  1221. func TestVerifyCommitTrustingErrorsOnOverflow(t *testing.T) {
  1222. var (
  1223. blockID = makeBlockIDRandom()
  1224. voteSet, valSet, vals = randVoteSet(1, 1, PrecommitType, 1, MaxTotalVotingPower)
  1225. commit, err = MakeCommit(blockID, 1, 1, voteSet, vals, time.Now())
  1226. )
  1227. require.NoError(t, err)
  1228. err = valSet.VerifyCommitTrusting("test_chain_id", commit,
  1229. tmmath.Fraction{Numerator: 25, Denominator: 55})
  1230. if assert.Error(t, err) {
  1231. assert.Contains(t, err.Error(), "int64 overflow")
  1232. }
  1233. }
  1234. func TestSafeMul(t *testing.T) {
  1235. testCases := []struct {
  1236. a int64
  1237. b int64
  1238. c int64
  1239. overflow bool
  1240. }{
  1241. 0: {0, 0, 0, false},
  1242. 1: {1, 0, 0, false},
  1243. 2: {2, 3, 6, false},
  1244. 3: {2, -3, -6, false},
  1245. 4: {-2, -3, 6, false},
  1246. 5: {-2, 3, -6, false},
  1247. 6: {math.MaxInt64, 1, math.MaxInt64, false},
  1248. 7: {math.MaxInt64 / 2, 2, math.MaxInt64 - 1, false},
  1249. 8: {math.MaxInt64 / 2, 3, -1, true},
  1250. 9: {math.MaxInt64, 2, -1, true},
  1251. }
  1252. for i, tc := range testCases {
  1253. c, overflow := safeMul(tc.a, tc.b)
  1254. assert.Equal(t, tc.c, c, "#%d", i)
  1255. assert.Equal(t, tc.overflow, overflow, "#%d", i)
  1256. }
  1257. }
  1258. //---------------------
  1259. // Sort validators by priority and address
  1260. type validatorsByPriority []*Validator
  1261. func (valz validatorsByPriority) Len() int {
  1262. return len(valz)
  1263. }
  1264. func (valz validatorsByPriority) Less(i, j int) bool {
  1265. if valz[i].ProposerPriority < valz[j].ProposerPriority {
  1266. return true
  1267. }
  1268. if valz[i].ProposerPriority > valz[j].ProposerPriority {
  1269. return false
  1270. }
  1271. return bytes.Compare(valz[i].Address, valz[j].Address) < 0
  1272. }
  1273. func (valz validatorsByPriority) Swap(i, j int) {
  1274. it := valz[i]
  1275. valz[i] = valz[j]
  1276. valz[j] = it
  1277. }
  1278. //-------------------------------------
  1279. type testValsByVotingPower []testVal
  1280. func (tvals testValsByVotingPower) Len() int {
  1281. return len(tvals)
  1282. }
  1283. func (tvals testValsByVotingPower) Less(i, j int) bool {
  1284. if tvals[i].power == tvals[j].power {
  1285. return bytes.Compare([]byte(tvals[i].name), []byte(tvals[j].name)) == -1
  1286. }
  1287. return tvals[i].power > tvals[j].power
  1288. }
  1289. func (tvals testValsByVotingPower) Swap(i, j int) {
  1290. it := tvals[i]
  1291. tvals[i] = tvals[j]
  1292. tvals[j] = it
  1293. }
  1294. //-------------------------------------
  1295. // Benchmark tests
  1296. //
  1297. func BenchmarkUpdates(b *testing.B) {
  1298. const (
  1299. n = 100
  1300. m = 2000
  1301. )
  1302. // Init with n validators
  1303. vs := make([]*Validator, n)
  1304. for j := 0; j < n; j++ {
  1305. vs[j] = newValidator([]byte(fmt.Sprintf("v%d", j)), 100)
  1306. }
  1307. valSet := NewValidatorSet(vs)
  1308. l := len(valSet.Validators)
  1309. // Make m new validators
  1310. newValList := make([]*Validator, m)
  1311. for j := 0; j < m; j++ {
  1312. newValList[j] = newValidator([]byte(fmt.Sprintf("v%d", j+l)), 1000)
  1313. }
  1314. b.ResetTimer()
  1315. for i := 0; i < b.N; i++ {
  1316. // Add m validators to valSetCopy
  1317. valSetCopy := valSet.Copy()
  1318. assert.NoError(b, valSetCopy.UpdateWithChangeSet(newValList))
  1319. }
  1320. }