Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

L2 Staking and Voting #11034

Merged
merged 21 commits into from
Jun 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
b10b77a
test: proof of concept 2e2 test using anvil devchain (#11020)
arthurgousset Jun 7, 2024
2993cc1
set EpochSize on L2
soloseng Jun 7, 2024
7f54f1b
allow voting and activating
soloseng Jun 7, 2024
cbc0028
move election test contract to vote dir
soloseng Jun 7, 2024
a1ea90c
updated test to allow testing of L2 with no reward distribution
soloseng Jun 7, 2024
adb51bd
feat: add ReserveSpenderMultiSig to anvil migrations (#11028)
arthurgousset Jun 11, 2024
0822209
test: refactor foundry test directory into unit, e2e, and integration…
arthurgousset Jun 11, 2024
714c966
lint: function order
soloseng Jun 11, 2024
b06cb8f
Merge branch 'master' into soloseng/l2-voting
soloseng Jun 11, 2024
4a167fb
Soloseng/CHORE-update-workflow (#11029)
soloseng Jun 11, 2024
1748fd1
Merge branch 'master' into soloseng/l2-voting
soloseng Jun 11, 2024
8fdcad3
initial validators contract review
soloseng Jun 11, 2024
743ea3d
Remove block gas limit flag for `governance/voting` CI tests
soloseng Jun 11, 2024
7f853ea
bump version
soloseng Jun 11, 2024
ca9d29c
++ tests && format
soloseng Jun 11, 2024
9b1ca78
removed comments
soloseng Jun 11, 2024
e027260
getValidatorGroupSlashingMultiplier allowed only on L1
soloseng Jun 11, 2024
7f289e6
reverting changes to test contract size issue
soloseng Jun 12, 2024
be3c2cf
minimal changes
soloseng Jun 12, 2024
c8cbad1
Merge branch 'release/core-contracts/12' into soloseng/l2-voting
soloseng Jun 12, 2024
e3b4ccb
allow slashing multiplier reset on L2
soloseng Jun 12, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions .github/workflows/protocol_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,7 @@ jobs:
if: success() || failure()
run: |
forge test -vvv \
--match-path "test-sol/unit/governance/voting/*" \
--block-gas-limit 50000000
--match-path "test-sol/unit/governance/voting/*"

- name: Run unit tests stability
if: success() || failure()
Expand Down
18 changes: 12 additions & 6 deletions packages/protocol/contracts/common/UsingPrecompiles.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ pragma solidity ^0.5.13;

import "openzeppelin-solidity/contracts/math/SafeMath.sol";
import "../common/interfaces/ICeloVersionedContract.sol";
import "../../contracts-0.8/common/IsL2Check.sol";

contract UsingPrecompiles {
contract UsingPrecompiles is IsL2Check {
using SafeMath for uint256;

address constant TRANSFER = address(0xff - 2);
Expand All @@ -16,6 +17,7 @@ contract UsingPrecompiles {
address constant HASH_HEADER = address(0xff - 9);
address constant GET_PARENT_SEAL_BITMAP = address(0xff - 10);
address constant GET_VERIFIED_SEAL_BITMAP = address(0xff - 11);
uint256 constant DAY = 86400;

/**
* @notice calculate a * b^x for fractions a, b to `decimals` precision
Expand Down Expand Up @@ -55,11 +57,15 @@ contract UsingPrecompiles {
* @return The current epoch size in blocks.
*/
function getEpochSize() public view returns (uint256) {
bytes memory out;
bool success;
(success, out) = EPOCH_SIZE.staticcall(abi.encodePacked(true));
require(success, "error calling getEpochSize precompile");
return getUint256FromBytes(out, 0);
if (isL2()) {
return DAY.div(5);
} else {
bytes memory out;
bool success;
(success, out) = EPOCH_SIZE.staticcall(abi.encodePacked(true));
require(success, "error calling getEpochSize precompile");
return getUint256FromBytes(out, 0);
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,10 @@ import "openzeppelin-solidity/contracts/ownership/Ownable.sol";
import "../common/Initializable.sol";
import "../common/UsingPrecompiles.sol";

import "../../contracts-0.8/common/IsL2Check.sol";

/**
* @title Contract for storing blockchain parameters that can be set by governance.
*/
contract BlockchainParameters is Ownable, Initializable, UsingPrecompiles, IsL2Check {
contract BlockchainParameters is Ownable, Initializable, UsingPrecompiles {
using SafeMath for uint256;

// obsolete
Expand Down
34 changes: 12 additions & 22 deletions packages/protocol/contracts/governance/Election.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import "../common/UsingRegistry.sol";
import "../common/interfaces/ICeloVersionedContract.sol";
import "../common/libraries/Heap.sol";
import "../common/libraries/ReentrancyGuard.sol";
import "../../contracts-0.8/common/IsL2Check.sol";

contract Election is
IElection,
Expand All @@ -25,8 +24,7 @@ contract Election is
Initializable,
UsingRegistry,
UsingPrecompiles,
CalledByVm,
IsL2Check
CalledByVm
{
using AddressSortedLinkedList for SortedLinkedList.List;
using FixidityLib for FixidityLib.Fraction;
Expand Down Expand Up @@ -198,7 +196,7 @@ contract Election is
uint256 value,
address lesser,
address greater
) external nonReentrant onlyL1 returns (bool) {
) external nonReentrant returns (bool) {
require(votes.total.eligible.contains(group), "Group not eligible");
require(0 < value, "Vote value cannot be zero");
require(canReceiveVotes(group, value), "Group cannot receive votes");
Expand Down Expand Up @@ -231,7 +229,7 @@ contract Election is
* @return True upon success.
* @dev Pending votes cannot be activated until an election has been held.
*/
function activate(address group) external nonReentrant onlyL1 returns (bool) {
function activate(address group) external nonReentrant returns (bool) {
address account = getAccounts().voteSignerToAccount(msg.sender);
return _activate(group, account);
}
Expand All @@ -243,10 +241,7 @@ contract Election is
* @return True upon success.
* @dev Pending votes cannot be activated until an election has been held.
*/
function activateForAccount(
address group,
address account
) external nonReentrant onlyL1 returns (bool) {
function activateForAccount(address group, address account) external nonReentrant returns (bool) {
return _activate(group, account);
}

Expand Down Expand Up @@ -369,7 +364,7 @@ contract Election is
address group,
address lesser,
address greater
) external onlyL1 onlyRegisteredContract(VALIDATORS_REGISTRY_ID) {
) external onlyRegisteredContract(VALIDATORS_REGISTRY_ID) {
uint256 value = getTotalVotesForGroup(group);
votes.total.eligible.insert(group, value, lesser, greater);
emit ValidatorGroupMarkedEligible(group);
Expand Down Expand Up @@ -544,7 +539,7 @@ contract Election is
address group,
uint256 totalEpochRewards,
uint256[] calldata uptimes
) external view returns (uint256) {
) external view onlyL1 returns (uint256) {
IValidators validators = getValidators();
// The group must meet the balance requirements for their voters to receive epoch rewards.
if (!validators.meetsAccountLockedGoldRequirements(group) || votes.active.total <= 0) {
Expand Down Expand Up @@ -577,10 +572,7 @@ contract Election is
* @return Whether or not `account` has activatable votes for `group`.
* @dev Pending votes cannot be activated until an election has been held.
*/
function hasActivatablePendingVotes(
address account,
address group
) external view onlyL1 returns (bool) {
function hasActivatablePendingVotes(address account, address group) external view returns (bool) {
PendingVote storage pendingVote = votes.pending.forGroup[group].byAccount[account];
return pendingVote.epoch < getEpochNumber() && pendingVote.value > 0;
}
Expand Down Expand Up @@ -619,7 +611,7 @@ contract Election is
* @param max The maximum number of validators that can be elected.
* @return True upon success.
*/
function setElectableValidators(uint256 min, uint256 max) public onlyOwner onlyL1 returns (bool) {
function setElectableValidators(uint256 min, uint256 max) public onlyOwner returns (bool) {
require(0 < min, "Minimum electable validators cannot be zero");
require(min <= max, "Maximum electable validators cannot be smaller than minimum");
require(
Expand All @@ -636,9 +628,7 @@ contract Election is
* @param _maxNumGroupsVotedFor The maximum number of groups an account can vote for.
* @return True upon success.
*/
function setMaxNumGroupsVotedFor(
uint256 _maxNumGroupsVotedFor
) public onlyOwner onlyL1 returns (bool) {
function setMaxNumGroupsVotedFor(uint256 _maxNumGroupsVotedFor) public onlyOwner returns (bool) {
require(_maxNumGroupsVotedFor != maxNumGroupsVotedFor, "Max groups voted for not changed");
maxNumGroupsVotedFor = _maxNumGroupsVotedFor;
emit MaxNumGroupsVotedForSet(_maxNumGroupsVotedFor);
Expand All @@ -650,7 +640,7 @@ contract Election is
* @param threshold Electability threshold as unwrapped Fraction.
* @return True upon success.
*/
function setElectabilityThreshold(uint256 threshold) public onlyOwner onlyL1 returns (bool) {
function setElectabilityThreshold(uint256 threshold) public onlyOwner returns (bool) {
electabilityThreshold = FixidityLib.wrap(threshold);
require(
electabilityThreshold.lt(FixidityLib.fixed1()),
Expand Down Expand Up @@ -681,7 +671,7 @@ contract Election is
* If not run, voting power of account will not reflect rewards awarded.
* @param flag The on/off flag.
*/
function setAllowedToVoteOverMaxNumberOfGroups(bool flag) public onlyL1 {
function setAllowedToVoteOverMaxNumberOfGroups(bool flag) public {
address account = getAccounts().voteSignerToAccount(msg.sender);
IValidators validators = getValidators();
require(
Expand Down Expand Up @@ -822,7 +812,7 @@ contract Election is
* @notice Returns get current validator signers using the precompiles.
* @return List of current validator signers.
*/
function getCurrentValidatorSigners() public view returns (address[] memory) {
function getCurrentValidatorSigners() public view onlyL1 returns (address[] memory) {
uint256 n = numberValidatorsInCurrentSet();
address[] memory res = new address[](n);
for (uint256 i = 0; i < n; i = i.add(1)) {
Expand Down
4 changes: 1 addition & 3 deletions packages/protocol/contracts/governance/EpochRewards.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import "../common/Initializable.sol";
import "../common/UsingRegistry.sol";
import "../common/UsingPrecompiles.sol";
import "../common/interfaces/ICeloVersionedContract.sol";
import "../../contracts-0.8/common/IsL2Check.sol";

/**
* @title Contract for calculating epoch rewards.
Expand All @@ -22,8 +21,7 @@ contract EpochRewards is
UsingPrecompiles,
UsingRegistry,
Freezable,
CalledByVm,
IsL2Check
CalledByVm
{
using FixidityLib for FixidityLib.Fraction;
using SafeMath for uint256;
Expand Down
2 changes: 1 addition & 1 deletion packages/protocol/contracts/governance/Governance.sol
Original file line number Diff line number Diff line change
Expand Up @@ -941,7 +941,7 @@ contract Governance is
* @return Patch version of the contract.
*/
function getVersionNumber() external pure returns (uint256, uint256, uint256, uint256) {
return (1, 4, 1, 1);
return (1, 4, 2, 0);
}

/**
Expand Down
3 changes: 1 addition & 2 deletions packages/protocol/contracts/governance/SlasherUtil.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,8 @@ import "../common/Initializable.sol";
import "../common/UsingRegistry.sol";
import "../common/UsingPrecompiles.sol";
import "../common/interfaces/ICeloVersionedContract.sol";
import "../../contracts-0.8/common/IsL2Check.sol";

contract SlasherUtil is Ownable, Initializable, UsingRegistry, UsingPrecompiles, IsL2Check {
contract SlasherUtil is Ownable, Initializable, UsingRegistry, UsingPrecompiles {
using SafeMath for uint256;

struct SlashingIncentives {
Expand Down
10 changes: 3 additions & 7 deletions packages/protocol/contracts/governance/Validators.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import "../common/UsingRegistry.sol";
import "../common/UsingPrecompiles.sol";
import "../common/interfaces/ICeloVersionedContract.sol";
import "../common/libraries/ReentrancyGuard.sol";
import "../../contracts-0.8/common/IsL2Check.sol";

/**
* @title A contract for registering and electing Validator Groups and Validators.
Expand All @@ -28,8 +27,7 @@ contract Validators is
Initializable,
UsingRegistry,
UsingPrecompiles,
CalledByVm,
IsL2Check
CalledByVm
{
using FixidityLib for FixidityLib.Fraction;
using AddressLinkedList for LinkedList.List;
Expand Down Expand Up @@ -531,7 +529,6 @@ contract Validators is
address lesserMember,
address greaterMember
) external nonReentrant returns (bool) {
allowOnlyL1();
address account = getAccounts().validatorSignerToAccount(msg.sender);
require(isValidatorGroup(account), "Not a group");
require(isValidator(validator), "Not a validator");
Expand Down Expand Up @@ -560,6 +557,7 @@ contract Validators is
group.nextCommissionBlock = block.number.add(commissionUpdateDelay);
emit ValidatorGroupCommissionUpdateQueued(account, commission, group.nextCommissionBlock);
}

/**
* @notice Updates a validator group's commission based on the previously queued update
*/
Expand All @@ -583,7 +581,6 @@ contract Validators is
* @param validatorAccount The validator to deaffiliate from their affiliated validator group.
*/
function forceDeaffiliateIfValidator(address validatorAccount) external nonReentrant onlySlasher {
allowOnlyL1();
if (isValidator(validatorAccount)) {
Validator storage validator = validators[validatorAccount];
if (validator.affiliation != address(0)) {
Expand All @@ -597,7 +594,6 @@ contract Validators is
* the last time the group was slashed.
*/
function resetSlashingMultiplier() external nonReentrant {
soloseng marked this conversation as resolved.
Show resolved Hide resolved
allowOnlyL1();
address account = getAccounts().validatorSignerToAccount(msg.sender);
require(isValidatorGroup(account), "Not a validator group");
ValidatorGroup storage group = groups[account];
Expand Down Expand Up @@ -755,7 +751,6 @@ contract Validators is
* @param account The group to fetch slashing multiplier for.
*/
function getValidatorGroupSlashingMultiplier(address account) external view returns (uint256) {
soloseng marked this conversation as resolved.
Show resolved Hide resolved
allowOnlyL1();
require(isValidatorGroup(account), "Not a validator group");
ValidatorGroup storage group = groups[account];
return group.slashInfo.multiplier.unwrap();
Expand Down Expand Up @@ -1032,6 +1027,7 @@ contract Validators is
* @return Fixidity representation of the epoch score between 0 and 1.
*/
function calculateEpochScore(uint256 uptime) public view returns (uint256) {
allowOnlyL1();
require(uptime <= FixidityLib.fixed1().unwrap(), "Uptime cannot be larger than one");
uint256 numerator;
uint256 denominator;
Expand Down
4 changes: 1 addition & 3 deletions packages/protocol/contracts/identity/Random.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import "../common/CalledByVm.sol";
import "../common/Initializable.sol";
import "../common/UsingPrecompiles.sol";
import "../common/interfaces/ICeloVersionedContract.sol";
import "../../contracts-0.8/common/IsL2Check.sol";

/**
* @title Provides randomness for verifier selection
Expand All @@ -19,8 +18,7 @@ contract Random is
Ownable,
Initializable,
UsingPrecompiles,
CalledByVm,
IsL2Check
CalledByVm
{
using SafeMath for uint256;

Expand Down
Loading
Loading