Skip to content

Commit

Permalink
Idea to reduce duplicate code and not break compatibility
Browse files Browse the repository at this point in the history
  • Loading branch information
martinvol committed Sep 19, 2024
1 parent 0623d31 commit 1e8abd0
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 79 deletions.
10 changes: 10 additions & 0 deletions packages/protocol/contracts-0.8/governance/Validators.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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.
Expand Down
113 changes: 34 additions & 79 deletions packages/protocol/contracts/governance/Election.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down

0 comments on commit 1e8abd0

Please sign in to comment.