diff --git a/packages/protocol/contracts-0.8/governance/Validators.sol b/packages/protocol/contracts-0.8/governance/Validators.sol index 6a8c52b1d84..d6509708322 100644 --- a/packages/protocol/contracts-0.8/governance/Validators.sol +++ b/packages/protocol/contracts-0.8/governance/Validators.sol @@ -722,6 +722,7 @@ contract Validators is address[] memory topAccounts = groups[account].members.headN(n); address[] memory topValidators = new address[](n); + // TODO remove this if if (isL2()) { return topAccounts; } else { @@ -732,6 +733,15 @@ contract Validators is } } + function getTopGroupValidatorsAccounts( + address account, + uint256 n + ) external view returns (address[] memory) { + address[] memory topAccounts = groups[account].members.headN(n); + address[] memory topValidators = new address[](n); + return topAccounts; + } + /** * @notice Returns the number of members in the provided validator groups. * @param accounts The addresses of the validator groups. diff --git a/packages/protocol/contracts/governance/Election.sol b/packages/protocol/contracts/governance/Election.sol index 14e0f5db278..4c4bf066ba2 100644 --- a/packages/protocol/contracts/governance/Election.sol +++ b/packages/protocol/contracts/governance/Election.sol @@ -797,92 +797,39 @@ contract Election is return votes.active.total; } - /** - * @notice Returns a list of elected validator signers with seats allocated to groups via the D'Hondt - * method. - * @return The list of elected validator signers. - * @dev See https://en.wikipedia.org/wiki/D%27Hondt_method#Allocation for more information. - */ function electNValidatorSigners( uint256 minElectableValidators, uint256 maxElectableValidators - ) public view onlyL1 returns (address[] memory) { - // Groups must have at least `electabilityThreshold` proportion of the total votes to be - // considered for the election. - uint256 requiredVotes = electabilityThreshold - .multiply(FixidityLib.newFixed(getTotalVotes())) - .fromFixed(); - // Only consider groups with at least `requiredVotes` but do not consider more groups than the - // max number of electable validators. - uint256 numElectionGroups = votes.total.eligible.numElementsGreaterThan( - requiredVotes, - maxElectableValidators - ); - address[] memory electionGroups = votes.total.eligible.headN(numElectionGroups); - uint256[] memory numMembers = getValidators().getGroupsNumMembers(electionGroups); - // Holds the number of members elected for each of the eligible validator groups. - uint256[] memory numMembersElected = new uint256[](electionGroups.length); - uint256 totalNumMembersElected = 0; - - uint256[] memory keys = new uint256[](electionGroups.length); - FixidityLib.Fraction[] memory votesForNextMember = new FixidityLib.Fraction[]( - electionGroups.length - ); - for (uint256 i = 0; i < electionGroups.length; i = i.add(1)) { - keys[i] = i; - votesForNextMember[i] = FixidityLib.newFixed( - votes.total.eligible.getValue(electionGroups[i]) - ); - } + ) + public + view + // TODO REMOVE THIS onlyL1 + onlyL1 + returns (address[] memory) + { + bool accounts = false; + _electNValidatorSigners(minElectableValidators, minElectableValidators, accounts); + } - // Assign a number of seats to each validator group. - while (totalNumMembersElected < maxElectableValidators && electionGroups.length > 0) { - uint256 groupIndex = keys[0]; - // All electable validators have been elected. - if (votesForNextMember[groupIndex].unwrap() == 0) break; - // All members of the group have been elected - if (numMembers[groupIndex] <= numMembersElected[groupIndex]) { - votesForNextMember[groupIndex] = FixidityLib.wrap(0); - } else { - // Elect the next member from the validator group - numMembersElected[groupIndex] = numMembersElected[groupIndex].add(1); - totalNumMembersElected = totalNumMembersElected.add(1); - // If there are already n elected members in a group, the votes for the next member - // are total votes of group divided by n+1 - votesForNextMember[groupIndex] = FixidityLib - .newFixed(votes.total.eligible.getValue(electionGroups[groupIndex])) - .divide(FixidityLib.newFixed(numMembersElected[groupIndex].add(1))); - } - Heap.heapifyDown(keys, votesForNextMember); - } - require(totalNumMembersElected >= minElectableValidators, "Not enough elected validators"); - // Grab the top validators from each group that won seats. - address[] memory electedValidators = new address[](totalNumMembersElected); - totalNumMembersElected = 0; - for (uint256 i = 0; i < electionGroups.length; i = i.add(1)) { - // We use the validating delegate if one is set. - address[] memory electedGroupValidators = getValidators().getTopGroupValidators( - electionGroups[i], - numMembersElected[i] - ); - for (uint256 j = 0; j < electedGroupValidators.length; j = j.add(1)) { - electedValidators[totalNumMembersElected] = electedGroupValidators[j]; - totalNumMembersElected = totalNumMembersElected.add(1); - } - } - return electedValidators; + function electNValidatorAccounts( + uint256 minElectableValidators, + uint256 maxElectableValidators + ) public view returns (address[] memory) { + bool accounts = true; + _electNValidatorSigners(minElectableValidators, minElectableValidators, accounts); } /** - * @notice Returns a list of elected validator accounts with seats allocated to groups via the D'Hondt + * @notice Returns a list of elected validator signers with seats allocated to groups via the D'Hondt * method. - * @return The list of elected validator accounts. + * @return The list of elected validator signers. * @dev See https://en.wikipedia.org/wiki/D%27Hondt_method#Allocation for more information. */ - function electNValidatorAccounts( + function _electNValidatorSigners( uint256 minElectableValidators, - uint256 maxElectableValidators - ) public view onlyL2 returns (address[] memory) { + uint256 maxElectableValidators, + bool accounts // accounts or signers + ) internal view returns (address[] memory) { // Groups must have at least `electabilityThreshold` proportion of the total votes to be // considered for the election. uint256 requiredVotes = electabilityThreshold @@ -937,10 +884,18 @@ contract Election is totalNumMembersElected = 0; for (uint256 i = 0; i < electionGroups.length; i = i.add(1)) { // We use the validating delegate if one is set. - address[] memory electedGroupValidators = getValidators().getTopGroupValidators( - electionGroups[i], - numMembersElected[i] - ); + address[] memory electedGroupValidators; + if (accounts) { + electedGroupValidators = getValidators().getTopGroupValidatorsAccounts( + electionGroups[i], + numMembersElected[i] + ); + } else { + electedGroupValidators = getValidators().getTopGroupValidators( + electionGroups[i], + numMembersElected[i] + ); + } for (uint256 j = 0; j < electedGroupValidators.length; j = j.add(1)) { electedValidators[totalNumMembersElected] = electedGroupValidators[j]; totalNumMembersElected = totalNumMembersElected.add(1); diff --git a/packages/protocol/contracts/governance/interfaces/IValidators.sol b/packages/protocol/contracts/governance/interfaces/IValidators.sol index af2d2e8051e..8d771efec6c 100644 --- a/packages/protocol/contracts/governance/interfaces/IValidators.sol +++ b/packages/protocol/contracts/governance/interfaces/IValidators.sol @@ -76,6 +76,7 @@ interface IValidators { returns (address[] memory, uint256, uint256, uint256, uint256[] memory, uint256, uint256); function getGroupNumMembers(address) external view returns (uint256); function getTopGroupValidators(address, uint256) external view returns (address[] memory); + function getTopGroupValidatorsAccounts(address, uint256) external view returns (address[] memory); function getGroupsNumMembers( address[] calldata accounts ) external view returns (uint256[] memory);