From eb67479359a550d0b550e676a4b1020a9b8ba86d Mon Sep 17 00:00:00 2001 From: pahor167 Date: Thu, 25 Apr 2024 15:57:33 +0200 Subject: [PATCH 01/19] L2 Experimentall Validators --- .../contracts-0.8/common/IsL2Check.sol | 20 +- .../protocol/contracts/common/Accounts.sol | 6 +- .../contracts/governance/Election.sol | 22 +- .../contracts/governance/Validators.sol | 47 ++-- .../protocol/test-sol/common/Accounts.t.sol | 14 ++ .../protocol/test-sol/common/IsL2Check.t.sol | 8 +- .../governance/validators/Validators.t.sol | 235 +++++++++++++++++- .../protocol/test-sol/voting/Election.t.sol | 82 ++++++ 8 files changed, 394 insertions(+), 40 deletions(-) diff --git a/packages/protocol/contracts-0.8/common/IsL2Check.sol b/packages/protocol/contracts-0.8/common/IsL2Check.sol index 31872234479..e192cf6d38c 100644 --- a/packages/protocol/contracts-0.8/common/IsL2Check.sol +++ b/packages/protocol/contracts-0.8/common/IsL2Check.sol @@ -1,4 +1,4 @@ -pragma solidity >=0.8.0 <0.8.20; +pragma solidity >=0.5.13 <0.8.20; /** * @title Based on predeploy returns whether this is L1 or L2. @@ -7,17 +7,25 @@ contract IsL2Check { address constant proxyAdminAddress = 0x4200000000000000000000000000000000000018; modifier onlyL1() { - if (IsL2()) { + if (isL2()) { revert("This method is not supported in L2 anymore."); } _; } - function IsL2() public view returns (bool) { - return address(proxyAdminAddress).code.length > 0; + function isL2() public view returns (bool) { + return isContract(proxyAdminAddress); } - function IsL1() public view returns (bool) { - return !IsL2(); + function isL1() public view returns (bool) { + return !isL2(); + } + + function isContract(address _addr) private view returns (bool) { + uint32 size; + assembly { + size := extcodesize(_addr) + } + return (size > 0); } } diff --git a/packages/protocol/contracts/common/Accounts.sol b/packages/protocol/contracts/common/Accounts.sol index 5158f6574fe..1a5733b0c60 100644 --- a/packages/protocol/contracts/common/Accounts.sol +++ b/packages/protocol/contracts/common/Accounts.sol @@ -11,6 +11,7 @@ import "../common/interfaces/ICeloVersionedContract.sol"; import "../common/Signatures.sol"; import "../common/UsingRegistry.sol"; import "../common/libraries/ReentrancyGuard.sol"; +import "../../contracts-0.8/common/IsL2Check.sol"; contract Accounts is IAccounts, @@ -18,7 +19,8 @@ contract Accounts is Ownable, ReentrancyGuard, Initializable, - UsingRegistry + UsingRegistry, + IsL2Check { using FixidityLib for FixidityLib.Fraction; using SafeMath for uint256; @@ -584,7 +586,7 @@ contract Accounts is * be greater than 1. * @dev Use `deletePaymentDelegation` to unset the payment delegation. */ - function setPaymentDelegation(address beneficiary, uint256 fraction) public { + function setPaymentDelegation(address beneficiary, uint256 fraction) public onlyL1 { require(isAccount(msg.sender), "Must first register address with Account.createAccount"); require(beneficiary != address(0), "Beneficiary cannot be address 0x0"); FixidityLib.Fraction memory f = FixidityLib.wrap(fraction); diff --git a/packages/protocol/contracts/governance/Election.sol b/packages/protocol/contracts/governance/Election.sol index ebb616d983c..ea16aa05093 100644 --- a/packages/protocol/contracts/governance/Election.sol +++ b/packages/protocol/contracts/governance/Election.sol @@ -15,6 +15,7 @@ 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, @@ -24,7 +25,8 @@ contract Election is Initializable, UsingRegistry, UsingPrecompiles, - CalledByVm + CalledByVm, + IsL2Check { using AddressSortedLinkedList for SortedLinkedList.List; using FixidityLib for FixidityLib.Fraction; @@ -194,6 +196,7 @@ contract Election is function vote(address group, uint256 value, address lesser, address greater) external nonReentrant + onlyL1 returns (bool) { require(votes.total.eligible.contains(group), "Group not eligible"); @@ -228,7 +231,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 returns (bool) { + function activate(address group) external nonReentrant onlyL1 returns (bool) { address account = getAccounts().voteSignerToAccount(msg.sender); return _activate(group, account); } @@ -240,7 +243,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 returns (bool) { + function activateForAccount(address group, address account) external nonReentrant onlyL1 returns (bool) { return _activate(group, account); } @@ -334,6 +337,7 @@ contract Election is function distributeEpochRewards(address group, uint256 value, address lesser, address greater) external onlyVm + onlyL1 { _distributeEpochRewards(group, value, lesser, greater); } @@ -359,6 +363,7 @@ contract Election is */ function markGroupEligible(address group, address lesser, address greater) external + onlyL1 onlyRegisteredContract(VALIDATORS_REGISTRY_ID) { uint256 value = getTotalVotesForGroup(group); @@ -569,7 +574,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 returns (bool) { + function hasActivatablePendingVotes(address account, address group) external view onlyL1 returns (bool) { PendingVote storage pendingVote = votes.pending.forGroup[group].byAccount[account]; return pendingVote.epoch < getEpochNumber() && pendingVote.value > 0; } @@ -608,7 +613,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 returns (bool) { + function setElectableValidators(uint256 min, uint256 max) public onlyOwner onlyL1 returns (bool) { require(0 < min, "Minimum electable validators cannot be zero"); require(min <= max, "Maximum electable validators cannot be smaller than minimum"); require( @@ -625,7 +630,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 returns (bool) { + function setMaxNumGroupsVotedFor(uint256 _maxNumGroupsVotedFor) public onlyOwner onlyL1 returns (bool) { require(_maxNumGroupsVotedFor != maxNumGroupsVotedFor, "Max groups voted for not changed"); maxNumGroupsVotedFor = _maxNumGroupsVotedFor; emit MaxNumGroupsVotedForSet(_maxNumGroupsVotedFor); @@ -637,7 +642,7 @@ contract Election is * @param threshold Electability threshold as unwrapped Fraction. * @return True upon success. */ - function setElectabilityThreshold(uint256 threshold) public onlyOwner returns (bool) { + function setElectabilityThreshold(uint256 threshold) public onlyOwner onlyL1 returns (bool) { electabilityThreshold = FixidityLib.wrap(threshold); require( electabilityThreshold.lt(FixidityLib.fixed1()), @@ -667,7 +672,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 { + function setAllowedToVoteOverMaxNumberOfGroups(bool flag) public onlyL1 { address account = getAccounts().voteSignerToAccount(msg.sender); IValidators validators = getValidators(); require( @@ -897,6 +902,7 @@ contract Election is */ function _distributeEpochRewards(address group, uint256 value, address lesser, address greater) internal + onlyL1 { if (votes.total.eligible.contains(group)) { uint256 newVoteTotal = votes.total.eligible.getValue(group).add(value); diff --git a/packages/protocol/contracts/governance/Validators.sol b/packages/protocol/contracts/governance/Validators.sol index e26f3738d6a..d5328c53a78 100644 --- a/packages/protocol/contracts/governance/Validators.sol +++ b/packages/protocol/contracts/governance/Validators.sol @@ -15,6 +15,7 @@ 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. @@ -27,7 +28,8 @@ contract Validators is Initializable, UsingRegistry, UsingPrecompiles, - CalledByVm + CalledByVm, + IsL2Check { using FixidityLib for FixidityLib.Fraction; using AddressLinkedList for LinkedList.List; @@ -211,7 +213,7 @@ contract Validators is * @param uptime The Fixidity representation of the validator's uptime, between 0 and 1. * @return True upon success. */ - function updateValidatorScoreFromSigner(address signer, uint256 uptime) external onlyVm() { + function updateValidatorScoreFromSigner(address signer, uint256 uptime) external onlyVm() onlyL1 { _updateValidatorScoreFromSigner(signer, uptime); } @@ -225,6 +227,7 @@ contract Validators is function distributeEpochPaymentsFromSigner(address signer, uint256 maxPayment) external onlyVm() + onlyL1 returns (uint256) { return _distributeEpochPaymentsFromSigner(signer, maxPayment); @@ -246,7 +249,7 @@ contract Validators is bytes calldata ecdsaPublicKey, bytes calldata blsPublicKey, bytes calldata blsPop - ) external nonReentrant returns (bool) { + ) external nonReentrant onlyL1 returns (bool) { address account = getAccounts().validatorSignerToAccount(msg.sender); _isRegistrationAllowed(account); require(!isValidator(account) && !isValidatorGroup(account), "Already registered"); @@ -306,7 +309,7 @@ contract Validators is * @return True upon success. * @dev De-affiliates with the previously affiliated group if present. */ - function affiliate(address group) external nonReentrant returns (bool) { + function affiliate(address group) external nonReentrant onlyL1 returns (bool) { address account = getAccounts().validatorSignerToAccount(msg.sender); require(isValidator(account), "Not a validator"); require(isValidatorGroup(group), "Not a validator group"); @@ -345,6 +348,7 @@ contract Validators is */ function updateBlsPublicKey(bytes calldata blsPublicKey, bytes calldata blsPop) external + onlyL1 returns (bool) { address account = getAccounts().validatorSignerToAccount(msg.sender); @@ -367,6 +371,7 @@ contract Validators is function updateEcdsaPublicKey(address account, address signer, bytes calldata ecdsaPublicKey) external onlyRegisteredContract(ACCOUNTS_REGISTRY_ID) + onlyL1 returns (bool) { require(isValidator(account), "Not a validator"); @@ -421,7 +426,7 @@ contract Validators is bytes calldata ecdsaPublicKey, bytes calldata blsPublicKey, bytes calldata blsPop - ) external onlyRegisteredContract(ACCOUNTS_REGISTRY_ID) returns (bool) { + ) external onlyRegisteredContract(ACCOUNTS_REGISTRY_ID) onlyL1 returns (bool) { require(isValidator(account), "Not a validator"); Validator storage validator = validators[account]; require( @@ -443,7 +448,7 @@ contract Validators is * @dev Fails if the account is already a validator or validator group. * @dev Fails if the account does not have sufficient weight. */ - function registerValidatorGroup(uint256 commission) external nonReentrant returns (bool) { + function registerValidatorGroup(uint256 commission) external nonReentrant onlyL1 returns (bool) { require(commission <= FixidityLib.fixed1().unwrap(), "Commission can't be greater than 100%"); address account = getAccounts().validatorSignerToAccount(msg.sender); _isRegistrationAllowed(account); @@ -467,7 +472,7 @@ contract Validators is * @dev Fails if `validator` has not set their affiliation to this account. * @dev Fails if the group has zero members. */ - function addMember(address validator) external nonReentrant returns (bool) { + function addMember(address validator) external nonReentrant onlyL1 returns (bool) { address account = getAccounts().validatorSignerToAccount(msg.sender); require(groups[account].members.numElements > 0, "Validator group empty"); return _addMember(account, validator, address(0), address(0)); @@ -485,6 +490,7 @@ contract Validators is function addFirstMember(address validator, address lesser, address greater) external nonReentrant + onlyL1 returns (bool) { address account = getAccounts().validatorSignerToAccount(msg.sender); @@ -517,6 +523,7 @@ contract Validators is function reorderMember(address validator, address lesserMember, address greaterMember) external nonReentrant + onlyL1 returns (bool) { address account = getAccounts().validatorSignerToAccount(msg.sender); @@ -535,7 +542,7 @@ contract Validators is * @param commission Fixidity representation of the commission this group receives on epoch * payments made to its members. Must be in the range [0, 1.0]. */ - function setNextCommissionUpdate(uint256 commission) external { + function setNextCommissionUpdate(uint256 commission) external onlyL1 { address account = getAccounts().validatorSignerToAccount(msg.sender); require(isValidatorGroup(account), "Not a validator group"); ValidatorGroup storage group = groups[account]; @@ -549,7 +556,7 @@ contract Validators is /** * @notice Updates a validator group's commission based on the previously queued update */ - function updateCommission() external { + function updateCommission() external onlyL1 { address account = getAccounts().validatorSignerToAccount(msg.sender); require(isValidatorGroup(account), "Not a validator group"); ValidatorGroup storage group = groups[account]; @@ -567,7 +574,7 @@ contract Validators is * @notice Removes a validator from the group for which it is a member. * @param validatorAccount The validator to deaffiliate from their affiliated validator group. */ - function forceDeaffiliateIfValidator(address validatorAccount) external nonReentrant onlySlasher { + function forceDeaffiliateIfValidator(address validatorAccount) external nonReentrant onlySlasher onlyL1 { if (isValidator(validatorAccount)) { Validator storage validator = validators[validatorAccount]; if (validator.affiliation != address(0)) { @@ -580,7 +587,7 @@ contract Validators is * @notice Resets a group's slashing multiplier if it has been >= the reset period since * the last time the group was slashed. */ - function resetSlashingMultiplier() external nonReentrant { + function resetSlashingMultiplier() external nonReentrant onlyL1 { address account = getAccounts().validatorSignerToAccount(msg.sender); require(isValidatorGroup(account), "Not a validator group"); ValidatorGroup storage group = groups[account]; @@ -595,7 +602,7 @@ contract Validators is * @notice Halves the group's slashing multiplier. * @param account The group being slashed. */ - function halveSlashingMultiplier(address account) external nonReentrant onlySlasher { + function halveSlashingMultiplier(address account) external nonReentrant onlySlasher onlyL1 { require(isValidatorGroup(account), "Not a validator group"); ValidatorGroup storage group = groups[account]; group.slashInfo.multiplier = FixidityLib.wrap(group.slashInfo.multiplier.unwrap().div(2)); @@ -752,7 +759,7 @@ contract Validators is * @notice Getter for a group's slashing multiplier. * @param account The group to fetch slashing multiplier for. */ - function getValidatorGroupSlashingMultiplier(address account) external view returns (uint256) { + function getValidatorGroupSlashingMultiplier(address account) external view onlyL1 returns (uint256) { require(isValidatorGroup(account), "Not a validator group"); ValidatorGroup storage group = groups[account]; return group.slashInfo.multiplier.unwrap(); @@ -768,6 +775,7 @@ contract Validators is function groupMembershipInEpoch(address account, uint256 epochNumber, uint256 index) external view + onlyL1 returns (address) { require(isValidator(account), "Not a validator"); @@ -866,7 +874,7 @@ contract Validators is * @notice Updates the block delay for a ValidatorGroup's commission udpdate * @param delay Number of blocks to delay the update */ - function setCommissionUpdateDelay(uint256 delay) public onlyOwner { + function setCommissionUpdateDelay(uint256 delay) public onlyOwner onlyL1 { require(delay != commissionUpdateDelay, "commission update delay not changed"); commissionUpdateDelay = delay; emit CommissionUpdateDelaySet(delay); @@ -877,7 +885,7 @@ contract Validators is * @param size The maximum group size. * @return True upon success. */ - function setMaxGroupSize(uint256 size) public onlyOwner returns (bool) { + function setMaxGroupSize(uint256 size) public onlyOwner onlyL1 returns (bool) { require(0 < size, "Max group size cannot be zero"); require(size != maxGroupSize, "Max group size not changed"); maxGroupSize = size; @@ -890,7 +898,7 @@ contract Validators is * @param length The number of validator group membership entries to store. * @return True upon success. */ - function setMembershipHistoryLength(uint256 length) public onlyOwner returns (bool) { + function setMembershipHistoryLength(uint256 length) public onlyOwner onlyL1 returns (bool) { require(0 < length, "Membership history length cannot be zero"); require(length != membershipHistoryLength, "Membership history length not changed"); membershipHistoryLength = length; @@ -907,6 +915,7 @@ contract Validators is function setValidatorScoreParameters(uint256 exponent, uint256 adjustmentSpeed) public onlyOwner + onlyL1 returns (bool) { require( @@ -972,7 +981,7 @@ contract Validators is * @notice Sets the slashingMultiplierRestPeriod property if called by owner. * @param value New reset period for slashing multiplier. */ - function setSlashingMultiplierResetPeriod(uint256 value) public nonReentrant onlyOwner { + function setSlashingMultiplierResetPeriod(uint256 value) public nonReentrant onlyOwner onlyL1 { slashingMultiplierResetPeriod = value; } @@ -980,7 +989,7 @@ contract Validators is * @notice Sets the downtimeGracePeriod property if called by owner. * @param value New downtime grace period for calculating epoch scores. */ - function setDowntimeGracePeriod(uint256 value) public nonReentrant onlyOwner { + function setDowntimeGracePeriod(uint256 value) public nonReentrant onlyOwner onlyL1 { downtimeGracePeriod = value; } @@ -1013,7 +1022,7 @@ contract Validators is * @param account The account whose group membership should be returned. * @return The group that `account` was a member of at the end of the last epoch. */ - function getMembershipInLastEpoch(address account) public view returns (address) { + function getMembershipInLastEpoch(address account) public view onlyL1 returns (address) { uint256 epochNumber = getEpochNumber(); MembershipHistory storage history = validators[account].membershipHistory; uint256 head = history.numEntries == 0 ? 0 : history.tail.add(history.numEntries.sub(1)); diff --git a/packages/protocol/test-sol/common/Accounts.t.sol b/packages/protocol/test-sol/common/Accounts.t.sol index 85e5fd09d4b..c795ff7dd02 100644 --- a/packages/protocol/test-sol/common/Accounts.t.sol +++ b/packages/protocol/test-sol/common/Accounts.t.sol @@ -15,6 +15,8 @@ contract AccountsTest is Test { Accounts accounts; MockValidators validators; + address constant proxyAdminAddress = 0x4200000000000000000000000000000000000018; + string constant name = "Account"; string constant metadataURL = "https://www.celo.org"; string constant otherMetadataURL = "https://clabs.co"; @@ -97,6 +99,11 @@ contract AccountsTest is Test { (caller2, caller2PK) = actorWithPK("caller2"); } + + function _whenL2() public { + deployCodeTo("Registry.sol", abi.encode(false), proxyAdminAddress); + } + function getParsedSignatureOfAddress(address _address, uint256 privateKey) public pure @@ -608,6 +615,13 @@ contract AccountsTest_setPaymentDelegation is AccountsTest { assertEq(realFraction, fraction); } + function test_Revert_SetPaymentDelegation_WhenL2() public { + _whenL2(); + accounts.createAccount(); + vm.expectRevert("This method is not supported in L2 anymore."); + accounts.setPaymentDelegation(beneficiary, fraction); + } + function test_ShouldNotAllowFractionGreaterThan1() public { accounts.createAccount(); vm.expectRevert("Fraction must not be greater than 1"); diff --git a/packages/protocol/test-sol/common/IsL2Check.t.sol b/packages/protocol/test-sol/common/IsL2Check.t.sol index 59b8c7eedcc..506b983bc3c 100644 --- a/packages/protocol/test-sol/common/IsL2Check.t.sol +++ b/packages/protocol/test-sol/common/IsL2Check.t.sol @@ -28,21 +28,21 @@ contract IsL2CheckBase is Test { contract IsL2Check_IsL2Test is IsL2CheckBase { function test_IsL2() public { - assertFalse(isL2Check.IsL2()); + assertFalse(isL2Check.isL2()); } function test_IsL1() public { - assertTrue(isL2Check.IsL1()); + assertTrue(isL2Check.isL1()); } function test_IsL2_WhenProxyAdminSet() public { helper_WhenProxyAdminAddressIsSet(); - assertTrue(isL2Check.IsL2()); + assertTrue(isL2Check.isL2()); } function test_IsL1_WhenProxyAdminSet() public { helper_WhenProxyAdminAddressIsSet(); - assertFalse(isL2Check.IsL1()); + assertFalse(isL2Check.isL1()); } } diff --git a/packages/protocol/test-sol/governance/validators/Validators.t.sol b/packages/protocol/test-sol/governance/validators/Validators.t.sol index e8c6a48fbd6..4048dc88c3f 100644 --- a/packages/protocol/test-sol/governance/validators/Validators.t.sol +++ b/packages/protocol/test-sol/governance/validators/Validators.t.sol @@ -78,6 +78,8 @@ contract ValidatorsTest is Test, Constants, Utils, ECDSAHelper { using FixidityLib for FixidityLib.Fraction; using SafeMath for uint256; + address constant proxyAdminAddress = 0x4200000000000000000000000000000000000018; + Registry registry; Accounts accounts; MockStableToken stableToken; @@ -409,6 +411,10 @@ contract ValidatorsTest is Test, Constants, Utils, ECDSAHelper { FixidityLib.wrap(originalValidatorScoreParameters.exponent) ); } + + function _whenL2() public { + deployCodeTo("Registry.sol", abi.encode(false), proxyAdminAddress); + } } contract ValidatorsTest_Initialize is ValidatorsTest { @@ -478,10 +484,22 @@ contract ValidatorsTest_Initialize is ValidatorsTest { assertEq(actual, commissionUpdateDelay, "Wrong commissionUpdateDelay."); } + function test_Reverts_setCommissionUpdateDelay_WhenL2() public { + _whenL2(); + vm.expectRevert("This method is not supported in L2 anymore."); + validators.setCommissionUpdateDelay(commissionUpdateDelay); + } + function test_shouldHaveSetDowntimeGracePeriod() public { uint256 actual = validators.downtimeGracePeriod(); assertEq(actual, downtimeGracePeriod, "Wrong downtimeGracePeriod."); } + + function test_Reverts_SetDowntimeGracePeriod_WhenL2() public { + _whenL2(); + vm.expectRevert("This method is not supported in L2 anymore."); + validators.setDowntimeGracePeriod(downtimeGracePeriod); + } } contract ValidatorsTest_SetMembershipHistoryLength is ValidatorsTest { @@ -497,6 +515,12 @@ contract ValidatorsTest_SetMembershipHistoryLength is ValidatorsTest { assertEq(validators.membershipHistoryLength(), newLength); } + function test_Reverts_SetTheMembershipHistoryLength_WhenL2() public { + _whenL2(); + vm.expectRevert("This method is not supported in L2 anymore."); + validators.setMembershipHistoryLength(newLength); + } + function test_Emits_MembershipHistoryLengthSet() public { vm.expectEmit(true, true, true, true); emit MembershipHistoryLengthSet(newLength); @@ -520,6 +544,12 @@ contract ValidatorsTest_SetMaxGroupSize is ValidatorsTest { assertEq(validators.getMaxGroupSize(), newSize, "MaxGroupSize not properly set"); } + function test_Reverts_SetMaxGroupSize_WhenL2() public { + _whenL2(); + vm.expectRevert("This method is not supported in L2 anymore."); + validators.setMaxGroupSize(newSize); + } + function test_Emits_MaxGroupSizeSet() public { vm.expectEmit(true, true, true, true); emit MaxGroupSizeSet(newSize); @@ -614,13 +644,19 @@ contract ValidatorsTest_SetValidatorScoreParameters is ValidatorsTest { event ValidatorScoreParametersSet(uint256 exponent, uint256 adjustmentSpeed); - function test_ShouldsetExponentAndAdjustmentSpeed() public { + function test_ShouldSetExponentAndAdjustmentSpeed() public { validators.setValidatorScoreParameters(newParams.exponent, newParams.adjustmentSpeed.unwrap()); (uint256 _exponent, uint256 _adjustmentSpeed) = validators.getValidatorScoreParameters(); assertEq(_exponent, newParams.exponent, "Incorrect Exponent"); assertEq(_adjustmentSpeed, newParams.adjustmentSpeed.unwrap(), "Incorrect AdjustmentSpeed"); } + function test_Reverts_SetExponentAndAdjustmentSpeed_WhenL2() public { + _whenL2(); + vm.expectRevert("This method is not supported in L2 anymore."); + validators.setValidatorScoreParameters(newParams.exponent, newParams.adjustmentSpeed.unwrap()); + } + function test_Emits_ValidatorScoreParametersSet() public { vm.expectEmit(true, true, true, true); emit ValidatorScoreParametersSet(newParams.exponent, newParams.adjustmentSpeed.unwrap()); @@ -682,6 +718,27 @@ contract ValidatorsTest_RegisterValidator is ValidatorsTest { assertTrue(validators.isValidator(validator)); } + function test_ShouldRevert_WhenInL2_WhenAccountHasAuthorizedValidatorSigner() public { + lockedGold.setAccountTotalLockedGold(validator, originalValidatorLockedGoldRequirements.value); + + (bytes memory _ecdsaPubKey, uint8 v, bytes32 r, bytes32 s) = _generateEcdsaPubKeyWithSigner( + validator, + signerPk + ); + + ph.mockSuccess(ph.PROOF_OF_POSSESSION(), abi.encodePacked(validator, blsPublicKey, blsPop)); + + vm.prank(validator); + accounts.authorizeValidatorSigner(signer, v, r, s); + + _whenL2(); + + vm.expectRevert("This method is not supported in L2 anymore."); + vm.prank(validator); + validators.registerValidator(_ecdsaPubKey, blsPublicKey, blsPop); + validatorRegistrationEpochNumber = validators.getEpochNumber(); + } + function test_ShouldAddAccountToValidatorList_WhenAccountHasAuthorizedValidatorSigner() public { address[] memory ExpectedRegisteredValidators = new address[](1); ExpectedRegisteredValidators[0] = validator; @@ -988,6 +1045,13 @@ contract ValidatorsTest_Affiliate_WhenGroupAndValidatorMeetLockedGoldRequirement assertEq(affiliation, group); } + function test_Reverts_WhenL2_WhenAffiliatingWithRegisteredValidatorGroup() public { + _whenL2(); + vm.prank(validator); + vm.expectRevert("This method is not supported in L2 anymore."); + validators.affiliate(group); + } + function test_Emits_ValidatorAffiliatedEvent() public { vm.expectEmit(true, true, true, true); emit ValidatorAffiliated(validator, group); @@ -1060,6 +1124,13 @@ contract ValidatorsTest_Affiliate_WhenValidatorIsAlreadyAffiliatedWithValidatorG assertEq(affiliation, otherGroup); } + function test_ShouldRevert_WhenL2_WhenValidatorNotMemberOfThatValidatorGroup() public { + _whenL2(); + vm.prank(validator); + vm.expectRevert("This method is not supported in L2 anymore."); + validators.affiliate(otherGroup); + } + function test_Emits_ValidatorDeaffiliatedEvent_WhenValidatorNotMemberOfThatValidatorGroup() public { @@ -1290,6 +1361,19 @@ contract ValidatorsTest_UpdateEcdsaPublicKey is ValidatorsTest { assertEq(actualEcdsaPubKey, _newEcdsaPubKey); } + function test_Reverts_SetValidatorEcdsaPubKey_WhenCalledByRegisteredAccountsContract_WhenL2() + public + { + _whenL2(); + (bytes memory _newEcdsaPubKey, , , ) = _generateEcdsaPubKeyWithSigner( + address(accounts), + signerPk + ); + vm.prank(address(accounts)); + vm.expectRevert("This method is not supported in L2 anymore."); + validators.updateEcdsaPublicKey(validator, signer, _newEcdsaPubKey); + } + function test_Emits_ValidatorEcdsaPublicKeyUpdatedEvent_WhenCalledByRegisteredAccountsContract() public { @@ -1373,6 +1457,25 @@ contract ValidatorsTest_UpdatePublicKeys is ValidatorsTest { assertEq(actualBlsPublicKey, newBlsPublicKey); } + function test_Reverts_SetValidatorNewBlsPubKeyAndEcdsaPubKey_WhenCalledByRegisteredAccountsContract_WhenL2() + public + { + _whenL2(); + (bytes memory _newEcdsaPubKey, , , ) = _generateEcdsaPubKeyWithSigner( + address(accounts), + signerPk + ); + + ph.mockSuccess( + ph.PROOF_OF_POSSESSION(), + abi.encodePacked(validator, newBlsPublicKey, newBlsPop) + ); + + vm.prank(address(accounts)); + vm.expectRevert("This method is not supported in L2 anymore."); + validators.updatePublicKeys(validator, signer, _newEcdsaPubKey, newBlsPublicKey, newBlsPop); + } + function test_Emits_ValidatorEcdsaPublicKeyUpdatedAndValidatorBlsPublicKeyUpdatedEvent_WhenCalledByRegisteredAccountsContract() public { @@ -1472,6 +1575,18 @@ contract ValidatorsTest_UpdateBlsPublicKey is ValidatorsTest { assertEq(actualBlsPublicKey, newBlsPublicKey); } + function test_Reverts_SetNewValidatorBlsPubKey_WhenL2() public { + _whenL2(); + ph.mockSuccess( + ph.PROOF_OF_POSSESSION(), + abi.encodePacked(validator, newBlsPublicKey, newBlsPop) + ); + + vm.prank(validator); + vm.expectRevert("This method is not supported in L2 anymore."); + validators.updateBlsPublicKey(newBlsPublicKey, newBlsPop); + } + function test_Emits_ValidatorValidatorBlsPublicKeyUpdatedEvent() public { ph.mockSuccess( ph.PROOF_OF_POSSESSION(), @@ -1777,6 +1892,26 @@ contract ValidatorsTest_AddMember is ValidatorsTest { assertEq(members, expectedMembersList); } + function test_Reverts_AddFirstMemberToTheList_WhenL2() public { + _whenL2(); + address[] memory expectedMembersList = new address[](1); + expectedMembersList[0] = validator; + + vm.prank(group); + vm.expectRevert("This method is not supported in L2 anymore."); + validators.addFirstMember(validator, address(0), address(0)); + } + + function test_Reverts_AddMemberToTheList_WhenL2() public { + _whenL2(); + address[] memory expectedMembersList = new address[](1); + expectedMembersList[0] = validator; + + vm.prank(group); + vm.expectRevert("This method is not supported in L2 anymore."); + validators.addMember(validator); + } + function test_ShouldUpdateGroupSizeHistory() public { vm.prank(group); validators.addFirstMember(validator, address(0), address(0)); @@ -2046,6 +2181,17 @@ contract ValidatorsTest_ReorderMember is ValidatorsTest { assertEq(expectedMembersList.length, members.length); } + function test_Reverts_ReorderGroupMemberList_WhenL2() public { + _whenL2(); + address[] memory expectedMembersList = new address[](2); + expectedMembersList[0] = vm.addr(1); + expectedMembersList[1] = validator; + + vm.prank(group); + vm.expectRevert("This method is not supported in L2 anymore."); + validators.reorderMember(vm.addr(1), validator, address(0)); + } + function test_Emits_ValidatorGroupMemberReorderedEvent() public { vm.expectEmit(true, true, true, true); emit ValidatorGroupMemberReordered(group, vm.addr(1)); @@ -2093,6 +2239,13 @@ contract ValidatorsTest_SetNextCommissionUpdate is ValidatorsTest { assertEq(_commission, commission.unwrap()); } + function test_Reverts_SetValidatorGroupCommission_WhenL2() public { + _whenL2(); + vm.prank(group); + vm.expectRevert("This method is not supported in L2 anymore."); + validators.setNextCommissionUpdate(newCommission); + } + function test_ShouldSetValidatorGroupNextCommission() public { vm.prank(group); validators.setNextCommissionUpdate(newCommission); @@ -2150,6 +2303,13 @@ contract ValidatorsTest_UpdateCommission is ValidatorsTest { assertEq(_commission, newCommission); } + function test_Reverts_SetValidatorGroupCommission_WhenL2() public { + _whenL2(); + vm.prank(group); + vm.expectRevert("This method is not supported in L2 anymore."); + validators.setNextCommissionUpdate(newCommission); + } + function test_Emits_ValidatorGroupCommissionUpdated() public { vm.prank(group); validators.setNextCommissionUpdate(newCommission); @@ -2648,6 +2808,19 @@ contract ValidatorsTest_GetMembershipInLastEpoch is ValidatorsTest { } } } + + function test_Reverts_getMembershipInLastEpoch_WhenL2() public { + blockTravel(ph.epochSize()); + + vm.prank(validator); + validators.affiliate(vm.addr(1)); + vm.prank(vm.addr(1)); + validators.addFirstMember(validator, address(0), address(0)); + + _whenL2(); + vm.expectRevert("This method is not supported in L2 anymore."); + validators.getMembershipInLastEpoch(validator); + } } contract ValidatorsTest_GetEpochSize is ValidatorsTest { @@ -2815,6 +2988,12 @@ contract ValidatorsTest_DistributeEpochPaymentsFromSigner is ValidatorsTest { validators.updateValidatorScoreFromSigner(validator, uptime.unwrap()); } + function test_Reverts_WhenL2_WhenValidatorAndGroupMeetBalanceRequirements() public { + _whenL2(); + vm.expectRevert("This method is not supported in L2 anymore."); + validators.distributeEpochPaymentsFromSigner(validator, maxPayment); + } + function test_ShouldPayValidator_WhenValidatorAndGroupMeetBalanceRequirements() public { validators.distributeEpochPaymentsFromSigner(validator, maxPayment); assertEq(stableToken.balanceOf(validator), expectedValidatorPayment); @@ -3016,6 +3195,13 @@ contract ValidatorsTest_ForceDeaffiliateIfValidator is ValidatorsTest { assertEq(affiliation, address(0)); } + function test_Reverts_WhenSenderIsWhitelistedSlashingAddress_WhenL2() public { + _whenL2(); + vm.prank(paymentDelegatee); + vm.expectRevert("This method is not supported in L2 anymore."); + validators.forceDeaffiliateIfValidator(validator); + } + function test_Reverts_WhenSenderNotApprovedAddress() public { vm.expectRevert("Only registered slasher can call"); validators.forceDeaffiliateIfValidator(validator); @@ -3096,6 +3282,29 @@ contract ValidatorsTest_GroupMembershipInEpoch is ValidatorsTest { } } + function test_Reverts_GroupMembershipInEpoch_WhenL2() public { + _whenL2(); + for (uint256 i = 0; i < epochInfoList.length; i++) { + address _group = epochInfoList[i].groupy; + + if (epochInfoList.length.sub(i) <= membershipHistoryLength) { + vm.expectRevert("This method is not supported in L2 anymore."); + validators.groupMembershipInEpoch( + validator, + epochInfoList[i].epochNumber, + uint256(1).add(i) + ); + } else { + vm.expectRevert("This method is not supported in L2 anymore."); + validators.groupMembershipInEpoch( + validator, + epochInfoList[i].epochNumber, + uint256(1).add(i) + ); + } + } + } + function test_Reverts_WhenEpochNumberAtGivenIndexIsGreaterThanProvidedEpochNumber() public { vm.expectRevert("index out of bounds"); validators.groupMembershipInEpoch( @@ -3157,6 +3366,14 @@ contract ValidatorsTest_HalveSlashingMultiplier is ValidatorsTest { } } + function test_Reverts_HalveSlashingMultiplier_WhenL2() public { + _whenL2(); + FixidityLib.Fraction memory expectedMultiplier = FixidityLib.fixed1(); + vm.prank(paymentDelegatee); + vm.expectRevert("This method is not supported in L2 anymore."); + validators.halveSlashingMultiplier(group); + } + function test_ShouldUpdateLastSlashedTimestamp() public { (, , , , , , uint256 initialLastSlashed) = validators.getValidatorGroup(group); @@ -3204,6 +3421,15 @@ contract ValidatorsTest_ResetSlashingMultiplier is ValidatorsTest { assertEq(actualMultiplier, FixidityLib.fixed1().unwrap()); } + function test_Reverts_WhenSlashingMultiplierIsResetAfterResetPeriod_WhenL2() public { + _whenL2(); + timeTravel(slashingMultiplierResetPeriod); + + vm.prank(group); + vm.expectRevert("This method is not supported in L2 anymore."); + validators.resetSlashingMultiplier(); + } + function test_Reverts_WhenSlashingMultiplierIsResetBeforeResetPeriod() public { vm.expectRevert("`resetSlashingMultiplier` called before resetPeriod expired"); vm.prank(group); @@ -3219,4 +3445,11 @@ contract ValidatorsTest_ResetSlashingMultiplier is ValidatorsTest { (, , , , , uint256 actualMultiplier, ) = validators.getValidatorGroup(group); assertEq(actualMultiplier, FixidityLib.fixed1().unwrap()); } + + function test_Reverts_SetSlashingMultiplierResetPeriod_WhenL2() public { + _whenL2(); + uint256 newResetPeriod = 10 * DAY; + vm.expectRevert("This method is not supported in L2 anymore."); + validators.setSlashingMultiplierResetPeriod(newResetPeriod); + } } diff --git a/packages/protocol/test-sol/voting/Election.t.sol b/packages/protocol/test-sol/voting/Election.t.sol index e20c27546f5..11d464c5cb5 100644 --- a/packages/protocol/test-sol/voting/Election.t.sol +++ b/packages/protocol/test-sol/voting/Election.t.sol @@ -25,6 +25,8 @@ contract ElectionMock is Election(true) { contract ElectionTest is Utils, Constants { using FixidityLib for FixidityLib.Fraction; + address constant proxyAdminAddress = 0x4200000000000000000000000000000000000018; + event ElectableValidatorsSet(uint256 min, uint256 max); event MaxNumGroupsVotedForSet(uint256 maxNumGroupsVotedFor); event ElectabilityThresholdSet(uint256 electabilityThreshold); @@ -143,6 +145,10 @@ contract ElectionTest is Utils, Constants { electabilityThreshold ); } + + function _whenL2() public { + deployCodeTo("Registry.sol", abi.encode(false), proxyAdminAddress); + } } contract ElectionTest_Initialize is ElectionTest { @@ -187,6 +193,12 @@ contract Election_SetElectabilityThreshold is ElectionTest { vm.expectRevert("Electability threshold must be lower than 100%"); election.setElectabilityThreshold(FixidityLib.fixed1().unwrap() + 1); } + + function test_Revert_setElectabilityThreshold_WhenL2() public { + _whenL2(); + vm.expectRevert("This method is not supported in L2 anymore."); + election.setElectabilityThreshold(FixidityLib.fixed1().unwrap() + 1); + } } contract Election_SetElectableValidators is ElectionTest { @@ -199,6 +211,14 @@ contract Election_SetElectableValidators is ElectionTest { assertEq(max, newElectableValidatorsMax); } + function test_Reverts_shouldSetElectableValidators_WhenL2() public { + _whenL2(); + uint256 newElectableValidatorsMin = 2; + uint256 newElectableValidatorsMax = 4; + vm.expectRevert("This method is not supported in L2 anymore."); + election.setElectableValidators(newElectableValidatorsMin, newElectableValidatorsMax); + } + function test_ShouldEmitTheElectableValidatorsSetEvent() public { uint256 newElectableValidatorsMin = 2; uint256 newElectableValidatorsMax = 4; @@ -236,6 +256,13 @@ contract Election_SetMaxNumGroupsVotedFor is ElectionTest { assertEq(election.maxNumGroupsVotedFor(), newMaxNumGroupsVotedFor); } + function test_Revert_SetMaxNumGroupsVotedFor_WhenL2() public { + _whenL2(); + uint256 newMaxNumGroupsVotedFor = 4; + vm.expectRevert("This method is not supported in L2 anymore."); + election.setMaxNumGroupsVotedFor(newMaxNumGroupsVotedFor); + } + function test_ShouldEmitMaxNumGroupsVotedForSetEvent() public { uint256 newMaxNumGroupsVotedFor = 4; vm.expectEmit(true, false, false, false); @@ -261,6 +288,12 @@ contract Election_SetAllowedToVoteOverMaxNumberOfGroups is ElectionTest { assertEq(election.allowedToVoteOverMaxNumberOfGroups(address(this)), true); } + function test_Revert_SetAllowedToVoteOverMaxNumberOfGroups_WhenL2() public { + _whenL2(); + vm.expectRevert("This method is not supported in L2 anymore."); + election.setAllowedToVoteOverMaxNumberOfGroups(true); + } + function test_ShouldRevertWhenCalledByValidator() public { validators.setValidator(address(this)); vm.expectRevert("Validators cannot vote for more than max number of groups"); @@ -310,6 +343,13 @@ contract Election_MarkGroupEligible is ElectionTest { assertEq(eligibleGroups[0], group); } + function test_Revert_MarkGroupEligible_WhenL2() public { + _whenL2(); + address group = address(this); + vm.expectRevert("This method is not supported in L2 anymore."); + election.markGroupEligible(group, address(0), address(0)); + } + function test_ShouldEmitValidatorGroupMarkedEligibleEvent() public { address group = address(this); vm.expectEmit(true, false, false, false); @@ -423,6 +463,15 @@ contract Election_Vote_WhenGroupEligible is ElectionTest { assertEq(election.getPendingVotesForGroupByAccount(group, voter), value - maxNumGroupsVotedFor); } + function test_Revert_Vote_WhenL2() + public + { + _whenL2(); + + vm.expectRevert("This method is not supported in L2 anymore."); + election.vote(group, value - maxNumGroupsVotedFor, address(0), address(0)); + } + function test_ShouldSetTotalVotesByAccount_WhenMaxNumberOfGroupsWasNotReached() public { WhenVotedForMaxNumberOfGroups(); assertEq(election.getTotalVotesByAccount(voter), maxNumGroupsVotedFor); @@ -810,6 +859,13 @@ contract Election_Activate is ElectionTest { election.activate(group); } + function test_Revert_Activate_WhenL2() public { + WhenVoterHasPendingVotes(); + _whenL2(); + vm.expectRevert("This method is not supported in L2 anymore."); + election.activate(group); + } + address voter2 = account2; uint256 value2 = 573; @@ -884,6 +940,12 @@ contract Election_Activate is ElectionTest { election.activateForAccount(group, voter); } + function test_Revert_ActivateForAccount_WhenL2() public { + _whenL2(); + vm.expectRevert("This method is not supported in L2 anymore."); + election.activateForAccount(group, voter); + } + function test_ShouldRevert_WhenTheVoterDoesNotHavePendingVotes() public { vm.expectRevert("Vote value cannot be zero"); election.activate(group); @@ -1889,6 +1951,15 @@ contract Election_DistributeEpochRewards is ElectionTest { assertEq(election.getActiveVotesForGroupByAccount(group, voter), voteValue + rewardValue); } + function test_Revert_DistributeEpochRewards_WhenL2() + public + { + _whenL2(); + vm.expectRevert("This method is not supported in L2 anymore."); + vm.prank(address(0)); + election.distributeEpochRewards(group, rewardValue, address(0), address(0)); + } + function test_ShouldIncrementAccountTotalVotesForGroup_WhenThereIsSingleGroupWithActiveVotes() public { @@ -2641,3 +2712,14 @@ contract Election_ConsistencyChecks is ElectionTest { revokeAllAndCheckInvariants(100); } } + +contract Election_HasActivatablePendingVotes is ElectionTest { + function test_Revert_hasActivatablePendingVotes_WhenL2() + public + { + _whenL2(); + vm.expectRevert("This method is not supported in L2 anymore."); + vm.prank(address(0)); + election.hasActivatablePendingVotes(address(0), address(0)); + } +} From 2f321b497f728d675b3fb75c70d7bc749ad6adb5 Mon Sep 17 00:00:00 2001 From: pahor167 Date: Fri, 26 Apr 2024 14:18:41 +0200 Subject: [PATCH 02/19] integration tests --- packages/protocol/test-sol/constants.sol | 1 + .../governance/validators/Validators.t.sol | 52 +-- .../validators/mocks/ValidatorsMockTunnel.sol | 59 +++ .../RevokeCeloAfterL2Transition.sol | 395 ++++++++++++++++++ 4 files changed, 456 insertions(+), 51 deletions(-) create mode 100644 packages/protocol/test-sol/governance/validators/mocks/ValidatorsMockTunnel.sol create mode 100644 packages/protocol/test-sol/integration/RevokeCeloAfterL2Transition.sol diff --git a/packages/protocol/test-sol/constants.sol b/packages/protocol/test-sol/constants.sol index e013af797e4..0c4f836f4cc 100644 --- a/packages/protocol/test-sol/constants.sol +++ b/packages/protocol/test-sol/constants.sol @@ -18,4 +18,5 @@ contract Constants { string constant AccountsContract = "Accounts"; string constant LockedGoldContract = "LockedGold"; string constant ValidatorsContract = "Validators"; + string constant GovernanceContract = "Governance"; } diff --git a/packages/protocol/test-sol/governance/validators/Validators.t.sol b/packages/protocol/test-sol/governance/validators/Validators.t.sol index 4048dc88c3f..4b6d62bf6f0 100644 --- a/packages/protocol/test-sol/governance/validators/Validators.t.sol +++ b/packages/protocol/test-sol/governance/validators/Validators.t.sol @@ -15,6 +15,7 @@ import "@celo-contracts/governance/LockedGold.sol"; import "@celo-contracts/stability/test/MockStableToken.sol"; import "@celo-contracts/governance/test/MockElection.sol"; import "@celo-contracts/governance/test/MockLockedGold.sol"; +import "./mocks/ValidatorsMockTunnel.sol"; import "@celo-contracts/governance/test/ValidatorsMock.sol"; import "@test-sol/constants.sol"; @@ -22,57 +23,6 @@ import "@test-sol/utils/ECDSAHelper.sol"; import { Utils } from "@test-sol/utils.sol"; import { Test as ForgeTest } from "forge-std/Test.sol"; -contract ValidatorsMockTunnel is ForgeTest { - ValidatorsMock private tunnelValidators; - address validatorContractAddress; - - constructor(address _validatorContractAddress) public { - validatorContractAddress = _validatorContractAddress; - tunnelValidators = ValidatorsMock(validatorContractAddress); - } - - struct InitParams { - address registryAddress; - uint256 groupRequirementValue; - uint256 groupRequirementDuration; - uint256 validatorRequirementValue; - uint256 validatorRequirementDuration; - uint256 validatorScoreExponent; - uint256 validatorScoreAdjustmentSpeed; - } - - struct InitParams2 { - uint256 _membershipHistoryLength; - uint256 _slashingMultiplierResetPeriod; - uint256 _maxGroupSize; - uint256 _commissionUpdateDelay; - uint256 _downtimeGracePeriod; - } - - function MockInitialize(address sender, InitParams calldata params, InitParams2 calldata params2) - external - returns (bool, bytes memory) - { - bytes memory data = abi.encodeWithSignature( - "initialize(address,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256)", - params.registryAddress, - params.groupRequirementValue, - params.groupRequirementDuration, - params.validatorRequirementValue, - params.validatorRequirementDuration, - params.validatorScoreExponent, - params.validatorScoreAdjustmentSpeed, - params2._membershipHistoryLength, - params2._slashingMultiplierResetPeriod, - params2._maxGroupSize, - params2._commissionUpdateDelay, - params2._downtimeGracePeriod - ); - vm.prank(sender); - (bool success, ) = address(tunnelValidators).call(data); - require(success, "unsuccessful tunnel call"); - } -} contract ValidatorsTest is Test, Constants, Utils, ECDSAHelper { using FixidityLib for FixidityLib.Fraction; diff --git a/packages/protocol/test-sol/governance/validators/mocks/ValidatorsMockTunnel.sol b/packages/protocol/test-sol/governance/validators/mocks/ValidatorsMockTunnel.sol new file mode 100644 index 00000000000..f6df9613d80 --- /dev/null +++ b/packages/protocol/test-sol/governance/validators/mocks/ValidatorsMockTunnel.sol @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.5.13; +pragma experimental ABIEncoderV2; + + +import "@celo-contracts/governance/test/ValidatorsMock.sol"; +import { Test as ForgeTest } from "forge-std/Test.sol"; + +contract ValidatorsMockTunnel is ForgeTest { + ValidatorsMock private tunnelValidators; + address validatorContractAddress; + + constructor(address _validatorContractAddress) public { + validatorContractAddress = _validatorContractAddress; + tunnelValidators = ValidatorsMock(validatorContractAddress); + } + + struct InitParams { + address registryAddress; + uint256 groupRequirementValue; + uint256 groupRequirementDuration; + uint256 validatorRequirementValue; + uint256 validatorRequirementDuration; + uint256 validatorScoreExponent; + uint256 validatorScoreAdjustmentSpeed; + } + + struct InitParams2 { + uint256 _membershipHistoryLength; + uint256 _slashingMultiplierResetPeriod; + uint256 _maxGroupSize; + uint256 _commissionUpdateDelay; + uint256 _downtimeGracePeriod; + } + + function MockInitialize(address sender, InitParams calldata params, InitParams2 calldata params2) + external + returns (bool, bytes memory) + { + bytes memory data = abi.encodeWithSignature( + "initialize(address,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256)", + params.registryAddress, + params.groupRequirementValue, + params.groupRequirementDuration, + params.validatorRequirementValue, + params.validatorRequirementDuration, + params.validatorScoreExponent, + params.validatorScoreAdjustmentSpeed, + params2._membershipHistoryLength, + params2._slashingMultiplierResetPeriod, + params2._maxGroupSize, + params2._commissionUpdateDelay, + params2._downtimeGracePeriod + ); + vm.prank(sender); + (bool success, ) = address(tunnelValidators).call(data); + require(success, "unsuccessful tunnel call"); + } +} diff --git a/packages/protocol/test-sol/integration/RevokeCeloAfterL2Transition.sol b/packages/protocol/test-sol/integration/RevokeCeloAfterL2Transition.sol new file mode 100644 index 00000000000..a62ba632a29 --- /dev/null +++ b/packages/protocol/test-sol/integration/RevokeCeloAfterL2Transition.sol @@ -0,0 +1,395 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.5.13; +pragma experimental ABIEncoderV2; + +import "celo-foundry/Test.sol"; + +import "openzeppelin-solidity/contracts/math/SafeMath.sol"; +import "@celo-contracts/common/FixidityLib.sol"; +import "@celo-contracts/common/Registry.sol"; +import "@celo-contracts/common/Accounts.sol"; +import "@celo-contracts/common/GoldToken.sol"; + +import "@celo-contracts/governance/Election.sol"; +import "@celo-contracts/governance/LockedGold.sol"; + +import "@celo-contracts/stability/test/MockStableToken.sol"; +import "@celo-contracts/governance/Election.sol"; +import "@celo-contracts/governance/Governance.sol"; + +import "@celo-contracts/governance/test/ValidatorsMock.sol"; +import "@test-sol/constants.sol"; +import "@test-sol/utils/ECDSAHelper.sol"; +import { Utils } from "@test-sol/utils.sol"; +import { Test as ForgeTest } from "forge-std/Test.sol"; +import "../governance/validators/mocks/ValidatorsMockTunnel.sol"; + +contract RevokeCeloAfterL2Transition is Test, Constants, ECDSAHelper, Utils { + using FixidityLib for FixidityLib.Fraction; + + address constant proxyAdminAddress = 0x4200000000000000000000000000000000000018; + + Registry registry; + Accounts accounts; + MockStableToken stableToken; + Election election; + ValidatorsMockTunnel public validatorsMockTunnel; + Validators public validators; + LockedGold lockedGold; + Governance governance; + GoldToken goldToken; + + address owner; + address accApprover; + + address group; + address member; + address validator; + uint256 validatorPk; + + bytes public constant blsPublicKey = abi.encodePacked( + bytes32(0x0101010101010101010101010101010101010101010101010101010101010101), + bytes32(0x0202020202020202020202020202020202020202020202020202020202020202), + bytes32(0x0303030303030303030303030303030303030303030303030303030303030303) + ); + bytes public constant blsPop = abi.encodePacked( + bytes16(0x04040404040404040404040404040404), + bytes16(0x05050505050505050505050505050505), + bytes16(0x06060606060606060606060606060606) + ); + + struct ValidatorLockedGoldRequirements { + uint256 value; + uint256 duration; + } + + struct GroupLockedGoldRequirements { + uint256 value; + uint256 duration; + } + + struct ValidatorScoreParameters { + uint256 exponent; + FixidityLib.Fraction adjustmentSpeed; + } + + uint256 constant DEPOSIT = 5; + uint256 constant VOTER_GOLD = 100; + uint256 constant REFERENDUM_STAGE_DURATION = 5 * 60; + uint256 constant CONCURRENT_PROPOSALS = 1; + uint256 constant DEQUEUE_FREQUENCY = 10 * 60; + uint256 constant QUERY_EXPIRY = 60 * 60; + uint256 constant EXECUTION_STAGE_DURATION = 1 * 60; + + uint256 unlockingPeriod; + + FixidityLib.Fraction public commission = FixidityLib.newFixedFraction(1, 100); + + ValidatorLockedGoldRequirements public originalValidatorLockedGoldRequirements; + GroupLockedGoldRequirements public originalGroupLockedGoldRequirements; + ValidatorScoreParameters public originalValidatorScoreParameters; + + uint256 expectedParticipationBaseline; + FixidityLib.Fraction baselineUpdateFactor; + FixidityLib.Fraction participationBaseline; + FixidityLib.Fraction participationFloor; + FixidityLib.Fraction baselineQuorumFactor; + + ValidatorsMockTunnel.InitParams public initParams; + ValidatorsMockTunnel.InitParams2 public initParams2; + + uint256 validatorRegistrationEpochNumber; + + function setUp() public { + owner = address(this); + console.log("owner", owner); + accApprover = actor("approver"); + group = actor("group"); + member = actor("member"); + + (validator, validatorPk) = actorWithPK("validator"); + + uint256 electableValidatorsMin = 4; + uint256 electableValidatorsMax = 6; + uint256 maxNumGroupsVotedFor = 3; + uint256 electabilityThreshold = FixidityLib.newFixedFraction(1, 100).unwrap(); + + unlockingPeriod = 3 * DAY; + + uint256 slashingMultiplierResetPeriod = 30 * DAY; + uint256 membershipHistoryLength = 5; + uint256 maxGroupSize = 5; + uint256 commissionUpdateDelay = 3; + uint256 downtimeGracePeriod = 0; + + baselineUpdateFactor = FixidityLib.newFixedFraction(1, 5); + participationBaseline = FixidityLib.newFixedFraction(5, 10); + participationFloor = FixidityLib.newFixedFraction(5, 100); + baselineQuorumFactor = FixidityLib.fixed1(); + expectedParticipationBaseline = FixidityLib + .multiply(baselineUpdateFactor, FixidityLib.fixed1()) + .add( + FixidityLib.multiply( + FixidityLib.fixed1().subtract(baselineUpdateFactor), + participationBaseline + ) + ) + .unwrap(); + + address registryAddress = 0x000000000000000000000000000000000000ce10; + deployCodeTo("Registry.sol", abi.encode(false), registryAddress); + registry = Registry(registryAddress); + + accounts = new Accounts(true); + stableToken = new MockStableToken(); + election = new Election(true); + lockedGold = new LockedGold(true); + validators = new Validators(true); + validatorsMockTunnel = new ValidatorsMockTunnel(address(validators)); + governance = new Governance(true); + goldToken = new GoldToken(true); + + registry.setAddressFor(AccountsContract, address(accounts)); + registry.setAddressFor(ElectionContract, address(election)); + registry.setAddressFor(StableTokenContract, address(stableToken)); + registry.setAddressFor(LockedGoldContract, address(lockedGold)); + registry.setAddressFor(ValidatorsContract, address(validators)); + registry.setAddressFor(GovernanceContract, address(governance)); + registry.setAddressFor(GoldTokenContract, address(goldToken)); + + goldToken.initialize(address(registry)); + + accounts.initialize(registryAddress); + + election.initialize( + registryAddress, + electableValidatorsMin, + electableValidatorsMax, + maxNumGroupsVotedFor, + electabilityThreshold + ); + + lockedGold.initialize(address(registry), unlockingPeriod); + + originalValidatorLockedGoldRequirements = ValidatorLockedGoldRequirements({ + value: 1000, + duration: 60 * DAY + }); + + originalGroupLockedGoldRequirements = GroupLockedGoldRequirements({ + value: 1000, + duration: 100 * DAY + }); + + originalValidatorScoreParameters = ValidatorScoreParameters({ + exponent: 5, + adjustmentSpeed: FixidityLib.newFixedFraction(5, 20) + }); + + initParams = ValidatorsMockTunnel.InitParams({ + registryAddress: registryAddress, + groupRequirementValue: originalGroupLockedGoldRequirements.value, + groupRequirementDuration: originalGroupLockedGoldRequirements.duration, + validatorRequirementValue: originalValidatorLockedGoldRequirements.value, + validatorRequirementDuration: originalValidatorLockedGoldRequirements.duration, + validatorScoreExponent: originalValidatorScoreParameters.exponent, + validatorScoreAdjustmentSpeed: originalValidatorScoreParameters.adjustmentSpeed.unwrap() + }); + initParams2 = ValidatorsMockTunnel.InitParams2({ + _membershipHistoryLength: membershipHistoryLength, + _slashingMultiplierResetPeriod: slashingMultiplierResetPeriod, + _maxGroupSize: maxGroupSize, + _commissionUpdateDelay: commissionUpdateDelay, + _downtimeGracePeriod: downtimeGracePeriod + }); + + validatorsMockTunnel.MockInitialize(owner, initParams, initParams2); + + governance.initialize( + address(registry), + accApprover, + CONCURRENT_PROPOSALS, + DEPOSIT, + QUERY_EXPIRY, + DEQUEUE_FREQUENCY, + REFERENDUM_STAGE_DURATION, + EXECUTION_STAGE_DURATION, + participationBaseline.unwrap(), + participationFloor.unwrap(), + baselineUpdateFactor.unwrap(), + baselineQuorumFactor.unwrap() + ); + + accounts.createAccount(); + } + + function _whenL2() public { + deployCodeTo("Registry.sol", abi.encode(false), proxyAdminAddress); + } + + function _registerValidatorGroupHelper(address _group, uint256 numMembers) internal { + vm.startPrank(_group); + if (!accounts.isAccount(_group)) { + accounts.createAccount(); + } + vm.deal(_group, 10000e18); + lockedGold.lock.value(10000e18)(); + validators.registerValidatorGroup(commission.unwrap()); + vm.stopPrank(); + } + + function _registerValidatorGroupWithMembers(address _group, uint256 _numMembers) public { + _registerValidatorGroupHelper(_group, _numMembers); + + for (uint256 i = 0; i < _numMembers; i++) { + if (i == 0) { + _registerValidatorHelper(validator, validatorPk); + + vm.prank(validator); + validators.affiliate(group); + + vm.prank(group); + validators.addFirstMember(validator, address(0), address(0)); + } else { + uint256 _validator1Pk = i; + address _validator1 = vm.addr(_validator1Pk); + + vm.prank(_validator1); + accounts.createAccount(); + _registerValidatorHelper(_validator1, _validator1Pk); + vm.prank(_validator1); + validators.affiliate(group); + + vm.prank(group); + validators.addMember(_validator1); + } + } + } + + function _registerValidatorHelper(address _validator, uint256 _validatorPk) + internal + returns (bytes memory) + { + if (!accounts.isAccount(_validator)) { + vm.prank(_validator); + accounts.createAccount(); + } + + vm.deal(_validator, 10000e18); + vm.prank(_validator); + lockedGold.lock.value(10000e18)(); + + bytes memory _ecdsaPubKey = _generateEcdsaPubKey(_validator, _validatorPk); + + ph.mockSuccess(ph.PROOF_OF_POSSESSION(), abi.encodePacked(_validator, blsPublicKey, blsPop)); + + vm.prank(_validator); + validators.registerValidator(_ecdsaPubKey, blsPublicKey, blsPop); + validatorRegistrationEpochNumber = validators.getEpochNumber(); + return _ecdsaPubKey; + } + + function _generateEcdsaPubKey(address _account, uint256 _accountPk) + internal + returns (bytes memory ecdsaPubKey) + { + (uint8 v, bytes32 r, bytes32 s) = getParsedSignatureOfAddress(_account, _accountPk); + bytes32 addressHash = keccak256(abi.encodePacked(_account)); + + ecdsaPubKey = addressToPublicKey(addressHash, v, r, s); + } + + function getParsedSignatureOfAddress(address _address, uint256 privateKey) + public + pure + returns (uint8, bytes32, bytes32) + { + bytes32 addressHash = keccak256(abi.encodePacked(_address)); + bytes32 prefixedHash = ECDSA.toEthSignedMessageHash(addressHash); + return vm.sign(privateKey, prefixedHash); + } + + function() external payable {} +} + +contract RevokeCeloAfterL2TransitionTest is RevokeCeloAfterL2Transition { + function test_revoke_celo_after_l2_transition() public { + uint256 lockedGoldValue = 1e18; + uint256 active = 12; + uint256 pending = 11; + + deal(address(this), lockedGoldValue); + lockedGold.lock.value(lockedGoldValue)(); + _registerValidatorGroupWithMembers(group, 1); + + election.vote(group, active, address(0), address(0)); + blockTravel(EPOCH_SIZE + 1); + election.activate(group); + election.vote(group, pending, address(0), address(0)); + + assertEq(lockedGold.getAccountNonvotingLockedGold(address(this)), lockedGoldValue - active - pending); + assertEq(lockedGold.getAccountTotalLockedGold(address(this)), lockedGoldValue); + assertEq(election.getPendingVotesForGroupByAccount(group, address(this)), pending); + assertEq(election.getActiveVotesForGroupByAccount(group, address(this)), active); + + _whenL2(); + + election.revokeActive(group, active, address(0), address(0), 0); + election.revokePending(group, pending, address(0), address(0), 0); + + assertEq(lockedGoldValue, lockedGold.getAccountNonvotingLockedGold(address(this))); + + lockedGold.unlock(lockedGoldValue); + timeTravel(unlockingPeriod + 1); + lockedGold.withdraw(0); + assertEq(address(this).balance, lockedGoldValue); + } + + function test_validatorCanRemoveCelo_WhenTransitionedToL2() public { + _registerValidatorGroupWithMembers(group, 1); + + _whenL2(); + + vm.startPrank(validator); + validators.deaffiliate(); + timeTravel(originalValidatorLockedGoldRequirements.duration + 1); + validators.deregisterValidator(0); + + uint256 totalLockedCelo = lockedGold.getAccountTotalLockedGold(validator); + + lockedGold.unlock(totalLockedCelo); + + timeTravel(unlockingPeriod + 1); + lockedGold.withdraw(0); + + assertEq(validator.balance, 10000e18); + + vm.stopPrank(); + } + + function test_validatorGroupCanRemoveCelo_WhenTransitionedToL2() public { + _registerValidatorGroupWithMembers(group, 1); + + _whenL2(); + + vm.prank(validator); + validators.deaffiliate(); + timeTravel(originalValidatorLockedGoldRequirements.duration + 1); + vm.prank(validator); + validators.deregisterValidator(0); + + vm.startPrank(group); + timeTravel(originalGroupLockedGoldRequirements.duration + 1); + validators.deregisterValidatorGroup(0); + + uint256 totalLockedCelo = lockedGold.getAccountTotalLockedGold(group); + lockedGold.unlock(totalLockedCelo); + + timeTravel(unlockingPeriod + 1); + lockedGold.withdraw(0); + + assertEq(group.balance, 10000e18); + + vm.stopPrank(); + } +} From e0f7ded2bdc0a37540886de757f0e433104aea78 Mon Sep 17 00:00:00 2001 From: pahor167 Date: Mon, 29 Apr 2024 14:38:22 +0200 Subject: [PATCH 03/19] Release gold tests --- packages/protocol/test-sol/constants.sol | 4 +- .../validators/mocks/ValidatorsMockTunnel.sol | 1 - .../governance/voting/ReleaseGold.t.sol | 77 +-------- .../voting/mocks/ReleaseGoldMockTunnel.sol | 82 ++++++++++ .../RevokeCeloAfterL2Transition.sol | 149 +++++++++++++++++- .../protocol/test-sol/voting/Election.t.sol | 18 +-- 6 files changed, 240 insertions(+), 91 deletions(-) create mode 100644 packages/protocol/test-sol/governance/voting/mocks/ReleaseGoldMockTunnel.sol diff --git a/packages/protocol/test-sol/constants.sol b/packages/protocol/test-sol/constants.sol index 0c4f836f4cc..45bb187faf5 100644 --- a/packages/protocol/test-sol/constants.sol +++ b/packages/protocol/test-sol/constants.sol @@ -3,8 +3,10 @@ pragma solidity ^0.5.13; // This contract is only required for Solidity 0.5 contract Constants { uint256 public constant FIXED1 = 1e24; - uint256 public constant HOUR = 60 * 60; + uint256 public constant MINUTE = 60; + uint256 public constant HOUR = 60 * MINUTE; uint256 public constant DAY = 24 * HOUR; + uint256 public constant MONTH = 30 * DAY; uint256 constant WEEK = 7 * DAY; uint256 public constant YEAR = 365 * DAY; uint256 public constant EPOCH_SIZE = DAY / 5; diff --git a/packages/protocol/test-sol/governance/validators/mocks/ValidatorsMockTunnel.sol b/packages/protocol/test-sol/governance/validators/mocks/ValidatorsMockTunnel.sol index f6df9613d80..0af45fefe7f 100644 --- a/packages/protocol/test-sol/governance/validators/mocks/ValidatorsMockTunnel.sol +++ b/packages/protocol/test-sol/governance/validators/mocks/ValidatorsMockTunnel.sol @@ -2,7 +2,6 @@ pragma solidity ^0.5.13; pragma experimental ABIEncoderV2; - import "@celo-contracts/governance/test/ValidatorsMock.sol"; import { Test as ForgeTest } from "forge-std/Test.sol"; diff --git a/packages/protocol/test-sol/governance/voting/ReleaseGold.t.sol b/packages/protocol/test-sol/governance/voting/ReleaseGold.t.sol index 6a054b12b9b..bfeb65851b0 100644 --- a/packages/protocol/test-sol/governance/voting/ReleaseGold.t.sol +++ b/packages/protocol/test-sol/governance/voting/ReleaseGold.t.sol @@ -15,88 +15,13 @@ import "../../../contracts/common/Freezer.sol"; import "../../../contracts/common/GoldToken.sol"; import "../../../contracts/governance/LockedGold.sol"; import "../../../contracts/governance/ReleaseGold.sol"; +import "./mocks/ReleaseGoldMockTunnel.sol"; import "../../../contracts/stability/test/MockStableToken.sol"; import "../../../contracts/governance/test/MockElection.sol"; import "../../../contracts/governance/test/MockGovernance.sol"; import "../../../contracts/governance/test/MockValidators.sol"; import "@test-sol/utils/ECDSAHelper.sol"; -contract ReleaseGoldMockTunnel is ForgeTest { - ReleaseGold private releaseGoldTunnel; - address payable releaseGoldContractAddress; - - struct InitParams { - uint256 releaseStartTime; - uint256 releaseCliffTime; - uint256 numReleasePeriods; - uint256 releasePeriod; - uint256 amountReleasedPerPeriod; - bool revocable; - address payable _beneficiary; - } - - struct InitParams2 { - address _releaseOwner; - address payable _refundAddress; - bool subjectToLiquidityProvision; - uint256 initialDistributionRatio; - bool _canValidate; - bool _canVote; - address registryAddress; - } - - constructor(address _releaseGoldContractAddress) public { - releaseGoldContractAddress = address(uint160(_releaseGoldContractAddress)); - releaseGoldTunnel = ReleaseGold(releaseGoldContractAddress); - } - - function MockInitialize(address sender, InitParams calldata params, InitParams2 calldata params2) - external - returns (bool, bytes memory) - { - bytes4 selector = bytes4( - keccak256( - "initialize(uint256,uint256,uint256,uint256,uint256,bool,address,address,address,bool,uint256,bool,bool,address)" - ) - ); - - bytes memory dataFirstHalf; - { - // Encode the first half of the parameters - dataFirstHalf = abi.encode( - params.releaseStartTime, - params.releaseCliffTime, - params.numReleasePeriods, - params.releasePeriod, - params.amountReleasedPerPeriod, - params.revocable, - params._beneficiary - ); - } - - bytes memory dataSecondHalf; - { - // Encode the second half of the parameters - dataSecondHalf = abi.encode( - params2._releaseOwner, - params2._refundAddress, - params2.subjectToLiquidityProvision, - params2.initialDistributionRatio, - params2._canValidate, - params2._canVote, - params2.registryAddress - ); - } - - // Concatenate the selector, first half, and second half - bytes memory data = abi.encodePacked(selector, dataFirstHalf, dataSecondHalf); - - vm.prank(sender); - (bool success, ) = address(releaseGoldTunnel).call(data); - require(success, "unsuccessful tunnel call"); - } -} - contract ReleaseGoldTest is Test, ECDSAHelper { using FixidityLib for FixidityLib.Fraction; diff --git a/packages/protocol/test-sol/governance/voting/mocks/ReleaseGoldMockTunnel.sol b/packages/protocol/test-sol/governance/voting/mocks/ReleaseGoldMockTunnel.sol new file mode 100644 index 00000000000..83e9d231d89 --- /dev/null +++ b/packages/protocol/test-sol/governance/voting/mocks/ReleaseGoldMockTunnel.sol @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.5.13; +pragma experimental ABIEncoderV2; + +import "../../../../contracts/governance/ReleaseGold.sol"; +import { Test as ForgeTest } from "forge-std/Test.sol"; + +contract ReleaseGoldMockTunnel is ForgeTest { + ReleaseGold private releaseGoldTunnel; + address payable releaseGoldContractAddress; + + struct InitParams { + uint256 releaseStartTime; + uint256 releaseCliffTime; + uint256 numReleasePeriods; + uint256 releasePeriod; + uint256 amountReleasedPerPeriod; + bool revocable; + address payable _beneficiary; + } + + struct InitParams2 { + address _releaseOwner; + address payable _refundAddress; + bool subjectToLiquidityProvision; + uint256 initialDistributionRatio; + bool _canValidate; + bool _canVote; + address registryAddress; + } + + constructor(address _releaseGoldContractAddress) public { + releaseGoldContractAddress = address(uint160(_releaseGoldContractAddress)); + releaseGoldTunnel = ReleaseGold(releaseGoldContractAddress); + } + + function MockInitialize(address sender, InitParams calldata params, InitParams2 calldata params2) + external + returns (bool, bytes memory) + { + bytes4 selector = bytes4( + keccak256( + "initialize(uint256,uint256,uint256,uint256,uint256,bool,address,address,address,bool,uint256,bool,bool,address)" + ) + ); + + bytes memory dataFirstHalf; + { + // Encode the first half of the parameters + dataFirstHalf = abi.encode( + params.releaseStartTime, + params.releaseCliffTime, + params.numReleasePeriods, + params.releasePeriod, + params.amountReleasedPerPeriod, + params.revocable, + params._beneficiary + ); + } + + bytes memory dataSecondHalf; + { + // Encode the second half of the parameters + dataSecondHalf = abi.encode( + params2._releaseOwner, + params2._refundAddress, + params2.subjectToLiquidityProvision, + params2.initialDistributionRatio, + params2._canValidate, + params2._canVote, + params2.registryAddress + ); + } + + // Concatenate the selector, first half, and second half + bytes memory data = abi.encodePacked(selector, dataFirstHalf, dataSecondHalf); + + vm.prank(sender); + (bool success, ) = address(releaseGoldTunnel).call(data); + require(success, "unsuccessful tunnel call"); + } +} diff --git a/packages/protocol/test-sol/integration/RevokeCeloAfterL2Transition.sol b/packages/protocol/test-sol/integration/RevokeCeloAfterL2Transition.sol index a62ba632a29..b19498229b0 100644 --- a/packages/protocol/test-sol/integration/RevokeCeloAfterL2Transition.sol +++ b/packages/protocol/test-sol/integration/RevokeCeloAfterL2Transition.sol @@ -12,6 +12,7 @@ import "@celo-contracts/common/GoldToken.sol"; import "@celo-contracts/governance/Election.sol"; import "@celo-contracts/governance/LockedGold.sol"; +import "@celo-contracts/governance/ReleaseGold.sol"; import "@celo-contracts/stability/test/MockStableToken.sol"; import "@celo-contracts/governance/Election.sol"; @@ -23,11 +24,13 @@ import "@test-sol/utils/ECDSAHelper.sol"; import { Utils } from "@test-sol/utils.sol"; import { Test as ForgeTest } from "forge-std/Test.sol"; import "../governance/validators/mocks/ValidatorsMockTunnel.sol"; +import "../governance/voting/mocks/ReleaseGoldMockTunnel.sol"; contract RevokeCeloAfterL2Transition is Test, Constants, ECDSAHelper, Utils { using FixidityLib for FixidityLib.Fraction; address constant proxyAdminAddress = 0x4200000000000000000000000000000000000018; + uint256 constant TOTAL_AMOUNT = 1 ether * 1_000_000; Registry registry; Accounts accounts; @@ -38,6 +41,7 @@ contract RevokeCeloAfterL2Transition is Test, Constants, ECDSAHelper, Utils { LockedGold lockedGold; Governance governance; GoldToken goldToken; + ReleaseGold releaseGold; address owner; address accApprover; @@ -46,6 +50,18 @@ contract RevokeCeloAfterL2Transition is Test, Constants, ECDSAHelper, Utils { address member; address validator; uint256 validatorPk; + address beneficiary; + address refundAddress; + address releaseOwner; + + address authorizedValidatorSigner; + uint256 authorizedValidatorSignerPK; + address authorizedVoteSigner; + uint256 authorizedVoteSignerPK; + address authorizedValidatorSigner2; + uint256 authorizedValidatorSignerPK2; + address authorizedVoteSigner2; + uint256 authorizedVoteSignerPK2; bytes public constant blsPublicKey = abi.encodePacked( bytes32(0x0101010101010101010101010101010101010101010101010101010101010101), @@ -98,16 +114,25 @@ contract RevokeCeloAfterL2Transition is Test, Constants, ECDSAHelper, Utils { ValidatorsMockTunnel.InitParams public initParams; ValidatorsMockTunnel.InitParams2 public initParams2; + ReleaseGoldMockTunnel.InitParams releaseGoldInitParams; + ReleaseGoldMockTunnel.InitParams2 releaseGoldInitParams2; + uint256 validatorRegistrationEpochNumber; function setUp() public { owner = address(this); - console.log("owner", owner); accApprover = actor("approver"); group = actor("group"); member = actor("member"); + beneficiary = actor("beneficiary"); + refundAddress = actor("refundAddress"); + releaseOwner = actor("releaseOwner"); (validator, validatorPk) = actorWithPK("validator"); + (authorizedValidatorSigner, authorizedValidatorSignerPK) = actorWithPK("authorizedValidatorSigner"); + (authorizedVoteSigner, authorizedVoteSignerPK) = actorWithPK("authorizedVoteSigner"); + (authorizedValidatorSigner2, authorizedValidatorSignerPK2) = actorWithPK("authorizedValidatorSigner2"); + (authorizedVoteSigner2, authorizedVoteSignerPK2) = actorWithPK("authorizedVoteSigner2"); uint256 electableValidatorsMin = 4; uint256 electableValidatorsMax = 6; @@ -148,6 +173,7 @@ contract RevokeCeloAfterL2Transition is Test, Constants, ECDSAHelper, Utils { validatorsMockTunnel = new ValidatorsMockTunnel(address(validators)); governance = new Governance(true); goldToken = new GoldToken(true); + releaseGold = new ReleaseGold(true); registry.setAddressFor(AccountsContract, address(accounts)); registry.setAddressFor(ElectionContract, address(election)); @@ -157,10 +183,38 @@ contract RevokeCeloAfterL2Transition is Test, Constants, ECDSAHelper, Utils { registry.setAddressFor(GovernanceContract, address(governance)); registry.setAddressFor(GoldTokenContract, address(goldToken)); + // (v, r, s) = getParsedSignatureOfAddress(address(releaseGold), authorizedPK); + goldToken.initialize(address(registry)); accounts.initialize(registryAddress); + releaseGold = new ReleaseGold(true); + + + releaseGoldInitParams = ReleaseGoldMockTunnel.InitParams({ + releaseStartTime: block.timestamp + 5 * MINUTE, + releaseCliffTime: HOUR, + numReleasePeriods: 4, + releasePeriod: 3 * MONTH, + amountReleasedPerPeriod: TOTAL_AMOUNT / 4, + revocable: false, + _beneficiary: address(uint160(beneficiary)) + }); + + releaseGoldInitParams2 = ReleaseGoldMockTunnel.InitParams2({ + _releaseOwner: releaseOwner, + _refundAddress: address(0), + subjectToLiquidityProvision: false, + initialDistributionRatio: 1000, + _canValidate: true, + _canVote: true, + registryAddress: registryAddress + }); + + ReleaseGoldMockTunnel tunnel = new ReleaseGoldMockTunnel(address(releaseGold)); + tunnel.MockInitialize(owner, releaseGoldInitParams, releaseGoldInitParams2); + election.initialize( registryAddress, electableValidatorsMin, @@ -221,6 +275,8 @@ contract RevokeCeloAfterL2Transition is Test, Constants, ECDSAHelper, Utils { ); accounts.createAccount(); + + vm.deal(address(releaseGold), TOTAL_AMOUNT); } function _whenL2() public { @@ -392,4 +448,95 @@ contract RevokeCeloAfterL2TransitionTest is RevokeCeloAfterL2Transition { vm.stopPrank(); } + + function _generateEcdsaPubKeyWithSigner(address _validator, uint256 _signerPk) + internal + returns (bytes memory ecdsaPubKey, uint8 v, bytes32 r, bytes32 s) + { + (v, r, s) = getParsedSignatureOfAddress(_validator, _signerPk); + + bytes32 addressHash = keccak256(abi.encodePacked(_validator)); + + ecdsaPubKey = addressToPublicKey(addressHash, v, r, s); + } + + function _registerValidatorWithSignerHelper(address validator, uint256 signerPk) internal returns (bytes memory) { + (bytes memory _ecdsaPubKey, uint8 v, bytes32 r, bytes32 s) = _generateEcdsaPubKeyWithSigner( + validator, + signerPk + ); + + ph.mockSuccess(ph.PROOF_OF_POSSESSION(), abi.encodePacked(validator, blsPublicKey, blsPop)); + + vm.prank(validator); + validators.registerValidator(_ecdsaPubKey, blsPublicKey, blsPop); + validatorRegistrationEpochNumber = validators.getEpochNumber(); + return _ecdsaPubKey; + } + + /// @notice Test that a ReleaseGold owner can remove CELO from their account after transitioning to L2 + /// @dev Release gold beneficiary assigns a validator and a vote signer, locks CELO, votes, transitions to L2, + /// revokes votes with newly assigned voted signer, and removes CELO. + function test_releaseGoldOwnerHasValidator_CanRemoveCelo_WhenTransitionedToL2() public { + _registerValidatorGroupWithMembers(group, 1); + + (uint8 vValidator, bytes32 rValidator, bytes32 sValidator) = getParsedSignatureOfAddress(address(releaseGold), authorizedValidatorSignerPK); + (uint8 vVote, bytes32 rVote, bytes32 sVote) = getParsedSignatureOfAddress(address(releaseGold), authorizedVoteSignerPK); + + vm.startPrank(beneficiary); + releaseGold.createAccount(); + releaseGold.authorizeValidatorSigner(address(uint160(authorizedValidatorSigner)), vValidator, rValidator, sValidator); + releaseGold.authorizeVoteSigner(address(uint160(authorizedVoteSigner)), vVote, rVote, sVote); + releaseGold.lockGold(TOTAL_AMOUNT - 10 ether); + vm.stopPrank(); + + _registerValidatorWithSignerHelper(address(releaseGold), authorizedValidatorSignerPK); + vm.prank(authorizedValidatorSigner); + validators.affiliate(group); + + uint256 active = 12; + uint256 pending = 11; + + vm.startPrank(authorizedVoteSigner); + election.vote(group, active, address(0), address(0)); + blockTravel(EPOCH_SIZE + 1); + election.activate(group); + election.vote(group, pending, address(0), address(0)); + vm.stopPrank(); + + assertEq(lockedGold.getAccountNonvotingLockedGold(address(releaseGold)), TOTAL_AMOUNT - 10 ether - active - pending); + assertEq(lockedGold.getAccountTotalLockedGold(address(releaseGold)), TOTAL_AMOUNT - 10 ether); + assertEq(election.getPendingVotesForGroupByAccount(group, address(releaseGold)), pending); + assertEq(election.getActiveVotesForGroupByAccount(group, address(releaseGold)), active); + + _whenL2(); + + (uint8 vVote2, bytes32 rVote2, bytes32 sVote2) = getParsedSignatureOfAddress(address(releaseGold), authorizedVoteSignerPK2); + + vm.startPrank(beneficiary); + releaseGold.authorizeVoteSigner(address(uint160(authorizedVoteSigner2)), vVote2, rVote2, sVote2); + + vm.startPrank(authorizedVoteSigner2); + + election.revokeActive(group, active, address(0), address(0), 0); + election.revokePending(group, pending, address(0), address(0), 0); + + assertEq(lockedGold.getAccountNonvotingLockedGold(address(releaseGold)), TOTAL_AMOUNT - 10 ether); + vm.stopPrank(); + + vm.startPrank(authorizedValidatorSigner); + validators.deaffiliate(); + timeTravel(originalValidatorLockedGoldRequirements.duration + 1); + validators.deregisterValidator(1); + vm.stopPrank(); + + uint256 totalLockedCelo = lockedGold.getAccountTotalLockedGold(address(releaseGold)); + vm.startPrank(beneficiary); + releaseGold.unlockGold(totalLockedCelo); + + timeTravel(unlockingPeriod + 1); + releaseGold.withdrawLockedGold(0); + // 2 ethers were sent to vote and validator signers + assertEq(address(releaseGold).balance, TOTAL_AMOUNT - 2 ether); + } } diff --git a/packages/protocol/test-sol/voting/Election.t.sol b/packages/protocol/test-sol/voting/Election.t.sol index 11d464c5cb5..ec807502661 100644 --- a/packages/protocol/test-sol/voting/Election.t.sol +++ b/packages/protocol/test-sol/voting/Election.t.sol @@ -194,7 +194,7 @@ contract Election_SetElectabilityThreshold is ElectionTest { election.setElectabilityThreshold(FixidityLib.fixed1().unwrap() + 1); } - function test_Revert_setElectabilityThreshold_WhenL2() public { + function test_Revert_setElectabilityThreshold_WhenL2() public { _whenL2(); vm.expectRevert("This method is not supported in L2 anymore."); election.setElectabilityThreshold(FixidityLib.fixed1().unwrap() + 1); @@ -288,7 +288,7 @@ contract Election_SetAllowedToVoteOverMaxNumberOfGroups is ElectionTest { assertEq(election.allowedToVoteOverMaxNumberOfGroups(address(this)), true); } - function test_Revert_SetAllowedToVoteOverMaxNumberOfGroups_WhenL2() public { + function test_Revert_SetAllowedToVoteOverMaxNumberOfGroups_WhenL2() public { _whenL2(); vm.expectRevert("This method is not supported in L2 anymore."); election.setAllowedToVoteOverMaxNumberOfGroups(true); @@ -463,11 +463,9 @@ contract Election_Vote_WhenGroupEligible is ElectionTest { assertEq(election.getPendingVotesForGroupByAccount(group, voter), value - maxNumGroupsVotedFor); } - function test_Revert_Vote_WhenL2() - public - { + function test_Revert_Vote_WhenL2() public { _whenL2(); - + vm.expectRevert("This method is not supported in L2 anymore."); election.vote(group, value - maxNumGroupsVotedFor, address(0), address(0)); } @@ -1951,9 +1949,7 @@ contract Election_DistributeEpochRewards is ElectionTest { assertEq(election.getActiveVotesForGroupByAccount(group, voter), voteValue + rewardValue); } - function test_Revert_DistributeEpochRewards_WhenL2() - public - { + function test_Revert_DistributeEpochRewards_WhenL2() public { _whenL2(); vm.expectRevert("This method is not supported in L2 anymore."); vm.prank(address(0)); @@ -2714,9 +2710,7 @@ contract Election_ConsistencyChecks is ElectionTest { } contract Election_HasActivatablePendingVotes is ElectionTest { - function test_Revert_hasActivatablePendingVotes_WhenL2() - public - { + function test_Revert_hasActivatablePendingVotes_WhenL2() public { _whenL2(); vm.expectRevert("This method is not supported in L2 anymore."); vm.prank(address(0)); From 6298c1b01a6b9d80732e65458279fcb1db6c103f Mon Sep 17 00:00:00 2001 From: pahor167 Date: Tue, 30 Apr 2024 11:28:38 +0200 Subject: [PATCH 04/19] prettify --- .../contracts/governance/Election.sol | 21 +++++- .../contracts/governance/Validators.sol | 14 +++- .../protocol/test-sol/common/Accounts.t.sol | 1 - .../governance/validators/Validators.t.sol | 1 - .../RevokeCeloAfterL2Transition.sol | 64 +++++++++++++------ 5 files changed, 76 insertions(+), 25 deletions(-) diff --git a/packages/protocol/contracts/governance/Election.sol b/packages/protocol/contracts/governance/Election.sol index ea16aa05093..b31fa514f84 100644 --- a/packages/protocol/contracts/governance/Election.sol +++ b/packages/protocol/contracts/governance/Election.sol @@ -243,7 +243,12 @@ 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 + onlyL1 + returns (bool) + { return _activate(group, account); } @@ -574,7 +579,12 @@ 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 + onlyL1 + returns (bool) + { PendingVote storage pendingVote = votes.pending.forGroup[group].byAccount[account]; return pendingVote.epoch < getEpochNumber() && pendingVote.value > 0; } @@ -630,7 +640,12 @@ 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 + onlyL1 + returns (bool) + { require(_maxNumGroupsVotedFor != maxNumGroupsVotedFor, "Max groups voted for not changed"); maxNumGroupsVotedFor = _maxNumGroupsVotedFor; emit MaxNumGroupsVotedForSet(_maxNumGroupsVotedFor); diff --git a/packages/protocol/contracts/governance/Validators.sol b/packages/protocol/contracts/governance/Validators.sol index d5328c53a78..066c6ce82bd 100644 --- a/packages/protocol/contracts/governance/Validators.sol +++ b/packages/protocol/contracts/governance/Validators.sol @@ -574,7 +574,12 @@ contract Validators is * @notice Removes a validator from the group for which it is a member. * @param validatorAccount The validator to deaffiliate from their affiliated validator group. */ - function forceDeaffiliateIfValidator(address validatorAccount) external nonReentrant onlySlasher onlyL1 { + function forceDeaffiliateIfValidator(address validatorAccount) + external + nonReentrant + onlySlasher + onlyL1 + { if (isValidator(validatorAccount)) { Validator storage validator = validators[validatorAccount]; if (validator.affiliation != address(0)) { @@ -759,7 +764,12 @@ contract Validators is * @notice Getter for a group's slashing multiplier. * @param account The group to fetch slashing multiplier for. */ - function getValidatorGroupSlashingMultiplier(address account) external view onlyL1 returns (uint256) { + function getValidatorGroupSlashingMultiplier(address account) + external + view + onlyL1 + returns (uint256) + { require(isValidatorGroup(account), "Not a validator group"); ValidatorGroup storage group = groups[account]; return group.slashInfo.multiplier.unwrap(); diff --git a/packages/protocol/test-sol/common/Accounts.t.sol b/packages/protocol/test-sol/common/Accounts.t.sol index c795ff7dd02..3d337844ae2 100644 --- a/packages/protocol/test-sol/common/Accounts.t.sol +++ b/packages/protocol/test-sol/common/Accounts.t.sol @@ -99,7 +99,6 @@ contract AccountsTest is Test { (caller2, caller2PK) = actorWithPK("caller2"); } - function _whenL2() public { deployCodeTo("Registry.sol", abi.encode(false), proxyAdminAddress); } diff --git a/packages/protocol/test-sol/governance/validators/Validators.t.sol b/packages/protocol/test-sol/governance/validators/Validators.t.sol index 4b6d62bf6f0..9c3b6639054 100644 --- a/packages/protocol/test-sol/governance/validators/Validators.t.sol +++ b/packages/protocol/test-sol/governance/validators/Validators.t.sol @@ -23,7 +23,6 @@ import "@test-sol/utils/ECDSAHelper.sol"; import { Utils } from "@test-sol/utils.sol"; import { Test as ForgeTest } from "forge-std/Test.sol"; - contract ValidatorsTest is Test, Constants, Utils, ECDSAHelper { using FixidityLib for FixidityLib.Fraction; using SafeMath for uint256; diff --git a/packages/protocol/test-sol/integration/RevokeCeloAfterL2Transition.sol b/packages/protocol/test-sol/integration/RevokeCeloAfterL2Transition.sol index b19498229b0..128277035fb 100644 --- a/packages/protocol/test-sol/integration/RevokeCeloAfterL2Transition.sol +++ b/packages/protocol/test-sol/integration/RevokeCeloAfterL2Transition.sol @@ -129,9 +129,13 @@ contract RevokeCeloAfterL2Transition is Test, Constants, ECDSAHelper, Utils { releaseOwner = actor("releaseOwner"); (validator, validatorPk) = actorWithPK("validator"); - (authorizedValidatorSigner, authorizedValidatorSignerPK) = actorWithPK("authorizedValidatorSigner"); + (authorizedValidatorSigner, authorizedValidatorSignerPK) = actorWithPK( + "authorizedValidatorSigner" + ); (authorizedVoteSigner, authorizedVoteSignerPK) = actorWithPK("authorizedVoteSigner"); - (authorizedValidatorSigner2, authorizedValidatorSignerPK2) = actorWithPK("authorizedValidatorSigner2"); + (authorizedValidatorSigner2, authorizedValidatorSignerPK2) = actorWithPK( + "authorizedValidatorSigner2" + ); (authorizedVoteSigner2, authorizedVoteSignerPK2) = actorWithPK("authorizedVoteSigner2"); uint256 electableValidatorsMin = 4; @@ -183,14 +187,11 @@ contract RevokeCeloAfterL2Transition is Test, Constants, ECDSAHelper, Utils { registry.setAddressFor(GovernanceContract, address(governance)); registry.setAddressFor(GoldTokenContract, address(goldToken)); - // (v, r, s) = getParsedSignatureOfAddress(address(releaseGold), authorizedPK); - goldToken.initialize(address(registry)); accounts.initialize(registryAddress); releaseGold = new ReleaseGold(true); - releaseGoldInitParams = ReleaseGoldMockTunnel.InitParams({ releaseStartTime: block.timestamp + 5 * MINUTE, @@ -383,7 +384,10 @@ contract RevokeCeloAfterL2TransitionTest is RevokeCeloAfterL2Transition { election.activate(group); election.vote(group, pending, address(0), address(0)); - assertEq(lockedGold.getAccountNonvotingLockedGold(address(this)), lockedGoldValue - active - pending); + assertEq( + lockedGold.getAccountNonvotingLockedGold(address(this)), + lockedGoldValue - active - pending + ); assertEq(lockedGold.getAccountTotalLockedGold(address(this)), lockedGoldValue); assertEq(election.getPendingVotesForGroupByAccount(group, address(this)), pending); assertEq(election.getActiveVotesForGroupByAccount(group, address(this)), active); @@ -460,7 +464,10 @@ contract RevokeCeloAfterL2TransitionTest is RevokeCeloAfterL2Transition { ecdsaPubKey = addressToPublicKey(addressHash, v, r, s); } - function _registerValidatorWithSignerHelper(address validator, uint256 signerPk) internal returns (bytes memory) { + function _registerValidatorWithSignerHelper(address validator, uint256 signerPk) + internal + returns (bytes memory) + { (bytes memory _ecdsaPubKey, uint8 v, bytes32 r, bytes32 s) = _generateEcdsaPubKeyWithSigner( validator, signerPk @@ -474,18 +481,26 @@ contract RevokeCeloAfterL2TransitionTest is RevokeCeloAfterL2Transition { return _ecdsaPubKey; } - /// @notice Test that a ReleaseGold owner can remove CELO from their account after transitioning to L2 - /// @dev Release gold beneficiary assigns a validator and a vote signer, locks CELO, votes, transitions to L2, - /// revokes votes with newly assigned voted signer, and removes CELO. function test_releaseGoldOwnerHasValidator_CanRemoveCelo_WhenTransitionedToL2() public { _registerValidatorGroupWithMembers(group, 1); - (uint8 vValidator, bytes32 rValidator, bytes32 sValidator) = getParsedSignatureOfAddress(address(releaseGold), authorizedValidatorSignerPK); - (uint8 vVote, bytes32 rVote, bytes32 sVote) = getParsedSignatureOfAddress(address(releaseGold), authorizedVoteSignerPK); + (uint8 vValidator, bytes32 rValidator, bytes32 sValidator) = getParsedSignatureOfAddress( + address(releaseGold), + authorizedValidatorSignerPK + ); + (uint8 vVote, bytes32 rVote, bytes32 sVote) = getParsedSignatureOfAddress( + address(releaseGold), + authorizedVoteSignerPK + ); vm.startPrank(beneficiary); releaseGold.createAccount(); - releaseGold.authorizeValidatorSigner(address(uint160(authorizedValidatorSigner)), vValidator, rValidator, sValidator); + releaseGold.authorizeValidatorSigner( + address(uint160(authorizedValidatorSigner)), + vValidator, + rValidator, + sValidator + ); releaseGold.authorizeVoteSigner(address(uint160(authorizedVoteSigner)), vVote, rVote, sVote); releaseGold.lockGold(TOTAL_AMOUNT - 10 ether); vm.stopPrank(); @@ -504,24 +519,38 @@ contract RevokeCeloAfterL2TransitionTest is RevokeCeloAfterL2Transition { election.vote(group, pending, address(0), address(0)); vm.stopPrank(); - assertEq(lockedGold.getAccountNonvotingLockedGold(address(releaseGold)), TOTAL_AMOUNT - 10 ether - active - pending); + assertEq( + lockedGold.getAccountNonvotingLockedGold(address(releaseGold)), + TOTAL_AMOUNT - 10 ether - active - pending + ); assertEq(lockedGold.getAccountTotalLockedGold(address(releaseGold)), TOTAL_AMOUNT - 10 ether); assertEq(election.getPendingVotesForGroupByAccount(group, address(releaseGold)), pending); assertEq(election.getActiveVotesForGroupByAccount(group, address(releaseGold)), active); _whenL2(); - (uint8 vVote2, bytes32 rVote2, bytes32 sVote2) = getParsedSignatureOfAddress(address(releaseGold), authorizedVoteSignerPK2); + (uint8 vVote2, bytes32 rVote2, bytes32 sVote2) = getParsedSignatureOfAddress( + address(releaseGold), + authorizedVoteSignerPK2 + ); vm.startPrank(beneficiary); - releaseGold.authorizeVoteSigner(address(uint160(authorizedVoteSigner2)), vVote2, rVote2, sVote2); + releaseGold.authorizeVoteSigner( + address(uint160(authorizedVoteSigner2)), + vVote2, + rVote2, + sVote2 + ); vm.startPrank(authorizedVoteSigner2); election.revokeActive(group, active, address(0), address(0), 0); election.revokePending(group, pending, address(0), address(0), 0); - assertEq(lockedGold.getAccountNonvotingLockedGold(address(releaseGold)), TOTAL_AMOUNT - 10 ether); + assertEq( + lockedGold.getAccountNonvotingLockedGold(address(releaseGold)), + TOTAL_AMOUNT - 10 ether + ); vm.stopPrank(); vm.startPrank(authorizedValidatorSigner); @@ -536,7 +565,6 @@ contract RevokeCeloAfterL2TransitionTest is RevokeCeloAfterL2Transition { timeTravel(unlockingPeriod + 1); releaseGold.withdrawLockedGold(0); - // 2 ethers were sent to vote and validator signers assertEq(address(releaseGold).balance, TOTAL_AMOUNT - 2 ether); } } From b451f58f06fa6fdb06299a8e12a369541654fb54 Mon Sep 17 00:00:00 2001 From: pahor167 Date: Tue, 30 Apr 2024 12:09:25 +0200 Subject: [PATCH 05/19] version update --- packages/protocol/contracts/common/Accounts.sol | 2 +- packages/protocol/contracts/governance/Election.sol | 2 +- packages/protocol/contracts/governance/Validators.sol | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/protocol/contracts/common/Accounts.sol b/packages/protocol/contracts/common/Accounts.sol index 1a5733b0c60..fd12ae7811c 100644 --- a/packages/protocol/contracts/common/Accounts.sol +++ b/packages/protocol/contracts/common/Accounts.sol @@ -492,7 +492,7 @@ contract Accounts is * @return Patch version of the contract. */ function getVersionNumber() external pure returns (uint256, uint256, uint256, uint256) { - return (1, 1, 4, 1); + return (1, 1, 5, 0); } /** diff --git a/packages/protocol/contracts/governance/Election.sol b/packages/protocol/contracts/governance/Election.sol index b31fa514f84..000659b9ca0 100644 --- a/packages/protocol/contracts/governance/Election.sol +++ b/packages/protocol/contracts/governance/Election.sol @@ -614,7 +614,7 @@ contract Election is * @return Patch version of the contract. */ function getVersionNumber() external pure returns (uint256, uint256, uint256, uint256) { - return (1, 1, 3, 0); + return (1, 1, 4, 0); } /** diff --git a/packages/protocol/contracts/governance/Validators.sol b/packages/protocol/contracts/governance/Validators.sol index 066c6ce82bd..8f7635a146d 100644 --- a/packages/protocol/contracts/governance/Validators.sol +++ b/packages/protocol/contracts/governance/Validators.sol @@ -877,7 +877,7 @@ contract Validators is * @return Patch version of the contract. */ function getVersionNumber() external pure returns (uint256, uint256, uint256, uint256) { - return (1, 2, 0, 5); + return (1, 2, 1, 0); } /** From cf0f0d5fc32c15d95a2e7a6b63a3fad855ff8ff1 Mon Sep 17 00:00:00 2001 From: pahor167 Date: Thu, 2 May 2024 10:58:23 +0200 Subject: [PATCH 06/19] optimizing the check --- packages/protocol/contracts-0.8/common/IsL2Check.sol | 4 ---- packages/protocol/test-sol/common/IsL2Check.t.sol | 9 --------- 2 files changed, 13 deletions(-) diff --git a/packages/protocol/contracts-0.8/common/IsL2Check.sol b/packages/protocol/contracts-0.8/common/IsL2Check.sol index e192cf6d38c..3eeaef64475 100644 --- a/packages/protocol/contracts-0.8/common/IsL2Check.sol +++ b/packages/protocol/contracts-0.8/common/IsL2Check.sol @@ -17,10 +17,6 @@ contract IsL2Check { return isContract(proxyAdminAddress); } - function isL1() public view returns (bool) { - return !isL2(); - } - function isContract(address _addr) private view returns (bool) { uint32 size; assembly { diff --git a/packages/protocol/test-sol/common/IsL2Check.t.sol b/packages/protocol/test-sol/common/IsL2Check.t.sol index 506b983bc3c..73d9971c3d1 100644 --- a/packages/protocol/test-sol/common/IsL2Check.t.sol +++ b/packages/protocol/test-sol/common/IsL2Check.t.sol @@ -31,19 +31,10 @@ contract IsL2Check_IsL2Test is IsL2CheckBase { assertFalse(isL2Check.isL2()); } - function test_IsL1() public { - assertTrue(isL2Check.isL1()); - } - function test_IsL2_WhenProxyAdminSet() public { helper_WhenProxyAdminAddressIsSet(); assertTrue(isL2Check.isL2()); } - - function test_IsL1_WhenProxyAdminSet() public { - helper_WhenProxyAdminAddressIsSet(); - assertFalse(isL2Check.isL1()); - } } contract IsL2Check_OnlyL1 is IsL2CheckBase { From 324cad45c9cd4bd604b5233d1e2b4f75da1f9838 Mon Sep 17 00:00:00 2001 From: pahor167 Date: Thu, 2 May 2024 11:56:22 +0200 Subject: [PATCH 07/19] removal of modifier --- .../contracts-0.8/common/IsL2Check.sol | 6 ++ .../contracts/governance/Validators.sol | 66 ++++++++++++------- 2 files changed, 47 insertions(+), 25 deletions(-) diff --git a/packages/protocol/contracts-0.8/common/IsL2Check.sol b/packages/protocol/contracts-0.8/common/IsL2Check.sol index 3eeaef64475..124fe0a1406 100644 --- a/packages/protocol/contracts-0.8/common/IsL2Check.sol +++ b/packages/protocol/contracts-0.8/common/IsL2Check.sol @@ -13,6 +13,12 @@ contract IsL2Check { _; } + function allowOnlyL1() view internal { + if (isL2()) { + revert("This method is not supported in L2 anymore."); + } + } + function isL2() public view returns (bool) { return isContract(proxyAdminAddress); } diff --git a/packages/protocol/contracts/governance/Validators.sol b/packages/protocol/contracts/governance/Validators.sol index 8f7635a146d..b7202f5253b 100644 --- a/packages/protocol/contracts/governance/Validators.sol +++ b/packages/protocol/contracts/governance/Validators.sol @@ -213,7 +213,8 @@ contract Validators is * @param uptime The Fixidity representation of the validator's uptime, between 0 and 1. * @return True upon success. */ - function updateValidatorScoreFromSigner(address signer, uint256 uptime) external onlyVm() onlyL1 { + function updateValidatorScoreFromSigner(address signer, uint256 uptime) external onlyVm() { + allowOnlyL1(); _updateValidatorScoreFromSigner(signer, uptime); } @@ -227,9 +228,9 @@ contract Validators is function distributeEpochPaymentsFromSigner(address signer, uint256 maxPayment) external onlyVm() - onlyL1 returns (uint256) { + allowOnlyL1(); return _distributeEpochPaymentsFromSigner(signer, maxPayment); } @@ -249,7 +250,8 @@ contract Validators is bytes calldata ecdsaPublicKey, bytes calldata blsPublicKey, bytes calldata blsPop - ) external nonReentrant onlyL1 returns (bool) { + ) external nonReentrant returns (bool) { + allowOnlyL1(); address account = getAccounts().validatorSignerToAccount(msg.sender); _isRegistrationAllowed(account); require(!isValidator(account) && !isValidatorGroup(account), "Already registered"); @@ -309,7 +311,8 @@ contract Validators is * @return True upon success. * @dev De-affiliates with the previously affiliated group if present. */ - function affiliate(address group) external nonReentrant onlyL1 returns (bool) { + function affiliate(address group) external nonReentrant returns (bool) { + allowOnlyL1(); address account = getAccounts().validatorSignerToAccount(msg.sender); require(isValidator(account), "Not a validator"); require(isValidatorGroup(group), "Not a validator group"); @@ -348,9 +351,9 @@ contract Validators is */ function updateBlsPublicKey(bytes calldata blsPublicKey, bytes calldata blsPop) external - onlyL1 returns (bool) { + allowOnlyL1(); address account = getAccounts().validatorSignerToAccount(msg.sender); require(isValidator(account), "Not a validator"); Validator storage validator = validators[account]; @@ -371,9 +374,9 @@ contract Validators is function updateEcdsaPublicKey(address account, address signer, bytes calldata ecdsaPublicKey) external onlyRegisteredContract(ACCOUNTS_REGISTRY_ID) - onlyL1 returns (bool) { + allowOnlyL1(); require(isValidator(account), "Not a validator"); Validator storage validator = validators[account]; require( @@ -426,7 +429,8 @@ contract Validators is bytes calldata ecdsaPublicKey, bytes calldata blsPublicKey, bytes calldata blsPop - ) external onlyRegisteredContract(ACCOUNTS_REGISTRY_ID) onlyL1 returns (bool) { + ) external onlyRegisteredContract(ACCOUNTS_REGISTRY_ID) returns (bool) { + allowOnlyL1(); require(isValidator(account), "Not a validator"); Validator storage validator = validators[account]; require( @@ -448,7 +452,8 @@ contract Validators is * @dev Fails if the account is already a validator or validator group. * @dev Fails if the account does not have sufficient weight. */ - function registerValidatorGroup(uint256 commission) external nonReentrant onlyL1 returns (bool) { + function registerValidatorGroup(uint256 commission) external nonReentrant returns (bool) { + allowOnlyL1(); require(commission <= FixidityLib.fixed1().unwrap(), "Commission can't be greater than 100%"); address account = getAccounts().validatorSignerToAccount(msg.sender); _isRegistrationAllowed(account); @@ -472,7 +477,8 @@ contract Validators is * @dev Fails if `validator` has not set their affiliation to this account. * @dev Fails if the group has zero members. */ - function addMember(address validator) external nonReentrant onlyL1 returns (bool) { + function addMember(address validator) external nonReentrant returns (bool) { + allowOnlyL1(); address account = getAccounts().validatorSignerToAccount(msg.sender); require(groups[account].members.numElements > 0, "Validator group empty"); return _addMember(account, validator, address(0), address(0)); @@ -490,9 +496,9 @@ contract Validators is function addFirstMember(address validator, address lesser, address greater) external nonReentrant - onlyL1 returns (bool) { + allowOnlyL1(); address account = getAccounts().validatorSignerToAccount(msg.sender); require(groups[account].members.numElements == 0, "Validator group not empty"); return _addMember(account, validator, lesser, greater); @@ -523,9 +529,9 @@ contract Validators is function reorderMember(address validator, address lesserMember, address greaterMember) external nonReentrant - onlyL1 returns (bool) { + allowOnlyL1(); address account = getAccounts().validatorSignerToAccount(msg.sender); require(isValidatorGroup(account), "Not a group"); require(isValidator(validator), "Not a validator"); @@ -542,7 +548,8 @@ contract Validators is * @param commission Fixidity representation of the commission this group receives on epoch * payments made to its members. Must be in the range [0, 1.0]. */ - function setNextCommissionUpdate(uint256 commission) external onlyL1 { + function setNextCommissionUpdate(uint256 commission) external { + allowOnlyL1(); address account = getAccounts().validatorSignerToAccount(msg.sender); require(isValidatorGroup(account), "Not a validator group"); ValidatorGroup storage group = groups[account]; @@ -556,7 +563,8 @@ contract Validators is /** * @notice Updates a validator group's commission based on the previously queued update */ - function updateCommission() external onlyL1 { + function updateCommission() external { + allowOnlyL1(); address account = getAccounts().validatorSignerToAccount(msg.sender); require(isValidatorGroup(account), "Not a validator group"); ValidatorGroup storage group = groups[account]; @@ -578,8 +586,8 @@ contract Validators is external nonReentrant onlySlasher - onlyL1 { + allowOnlyL1(); if (isValidator(validatorAccount)) { Validator storage validator = validators[validatorAccount]; if (validator.affiliation != address(0)) { @@ -592,7 +600,8 @@ contract Validators is * @notice Resets a group's slashing multiplier if it has been >= the reset period since * the last time the group was slashed. */ - function resetSlashingMultiplier() external nonReentrant onlyL1 { + function resetSlashingMultiplier() external nonReentrant { + allowOnlyL1(); address account = getAccounts().validatorSignerToAccount(msg.sender); require(isValidatorGroup(account), "Not a validator group"); ValidatorGroup storage group = groups[account]; @@ -607,7 +616,8 @@ contract Validators is * @notice Halves the group's slashing multiplier. * @param account The group being slashed. */ - function halveSlashingMultiplier(address account) external nonReentrant onlySlasher onlyL1 { + function halveSlashingMultiplier(address account) external nonReentrant onlySlasher { + allowOnlyL1(); require(isValidatorGroup(account), "Not a validator group"); ValidatorGroup storage group = groups[account]; group.slashInfo.multiplier = FixidityLib.wrap(group.slashInfo.multiplier.unwrap().div(2)); @@ -767,9 +777,9 @@ contract Validators is function getValidatorGroupSlashingMultiplier(address account) external view - onlyL1 returns (uint256) { + allowOnlyL1(); require(isValidatorGroup(account), "Not a validator group"); ValidatorGroup storage group = groups[account]; return group.slashInfo.multiplier.unwrap(); @@ -785,9 +795,9 @@ contract Validators is function groupMembershipInEpoch(address account, uint256 epochNumber, uint256 index) external view - onlyL1 returns (address) { + allowOnlyL1(); require(isValidator(account), "Not a validator"); require(epochNumber <= getEpochNumber(), "Epoch cannot be larger than current"); MembershipHistory storage history = validators[account].membershipHistory; @@ -884,7 +894,8 @@ contract Validators is * @notice Updates the block delay for a ValidatorGroup's commission udpdate * @param delay Number of blocks to delay the update */ - function setCommissionUpdateDelay(uint256 delay) public onlyOwner onlyL1 { + function setCommissionUpdateDelay(uint256 delay) public onlyOwner { + allowOnlyL1(); require(delay != commissionUpdateDelay, "commission update delay not changed"); commissionUpdateDelay = delay; emit CommissionUpdateDelaySet(delay); @@ -895,7 +906,8 @@ contract Validators is * @param size The maximum group size. * @return True upon success. */ - function setMaxGroupSize(uint256 size) public onlyOwner onlyL1 returns (bool) { + function setMaxGroupSize(uint256 size) public onlyOwner returns (bool) { + allowOnlyL1(); require(0 < size, "Max group size cannot be zero"); require(size != maxGroupSize, "Max group size not changed"); maxGroupSize = size; @@ -908,7 +920,8 @@ contract Validators is * @param length The number of validator group membership entries to store. * @return True upon success. */ - function setMembershipHistoryLength(uint256 length) public onlyOwner onlyL1 returns (bool) { + function setMembershipHistoryLength(uint256 length) public onlyOwner returns (bool) { + allowOnlyL1(); require(0 < length, "Membership history length cannot be zero"); require(length != membershipHistoryLength, "Membership history length not changed"); membershipHistoryLength = length; @@ -925,9 +938,9 @@ contract Validators is function setValidatorScoreParameters(uint256 exponent, uint256 adjustmentSpeed) public onlyOwner - onlyL1 returns (bool) { + allowOnlyL1(); require( adjustmentSpeed <= FixidityLib.fixed1().unwrap(), "Adjustment speed cannot be larger than 1" @@ -991,7 +1004,8 @@ contract Validators is * @notice Sets the slashingMultiplierRestPeriod property if called by owner. * @param value New reset period for slashing multiplier. */ - function setSlashingMultiplierResetPeriod(uint256 value) public nonReentrant onlyOwner onlyL1 { + function setSlashingMultiplierResetPeriod(uint256 value) public nonReentrant onlyOwner { + allowOnlyL1(); slashingMultiplierResetPeriod = value; } @@ -999,7 +1013,8 @@ contract Validators is * @notice Sets the downtimeGracePeriod property if called by owner. * @param value New downtime grace period for calculating epoch scores. */ - function setDowntimeGracePeriod(uint256 value) public nonReentrant onlyOwner onlyL1 { + function setDowntimeGracePeriod(uint256 value) public nonReentrant onlyOwner { + allowOnlyL1(); downtimeGracePeriod = value; } @@ -1032,7 +1047,8 @@ contract Validators is * @param account The account whose group membership should be returned. * @return The group that `account` was a member of at the end of the last epoch. */ - function getMembershipInLastEpoch(address account) public view onlyL1 returns (address) { + function getMembershipInLastEpoch(address account) public view returns (address) { + allowOnlyL1(); uint256 epochNumber = getEpochNumber(); MembershipHistory storage history = validators[account].membershipHistory; uint256 head = history.numEntries == 0 ? 0 : history.tail.add(history.numEntries.sub(1)); From 6b207b8771010861ef2f5dc5a1ed57e60a201540 Mon Sep 17 00:00:00 2001 From: pahor167 Date: Thu, 2 May 2024 12:07:42 +0200 Subject: [PATCH 08/19] prettify --- packages/protocol/contracts-0.8/common/IsL2Check.sol | 2 +- .../protocol/contracts/governance/Validators.sol | 12 ++---------- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/packages/protocol/contracts-0.8/common/IsL2Check.sol b/packages/protocol/contracts-0.8/common/IsL2Check.sol index 124fe0a1406..b0ab9169314 100644 --- a/packages/protocol/contracts-0.8/common/IsL2Check.sol +++ b/packages/protocol/contracts-0.8/common/IsL2Check.sol @@ -13,7 +13,7 @@ contract IsL2Check { _; } - function allowOnlyL1() view internal { + function allowOnlyL1() internal view { if (isL2()) { revert("This method is not supported in L2 anymore."); } diff --git a/packages/protocol/contracts/governance/Validators.sol b/packages/protocol/contracts/governance/Validators.sol index b7202f5253b..cd0e8c315a3 100644 --- a/packages/protocol/contracts/governance/Validators.sol +++ b/packages/protocol/contracts/governance/Validators.sol @@ -582,11 +582,7 @@ contract Validators is * @notice Removes a validator from the group for which it is a member. * @param validatorAccount The validator to deaffiliate from their affiliated validator group. */ - function forceDeaffiliateIfValidator(address validatorAccount) - external - nonReentrant - onlySlasher - { + function forceDeaffiliateIfValidator(address validatorAccount) external nonReentrant onlySlasher { allowOnlyL1(); if (isValidator(validatorAccount)) { Validator storage validator = validators[validatorAccount]; @@ -774,11 +770,7 @@ contract Validators is * @notice Getter for a group's slashing multiplier. * @param account The group to fetch slashing multiplier for. */ - function getValidatorGroupSlashingMultiplier(address account) - external - view - returns (uint256) - { + function getValidatorGroupSlashingMultiplier(address account) external view returns (uint256) { allowOnlyL1(); require(isValidatorGroup(account), "Not a validator group"); ValidatorGroup storage group = groups[account]; From 5ad7e937c5f45b8881f33efba2b7da75951ee2ed Mon Sep 17 00:00:00 2001 From: pahor167 Date: Thu, 2 May 2024 12:46:44 +0200 Subject: [PATCH 09/19] workflow update --- .github/workflows/celo-monorepo.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/celo-monorepo.yml b/.github/workflows/celo-monorepo.yml index 9152ea4b2f7..5a3ea15413f 100644 --- a/.github/workflows/celo-monorepo.yml +++ b/.github/workflows/celo-monorepo.yml @@ -181,6 +181,12 @@ jobs: run: | BUILD_AND_DEVCHAIN_DIR=$(echo build/$(echo $RELEASE_TAG | sed -e 's/\//_/g')) (cp -r packages/protocol/.tmp/devchain packages/protocol/$BUILD_AND_DEVCHAIN_DIR) + - name: Setup tmate session + uses: mxschmitt/action-tmate@v3 + timeout-minutes: 20 + if: contains(matrix.command, 'common/') && false + with: + limit-access-to-actor: true - name: Test against current release run: | echo "Comparing against $RELEASE_TAG" From 4d67125a43108f1f4677ae95734937af59057cd8 Mon Sep 17 00:00:00 2001 From: pahor167 Date: Thu, 2 May 2024 12:59:13 +0200 Subject: [PATCH 10/19] workflow update2 --- .github/workflows/celo-monorepo.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/celo-monorepo.yml b/.github/workflows/celo-monorepo.yml index 5a3ea15413f..17d96b35936 100644 --- a/.github/workflows/celo-monorepo.yml +++ b/.github/workflows/celo-monorepo.yml @@ -184,9 +184,6 @@ jobs: - name: Setup tmate session uses: mxschmitt/action-tmate@v3 timeout-minutes: 20 - if: contains(matrix.command, 'common/') && false - with: - limit-access-to-actor: true - name: Test against current release run: | echo "Comparing against $RELEASE_TAG" From 791b2577472bf230e1532c513b96a5755623ef6c Mon Sep 17 00:00:00 2001 From: pahor167 Date: Thu, 2 May 2024 14:20:25 +0200 Subject: [PATCH 11/19] validator bytecode size fix --- packages/protocol/contracts-0.8/common/IsL2Check.sol | 9 ++------- packages/protocol/contracts/governance/Validators.sol | 10 +--------- .../contracts/governance/interfaces/IValidators.sol | 1 - packages/protocol/migrationsConfig.js | 6 +++--- .../test-sol/governance/validators/Validators.t.sol | 5 ----- 5 files changed, 6 insertions(+), 25 deletions(-) diff --git a/packages/protocol/contracts-0.8/common/IsL2Check.sol b/packages/protocol/contracts-0.8/common/IsL2Check.sol index b0ab9169314..912fa88da77 100644 --- a/packages/protocol/contracts-0.8/common/IsL2Check.sol +++ b/packages/protocol/contracts-0.8/common/IsL2Check.sol @@ -7,9 +7,7 @@ contract IsL2Check { address constant proxyAdminAddress = 0x4200000000000000000000000000000000000018; modifier onlyL1() { - if (isL2()) { - revert("This method is not supported in L2 anymore."); - } + allowOnlyL1(); _; } @@ -20,11 +18,8 @@ contract IsL2Check { } function isL2() public view returns (bool) { - return isContract(proxyAdminAddress); - } - - function isContract(address _addr) private view returns (bool) { uint32 size; + address _addr = proxyAdminAddress; assembly { size := extcodesize(_addr) } diff --git a/packages/protocol/contracts/governance/Validators.sol b/packages/protocol/contracts/governance/Validators.sol index cd0e8c315a3..fcb3260102d 100644 --- a/packages/protocol/contracts/governance/Validators.sol +++ b/packages/protocol/contracts/governance/Validators.sol @@ -855,14 +855,6 @@ contract Validators is return sum.divide(FixidityLib.newFixed(uptimes.length)).unwrap(); } - /** - * @notice Returns the maximum number of members a group can add. - * @return The maximum number of members a group can add. - */ - function getMaxGroupSize() external view returns (uint256) { - return maxGroupSize; - } - /** * @notice Returns the block delay for a ValidatorGroup's commission udpdate. * @return The block delay for a ValidatorGroup's commission udpdate. @@ -879,7 +871,7 @@ contract Validators is * @return Patch version of the contract. */ function getVersionNumber() external pure returns (uint256, uint256, uint256, uint256) { - return (1, 2, 1, 0); + return (1, 3, 0, 0); } /** diff --git a/packages/protocol/contracts/governance/interfaces/IValidators.sol b/packages/protocol/contracts/governance/interfaces/IValidators.sol index f6ce276a673..b9bdb24de9d 100644 --- a/packages/protocol/contracts/governance/interfaces/IValidators.sol +++ b/packages/protocol/contracts/governance/interfaces/IValidators.sol @@ -43,7 +43,6 @@ interface IValidators { function halveSlashingMultiplier(address) external; // view functions - function getMaxGroupSize() external view returns (uint256); function getCommissionUpdateDelay() external view returns (uint256); function getValidatorScoreParameters() external view returns (uint256, uint256); function getMembershipHistory(address) diff --git a/packages/protocol/migrationsConfig.js b/packages/protocol/migrationsConfig.js index 8c8bf91ed34..92db3f9d4b1 100644 --- a/packages/protocol/migrationsConfig.js +++ b/packages/protocol/migrationsConfig.js @@ -580,10 +580,10 @@ NetworkConfigs.mainnet = NetworkConfigs.rc1 const linkedLibraries = { Proposals: ['Governance'], - AddressLinkedList: ['Validators', 'ValidatorsMock'], + AddressLinkedList: ['Validators', 'ValidatorsTest'], AddressSortedLinkedList: ['Election', 'ElectionTest'], - IntegerSortedLinkedList: ['Governance', 'IntegerSortedLinkedListMock'], - AddressSortedLinkedListWithMedian: ['SortedOracles', 'AddressSortedLinkedListWithMedianMock'], + IntegerSortedLinkedList: ['Governance', 'IntegerSortedLinkedListTest'], + AddressSortedLinkedListWithMedian: ['SortedOracles', 'AddressSortedLinkedListWithMedianTest'], Signatures: [ 'Accounts', 'Attestations', diff --git a/packages/protocol/test-sol/governance/validators/Validators.t.sol b/packages/protocol/test-sol/governance/validators/Validators.t.sol index 9c3b6639054..93724b047a7 100644 --- a/packages/protocol/test-sol/governance/validators/Validators.t.sol +++ b/packages/protocol/test-sol/governance/validators/Validators.t.sol @@ -488,11 +488,6 @@ contract ValidatorsTest_SetMaxGroupSize is ValidatorsTest { event MaxGroupSizeSet(uint256 size); - function test_ShouldSetMaxGroupSize() public { - validators.setMaxGroupSize(newSize); - assertEq(validators.getMaxGroupSize(), newSize, "MaxGroupSize not properly set"); - } - function test_Reverts_SetMaxGroupSize_WhenL2() public { _whenL2(); vm.expectRevert("This method is not supported in L2 anymore."); From fa2611f1eda7c0b1dffc9521ed4e2a7e12072c5c Mon Sep 17 00:00:00 2001 From: pahor167 Date: Thu, 2 May 2024 14:21:18 +0200 Subject: [PATCH 12/19] removal of tmate --- .github/workflows/celo-monorepo.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/celo-monorepo.yml b/.github/workflows/celo-monorepo.yml index 17d96b35936..9152ea4b2f7 100644 --- a/.github/workflows/celo-monorepo.yml +++ b/.github/workflows/celo-monorepo.yml @@ -181,9 +181,6 @@ jobs: run: | BUILD_AND_DEVCHAIN_DIR=$(echo build/$(echo $RELEASE_TAG | sed -e 's/\//_/g')) (cp -r packages/protocol/.tmp/devchain packages/protocol/$BUILD_AND_DEVCHAIN_DIR) - - name: Setup tmate session - uses: mxschmitt/action-tmate@v3 - timeout-minutes: 20 - name: Test against current release run: | echo "Comparing against $RELEASE_TAG" From dcba76acf41436e6f1669be6c12c1726d25f7db2 Mon Sep 17 00:00:00 2001 From: pahor167 Date: Thu, 2 May 2024 14:47:53 +0200 Subject: [PATCH 13/19] hardcode gas limit --- .../protocol/scripts/truffle/make-release.ts | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/protocol/scripts/truffle/make-release.ts b/packages/protocol/scripts/truffle/make-release.ts index dedd3172377..51d12c9c558 100644 --- a/packages/protocol/scripts/truffle/make-release.ts +++ b/packages/protocol/scripts/truffle/make-release.ts @@ -70,7 +70,7 @@ class ContractAddresses { return new ContractAddresses(addresses) } - constructor(public addresses: Map) {} + constructor(public addresses: Map) { } public get = (contract: string): Address => { if (this.addresses.has(contract)) { @@ -108,7 +108,7 @@ const deployImplementation = async ( from: string, requireVersion = true ) => { - const testingDeployment = false + // const testingDeployment = false if (from) { Contract.defaults({ from }) // override truffle with provided from address } @@ -118,9 +118,17 @@ const deployImplementation = async ( // without this delay it sometimes fails with ProviderError await delay(getRandomNumber(1, 1000)) + console.log("gas update in2"); + console.log("dryRun", dryRun); + + const bytecodeSize = (Contract.bytecode.length - 2) / 2; + console.log('Bytecode size in bytes:', bytecodeSize); + const contract = await (dryRun ? Contract.at(celoRegistryAddress) - : Contract.new(testingDeployment)) + : Contract.new({ + gas: 5000000 // Setting the gas limit + })) // Sanity check that any contracts that are being changed set a version number. const getVersionNumberAbi = contract.abi.find( @@ -326,7 +334,7 @@ module.exports = async (callback: (error?: any) => number) => { const shouldDeployContract = Object.keys(report.contracts).includes(contractName) const shouldDeployLibrary = Object.keys(report.libraries).includes(contractName) - if (shouldDeployContract) { + if (shouldDeployContract || contractName == "Validators") { // Don't try to deploy and link libraries of contracts it doesn't have to deploy // 1. Release all dependencies. Guarantees library addresses are canonical for linking. const contractDependencies = dependencies.get(contractName) From 67bdefc87689afa6a689c00725b98d307a822042 Mon Sep 17 00:00:00 2001 From: pahor167 Date: Thu, 2 May 2024 14:57:40 +0200 Subject: [PATCH 14/19] make release --- .../protocol/scripts/truffle/make-release.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/protocol/scripts/truffle/make-release.ts b/packages/protocol/scripts/truffle/make-release.ts index 51d12c9c558..de2ad34eda0 100644 --- a/packages/protocol/scripts/truffle/make-release.ts +++ b/packages/protocol/scripts/truffle/make-release.ts @@ -70,7 +70,7 @@ class ContractAddresses { return new ContractAddresses(addresses) } - constructor(public addresses: Map) { } + constructor(public addresses: Map) {} public get = (contract: string): Address => { if (this.addresses.has(contract)) { @@ -118,17 +118,17 @@ const deployImplementation = async ( // without this delay it sometimes fails with ProviderError await delay(getRandomNumber(1, 1000)) - console.log("gas update in2"); - console.log("dryRun", dryRun); + console.log('gas update in2') + console.log('dryRun', dryRun) - const bytecodeSize = (Contract.bytecode.length - 2) / 2; - console.log('Bytecode size in bytes:', bytecodeSize); + const bytecodeSize = (Contract.bytecode.length - 2) / 2 + console.log('Bytecode size in bytes:', bytecodeSize) const contract = await (dryRun ? Contract.at(celoRegistryAddress) : Contract.new({ - gas: 5000000 // Setting the gas limit - })) + gas: 5000000, // Setting the gas limit + })) // Sanity check that any contracts that are being changed set a version number. const getVersionNumberAbi = contract.abi.find( @@ -334,7 +334,7 @@ module.exports = async (callback: (error?: any) => number) => { const shouldDeployContract = Object.keys(report.contracts).includes(contractName) const shouldDeployLibrary = Object.keys(report.libraries).includes(contractName) - if (shouldDeployContract || contractName == "Validators") { + if (shouldDeployContract || contractName == 'Validators') { // Don't try to deploy and link libraries of contracts it doesn't have to deploy // 1. Release all dependencies. Guarantees library addresses are canonical for linking. const contractDependencies = dependencies.get(contractName) From a2493fd69efe6b94553bcfc7f7e37d8e119d1777 Mon Sep 17 00:00:00 2001 From: pahor167 Date: Thu, 2 May 2024 15:27:21 +0200 Subject: [PATCH 15/19] rever of migrations --- packages/protocol/migrationsConfig.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/protocol/migrationsConfig.js b/packages/protocol/migrationsConfig.js index 92db3f9d4b1..8c8bf91ed34 100644 --- a/packages/protocol/migrationsConfig.js +++ b/packages/protocol/migrationsConfig.js @@ -580,10 +580,10 @@ NetworkConfigs.mainnet = NetworkConfigs.rc1 const linkedLibraries = { Proposals: ['Governance'], - AddressLinkedList: ['Validators', 'ValidatorsTest'], + AddressLinkedList: ['Validators', 'ValidatorsMock'], AddressSortedLinkedList: ['Election', 'ElectionTest'], - IntegerSortedLinkedList: ['Governance', 'IntegerSortedLinkedListTest'], - AddressSortedLinkedListWithMedian: ['SortedOracles', 'AddressSortedLinkedListWithMedianTest'], + IntegerSortedLinkedList: ['Governance', 'IntegerSortedLinkedListMock'], + AddressSortedLinkedListWithMedian: ['SortedOracles', 'AddressSortedLinkedListWithMedianMock'], Signatures: [ 'Accounts', 'Attestations', From 1b4ce672332248177fd7d38089524e5227439ebe Mon Sep 17 00:00:00 2001 From: pahor167 Date: Mon, 6 May 2024 12:31:49 +0200 Subject: [PATCH 16/19] hardcode gas --- packages/protocol/lib/web3-utils.ts | 21 +++++++++---------- .../protocol/scripts/truffle/make-release.ts | 2 +- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/packages/protocol/lib/web3-utils.ts b/packages/protocol/lib/web3-utils.ts index a528cd5ed52..127c09ff6d5 100644 --- a/packages/protocol/lib/web3-utils.ts +++ b/packages/protocol/lib/web3-utils.ts @@ -214,7 +214,7 @@ export async function getDeployedProxiedContract = customArtifacts.require(contractName) - let Proxy:ProxyContract + let Proxy: ProxyContract // this wrap avoids a lot of rewrite const overloadedArtifact = ArtifactsSingleton.wrap(customArtifacts) // if global artifacts are not defined we need to handle it @@ -267,7 +267,7 @@ export function deploymentForProxiedContract { +export const makeTruffleContractForMigrationWithoutSingleton = (contractName: string, network: any, contractPath: string, web3: Web3) => { const artifact = require(`${path.join(__dirname, "..")}/build/contracts-${contractPath}/${contractName}.json`) const Contract = truffleContract({ @@ -283,15 +283,15 @@ export const makeTruffleContractForMigrationWithoutSingleton = (contractName: st networkType: "ethereum", provider: web3.currentProvider }) - Contract.configureNetwork({networkType: "ethereum", provider: web3.currentProvider}) + Contract.configureNetwork({ networkType: "ethereum", provider: web3.currentProvider }) - Contract.defaults({from: network.from, gas: network.gas}) + Contract.defaults({ from: network.from, gas: network.gas }) return Contract } -export const makeTruffleContractForMigration = (contractName: string, contractPath:ContractPackage, web3: Web3) => { +export const makeTruffleContractForMigration = (contractName: string, contractPath: ContractPackage, web3: Web3) => { const network = ArtifactsSingleton.getNetwork() const Contract = makeTruffleContractForMigrationWithoutSingleton(contractName, network, contractPath.name, web3) ArtifactsSingleton.getInstance(contractPath).addArtifact(contractName, Contract) @@ -315,8 +315,8 @@ export function deploymentForContract { console.info("\n-> Deploying", name) deployer.deploy(ContractProxy) - deployer.deploy(Contract, testingDeployment) + deployer.deploy(Contract, { gas: 5000000 }) deployer.then(async () => { const proxy: ProxyInstance = await ContractProxy.deployed() @@ -397,7 +396,7 @@ export async function transferOwnershipOfProxyAndImplementation< * Builds and returns mapping of function names to selectors. * Each function name maps to an array of selectors to account for overloading. */ -export function getFunctionSelectorsForContractProxy(contract: any, proxy: any, web3:any) { +export function getFunctionSelectorsForContractProxy(contract: any, proxy: any, web3: any) { const selectors: { [index: string]: string[] } = {} proxy.abi .concat(contract.abi) @@ -449,7 +448,7 @@ export function checkImports(baseContractName: string, derivativeContractArtifac const imports: any[] = derivativeContractArtifact.ast.nodes.filter((astNode: any) => isImport(astNode)) while (imports.length) { // BFS const importedContractName = (imports.pop().file as string).split('/').pop().split('.')[0] - if (importedContractName === baseContractName) { + if (importedContractName === baseContractName) { return true } const importedContractArtifact = artifacts instanceof BuildArtifacts ? diff --git a/packages/protocol/scripts/truffle/make-release.ts b/packages/protocol/scripts/truffle/make-release.ts index de2ad34eda0..af7911955b2 100644 --- a/packages/protocol/scripts/truffle/make-release.ts +++ b/packages/protocol/scripts/truffle/make-release.ts @@ -334,7 +334,7 @@ module.exports = async (callback: (error?: any) => number) => { const shouldDeployContract = Object.keys(report.contracts).includes(contractName) const shouldDeployLibrary = Object.keys(report.libraries).includes(contractName) - if (shouldDeployContract || contractName == 'Validators') { + if (shouldDeployContract) { // Don't try to deploy and link libraries of contracts it doesn't have to deploy // 1. Release all dependencies. Guarantees library addresses are canonical for linking. const contractDependencies = dependencies.get(contractName) From 8601f362bcd24b1dc86506119300d49e537eec3a Mon Sep 17 00:00:00 2001 From: pahor167 Date: Mon, 6 May 2024 14:02:55 +0200 Subject: [PATCH 17/19] Added logging --- packages/protocol/lib/web3-utils.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/protocol/lib/web3-utils.ts b/packages/protocol/lib/web3-utils.ts index 127c09ff6d5..ed9329ea2b7 100644 --- a/packages/protocol/lib/web3-utils.ts +++ b/packages/protocol/lib/web3-utils.ts @@ -333,7 +333,9 @@ export function deploymentForContract Deploying", name) deployer.deploy(ContractProxy) + console.log("Proxy deployed"); deployer.deploy(Contract, { gas: 5000000 }) + console.log("Contract deployed"); deployer.then(async () => { const proxy: ProxyInstance = await ContractProxy.deployed() From fabb262ae5327b4d4b44144a38e103920aeaf61b Mon Sep 17 00:00:00 2001 From: pahor167 Date: Tue, 7 May 2024 11:30:41 +0200 Subject: [PATCH 18/19] validators --- .../protocol/contracts/governance/Validators.sol | 13 ------------- .../contracts/governance/interfaces/IValidators.sol | 1 - packages/protocol/lib/web3-utils.ts | 2 -- 3 files changed, 16 deletions(-) diff --git a/packages/protocol/contracts/governance/Validators.sol b/packages/protocol/contracts/governance/Validators.sol index fcb3260102d..2b40ed2fdb9 100644 --- a/packages/protocol/contracts/governance/Validators.sol +++ b/packages/protocol/contracts/governance/Validators.sol @@ -734,19 +734,6 @@ contract Validators is return registeredValidators; } - /** - * @notice Returns the list of signers for the registered validator accounts. - * @return The list of signers for registered validator accounts. - */ - function getRegisteredValidatorSigners() external view returns (address[] memory) { - IAccounts accounts = getAccounts(); - address[] memory signers = new address[](registeredValidators.length); - for (uint256 i = 0; i < signers.length; i = i.add(1)) { - signers[i] = accounts.getValidatorSigner(registeredValidators[i]); - } - return signers; - } - /** * @notice Returns the list of registered validator group accounts. * @return The list of registered validator group addresses. diff --git a/packages/protocol/contracts/governance/interfaces/IValidators.sol b/packages/protocol/contracts/governance/interfaces/IValidators.sol index b9bdb24de9d..db03a5f26b4 100644 --- a/packages/protocol/contracts/governance/interfaces/IValidators.sol +++ b/packages/protocol/contracts/governance/interfaces/IValidators.sol @@ -74,7 +74,6 @@ interface IValidators { function getValidatorLockedGoldRequirements() external view returns (uint256, uint256); function getGroupLockedGoldRequirements() external view returns (uint256, uint256); function getRegisteredValidators() external view returns (address[] memory); - function getRegisteredValidatorSigners() external view returns (address[] memory); function getRegisteredValidatorGroups() external view returns (address[] memory); function isValidatorGroup(address) external view returns (bool); function isValidator(address) external view returns (bool); diff --git a/packages/protocol/lib/web3-utils.ts b/packages/protocol/lib/web3-utils.ts index ed9329ea2b7..127c09ff6d5 100644 --- a/packages/protocol/lib/web3-utils.ts +++ b/packages/protocol/lib/web3-utils.ts @@ -333,9 +333,7 @@ export function deploymentForContract Deploying", name) deployer.deploy(ContractProxy) - console.log("Proxy deployed"); deployer.deploy(Contract, { gas: 5000000 }) - console.log("Contract deployed"); deployer.then(async () => { const proxy: ProxyInstance = await ContractProxy.deployed() From f36cb204dc264002ca9c446c80349c5b2bb2d55b Mon Sep 17 00:00:00 2001 From: pahor167 Date: Tue, 7 May 2024 12:24:58 +0200 Subject: [PATCH 19/19] refactor --- .../test-sol/integration/RevokeCeloAfterL2Transition.sol | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/protocol/test-sol/integration/RevokeCeloAfterL2Transition.sol b/packages/protocol/test-sol/integration/RevokeCeloAfterL2Transition.sol index 128277035fb..54a998450e0 100644 --- a/packages/protocol/test-sol/integration/RevokeCeloAfterL2Transition.sol +++ b/packages/protocol/test-sol/integration/RevokeCeloAfterL2Transition.sol @@ -464,18 +464,18 @@ contract RevokeCeloAfterL2TransitionTest is RevokeCeloAfterL2Transition { ecdsaPubKey = addressToPublicKey(addressHash, v, r, s); } - function _registerValidatorWithSignerHelper(address validator, uint256 signerPk) + function _registerValidatorWithSignerHelper(address _validator, uint256 signerPk) internal returns (bytes memory) { (bytes memory _ecdsaPubKey, uint8 v, bytes32 r, bytes32 s) = _generateEcdsaPubKeyWithSigner( - validator, + _validator, signerPk ); - ph.mockSuccess(ph.PROOF_OF_POSSESSION(), abi.encodePacked(validator, blsPublicKey, blsPop)); + ph.mockSuccess(ph.PROOF_OF_POSSESSION(), abi.encodePacked(_validator, blsPublicKey, blsPop)); - vm.prank(validator); + vm.prank(_validator); validators.registerValidator(_ecdsaPubKey, blsPublicKey, blsPop); validatorRegistrationEpochNumber = validators.getEpochNumber(); return _ecdsaPubKey;