Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Epoch manager enabler tests #11213

Merged
merged 8 commits into from
Sep 20, 2024
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions packages/protocol/contracts-0.8/common/EpochManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -126,10 +126,6 @@ contract EpochManager is
uint256 firstEpochBlock,
address[] memory firstElected
) external onlyEpochManagerEnabler {
require(
address(registry.getAddressForOrDie(CELO_UNRELEASED_TREASURE_REGISTRY_ID)).balance > 0,
"CeloUnreleasedTreasury not yet funded."
);
require(
getCeloToken().balanceOf(registry.getAddressForOrDie(CELO_UNRELEASED_TREASURE_REGISTRY_ID)) >
0,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,13 @@ contract EpochManagerEnabler is
emit LastKnownElectedAccountsSet();
}

/**
* @return a list of know elected validator accounts.
*/
function getlastKnownElectedAccounts() external view returns (address[] memory) {
return lastKnownElectedAccounts;
}

/**
* @notice Returns the storage, major, minor, and patch version of the contract.
* @return Storage version of the contract.
Expand Down
8 changes: 5 additions & 3 deletions packages/protocol/contracts-0.8/common/UsingPrecompiles.sol
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,9 @@ contract UsingPrecompiles is IsL2Check {
* @param index Index of requested validator in the validator set.
* @return Address of validator at the requested index.
*/
function validatorSignerAddressFromCurrentSet(uint256 index) public view returns (address) {
function validatorSignerAddressFromCurrentSet(
uint256 index
) public view virtual returns (address) {
bytes memory out;
bool success;
(success, out) = GET_VALIDATOR.staticcall(abi.encodePacked(index, uint256(block.number)));
Expand Down Expand Up @@ -118,7 +120,7 @@ contract UsingPrecompiles is IsL2Check {
* @notice Gets the size of the current elected validator set.
* @return Size of the current elected validator set.
*/
function numberValidatorsInCurrentSet() public view returns (uint256) {
function numberValidatorsInCurrentSet() public view virtual returns (uint256) {
bytes memory out;
bool success;
(success, out) = NUMBER_VALIDATORS.staticcall(abi.encodePacked(uint256(block.number)));
Expand All @@ -131,7 +133,7 @@ contract UsingPrecompiles is IsL2Check {
* @param blockNumber Block number to retrieve the validator set from.
* @return Size of the validator set.
*/
function numberValidatorsInSet(uint256 blockNumber) public view returns (uint256) {
function numberValidatorsInSet(uint256 blockNumber) public view virtual returns (uint256) {
bytes memory out;
bool success;
(success, out) = NUMBER_VALIDATORS.staticcall(abi.encodePacked(blockNumber));
Expand Down
13 changes: 0 additions & 13 deletions packages/protocol/contracts-0.8/common/test/MockCeloToken.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,6 @@ contract MockCeloToken08 {
uint8 public constant decimals = 18;
mapping(address => uint256) balances;

uint256 constant L1_MINTED_CELO_SUPPLY = 692702432463315819704447326; // as of May 15 2024

uint256 constant CELO_SUPPLY_CAP = 1000000000 ether; // 1 billion Celo
uint256 constant GENESIS_CELO_SUPPLY = 600000000 ether; // 600 million Celo

uint256 constant FIFTEEN_YEAR_LINEAR_REWARD = (CELO_SUPPLY_CAP - GENESIS_CELO_SUPPLY) / 2; // 200 million Celo

uint256 constant FIFTEEN_YEAR_CELO_SUPPLY = GENESIS_CELO_SUPPLY + FIFTEEN_YEAR_LINEAR_REWARD; // 800 million Celo (includes GENESIS_CELO_SUPPLY)

uint256 constant MAX_L2_DISTRIBUTION = FIFTEEN_YEAR_CELO_SUPPLY - L1_MINTED_CELO_SUPPLY; // 107.2 million Celo

uint256 constant L2_INITIAL_STASH_BALANCE = FIFTEEN_YEAR_LINEAR_REWARD + MAX_L2_DISTRIBUTION; // leftover from L1 target supply plus the 2nd 15 year term.

function setTotalSupply(uint256 value) external {
totalSupply_ = value;
}
Expand Down
33 changes: 33 additions & 0 deletions packages/protocol/test-sol/mocks/EpochManagerEnablerMock.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
pragma solidity ^0.8.0;

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

/**
* @title A wrapper around EpochManagerEnabler that exposes internal functions for testing.
*/
contract EpochManagerEnablerMock is EpochManagerEnabler(true) {
address[] validatorSet;

function setFirstBlockOfEpoch() external {
return _setFirstBlockOfEpoch();
}

function addValidator(address validator) external {
validatorSet.push(validator);
}

// Minimally override core functions from UsingPrecompiles
function numberValidatorsInCurrentSet() public view override returns (uint256) {
return validatorSet.length;
}

function numberValidatorsInSet(uint256) public view override returns (uint256) {
return validatorSet.length;
}

function validatorSignerAddressFromCurrentSet(
uint256 index
) public view override returns (address) {
return validatorSet[index];
}
}
180 changes: 161 additions & 19 deletions packages/protocol/test-sol/unit/common/EpochManagerEnabler.t.sol
Original file line number Diff line number Diff line change
@@ -1,37 +1,179 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.8.7 <0.8.20;
pragma solidity >=0.8.0 <0.8.20;

import "celo-foundry-8/Test.sol";
import "@celo-contracts-8/common/EpochManagerEnabler.sol";
import "@celo-contracts/stability/test/MockSortedOracles.sol";
import "@celo-contracts-8/common/EpochManager.sol";

import { EpochManagerEnablerMock } from "@test-sol/mocks/EpochManagerEnablerMock.sol";

import { CeloUnreleasedTreasure } from "@celo-contracts-8/common/CeloUnreleasedTreasure.sol";
import { ICeloUnreleasedTreasure } from "@celo-contracts/common/interfaces/ICeloUnreleasedTreasure.sol";
import { IAccounts } from "@celo-contracts/common/interfaces/IAccounts.sol";

import { TestConstants } from "@test-sol/constants.sol";
import { Utils08 } from "@test-sol/utils08.sol";

import "@celo-contracts/common/interfaces/IRegistry.sol";

import { EPOCH_SIZEPRE_COMPILE_ADDRESS, EpochSizePrecompile } from "@test-sol/precompiles/EpochSizePrecompile.sol";
import { EpochRewardsMock08 } from "@celo-contracts-8/governance/test/EpochRewardsMock.sol";
import { ValidatorsMock } from "@test-sol/unit/governance/validators/mocks/ValidatorsMock.sol";
import { MockCeloUnreleasedTreasure } from "@celo-contracts-8/common/test/MockCeloUnreleasedTreasure.sol";
import "@celo-contracts-8/common/test/MockCeloToken.sol";

contract EpochManagerEnablerTest is Test, TestConstants, Utils08 {
EpochManager epochManager;
EpochManagerEnablerMock epochManagerEnabler;
MockCeloUnreleasedTreasure celoUnreleasedTreasure;
MockCeloToken08 celoToken;

IRegistry registry;
IAccounts accounts;

address accountsAddress;
address nonOwner;

uint256 epochDuration = DAY;
uint256 numberValidators = 100;

event LastKnownEpochNumberSet(uint256 lastKnownEpochNumber);
event LastKnownFirstBlockOfEpochSet(uint256 lastKnownFirstBlockOfEpoch);
event LastKnownElectedAccountsSet();

function setUp() public virtual {
ph.setEpochSize(17280);
epochManager = new EpochManager(true);
epochManagerEnabler = new EpochManagerEnablerMock();
celoToken = new MockCeloToken08();

celoUnreleasedTreasure = new MockCeloUnreleasedTreasure();

accountsAddress = actor("accountsAddress");

contract EpochManagerEnablerMock is EpochManagerEnabler {
constructor(bool test) public EpochManagerEnabler(test) {}
nonOwner = actor("nonOwner");

function setFirstBlockOfEpoch() external {
return _setFirstBlockOfEpoch();
deployCodeTo("MockRegistry.sol", abi.encode(false), REGISTRY_ADDRESS);
deployCodeTo("Accounts.sol", abi.encode(false), accountsAddress);

registry = IRegistry(REGISTRY_ADDRESS);
accounts = IAccounts(accountsAddress);

registry.setAddressFor(EpochManagerContract, address(epochManager));
registry.setAddressFor(EpochManagerEnablerContract, address(epochManagerEnabler));
registry.setAddressFor(AccountsContract, address(accounts));
registry.setAddressFor(CeloTokenContract, address(celoToken));
registry.setAddressFor(CeloUnreleasedTreasureContract, address(celoUnreleasedTreasure));

celoToken.setTotalSupply(CELO_SUPPLY_CAP);
celoToken.setBalanceOf(address(celoUnreleasedTreasure), L2_INITIAL_STASH_BALANCE);

epochManagerEnabler.initialize(REGISTRY_ADDRESS);
epochManager.initialize(REGISTRY_ADDRESS, epochDuration);

_setupValidators();
travelEpochL1(vm);
travelEpochL1(vm);
}

function _setupValidators() internal {
for (uint256 i = 0; i < numberValidators; i++) {
vm.prank(vm.addr(i + 1));
accounts.createAccount();

epochManagerEnabler.addValidator(vm.addr(i + 1));
}
}
}

contract EpochManagerEnablerTest is Test {
EpochManagerEnablerMock epochManagerEnabler;
uint256 EPOCH_SIZE_NEW = 17280;
contract EpochManagerEnablerTest_initialize is EpochManagerEnablerTest {
function test_initialize() public {
assertEq(address(epochManagerEnabler.registry()), REGISTRY_ADDRESS);
}

function setUp() public virtual {
deployCodeTo("EpochSizePrecompile", EPOCH_SIZEPRE_COMPILE_ADDRESS);
address payable payableAddress = payable(EPOCH_SIZEPRE_COMPILE_ADDRESS);
function test_Reverts_WhenAlreadyInitialized() public virtual {
vm.expectRevert("contract already initialized");
epochManagerEnabler.initialize(REGISTRY_ADDRESS);
}
}

EpochSizePrecompile(payableAddress).setEpochSize(EPOCH_SIZE_NEW);
contract EpochManagerEnablerTest_initEpochManager is EpochManagerEnablerTest {
function test_CanBeCalledByAnyone() public {
travelEpochL1(vm);
travelEpochL1(vm);
soloseng marked this conversation as resolved.
Show resolved Hide resolved
epochManagerEnabler.captureEpochAndValidators();

epochManagerEnabler = new EpochManagerEnablerMock(true);
whenL2(vm);
vm.prank(nonOwner);
epochManagerEnabler.initEpochManager();

assertGt(epochManager.getElected().length, 0);
assertTrue(epochManager.systemAlreadyInitialized());
}

function test_Reverts_ifEpochAndValidatorsAreNotCaptured() public {
whenL2(vm);
vm.expectRevert("lastKnownEpochNumber not set.");

epochManagerEnabler.initEpochManager();
}

function test_Reverts_whenL1() public {
vm.expectRevert("This method is not supported in L1.");

epochManagerEnabler.initEpochManager();
}
}

contract EpochManagerEnablerTest_captureEpochAndValidators is EpochManagerEnablerTest {
function test_Reverts_whenL2() public {
travelEpochL1(vm);
whenL2(vm);
vm.expectRevert("This method is no longer supported in L2.");
epochManagerEnabler.captureEpochAndValidators();
}

function test_shouldSetLastKnownElectedAccounts() public {
travelEpochL1(vm);
epochManagerEnabler.captureEpochAndValidators();

assertEq(epochManagerEnabler.getlastKnownElectedAccounts().length, numberValidators);
}

function test_precompilerWorks() public {
// Make sure epoch size is correct
assertEq(epochManagerEnabler.getEpochSize(), EPOCH_SIZE_NEW);
function test_shouldSetLastKnownEpochNumber() public {
travelEpochL1(vm);
epochManagerEnabler.captureEpochAndValidators();

assertEq(epochManagerEnabler.lastKnownEpochNumber(), 4);
}

function test_shouldSetLastKnownFirstBlockOfEpoch() public {
travelEpochL1(vm);
epochManagerEnabler.captureEpochAndValidators();

assertEq(epochManagerEnabler.lastKnownFirstBlockOfEpoch(), 17280 * 3);
}

function test_Emits_LastKnownEpochNumberSet() public {
vm.expectEmit(true, true, true, true);
emit LastKnownEpochNumberSet(4);

travelEpochL1(vm);
epochManagerEnabler.captureEpochAndValidators();
}

function test_Emits_LastKnownElectedAccountsSet() public {
vm.expectEmit(true, true, true, true);
emit LastKnownElectedAccountsSet();

travelEpochL1(vm);
epochManagerEnabler.captureEpochAndValidators();
}

function test_Emits_LastKnownFirstBlockOfEpochSet() public {
vm.expectEmit(true, true, true, true);
emit LastKnownFirstBlockOfEpochSet(51840);

travelEpochL1(vm);
epochManagerEnabler.captureEpochAndValidators();
}
}

Expand Down
Loading