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

Get epoch info of specified epoch #11231

Merged
merged 5 commits into from
Oct 7, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
32 changes: 25 additions & 7 deletions packages/protocol/contracts-0.8/common/EpochManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,14 @@ contract EpochManager is
uint256 public epochDuration;

uint256 public firstKnownEpoch;
uint256 private currentEpochNumber;
uint256 internal currentEpochNumber;
address public oracleAddress;
address[] public elected;

mapping(address => ProcessedGroup) public processedGroups;

EpochProcessState public epochProcessing;
mapping(uint256 => Epoch) private epochs;
mapping(uint256 => Epoch) internal epochs;
mapping(address => uint256) public validatorPendingPayments;

/**
Expand Down Expand Up @@ -215,7 +215,7 @@ contract EpochManager is
address[] calldata groups,
address[] calldata lessers,
address[] calldata greaters
) external nonReentrant {
) external virtual nonReentrant {
require(isOnEpochProcess(), "Epoch process is not started");
// finalize epoch
// last block should be the block before and timestamp from previous block
Expand Down Expand Up @@ -327,16 +327,19 @@ contract EpochManager is
}

/**
* @return The current epoch info.
* @notice Returns the info of the current epoch.
* @return firstEpoch The first block of the epoch.
* @return lastBlock The first block of the epoch.
* @return startTimestamp The starting timestamp of the epoch.
* @return rewardsBlock The reward block of the epoch.
*/
function getCurrentEpoch()
external
view
onlySystemAlreadyInitialized
returns (uint256, uint256, uint256, uint256)
{
Epoch storage _epoch = epochs[currentEpochNumber];
return (_epoch.firstBlock, _epoch.lastBlock, _epoch.startTimestamp, _epoch.rewardsBlock);
return getEpochByNumber(currentEpochNumber);
}

/**
Expand Down Expand Up @@ -374,7 +377,7 @@ contract EpochManager is
}

/**
* @return The list of elected validators.
* @return The list of currently elected validators.
*/
function getElected() external view returns (address[] memory) {
return elected;
Expand Down Expand Up @@ -457,6 +460,21 @@ contract EpochManager is
return initialized && isSystemInitialized;
}

/**
* @notice Returns the epoch info of a specified epoch.
* @param epochNumber Epoch number where epoch info is retreived.
* @return firstEpoch The first block of the epoch.
* @return lastBlock The first block of the epoch.
* @return startTimestamp The starting timestamp of the epoch.
* @return rewardsBlock The reward block of the epoch.
*/
function getEpochByNumber(
uint256 epochNumber
) public view onlySystemAlreadyInitialized returns (uint256, uint256, uint256, uint256) {
Epoch storage _epoch = epochs[epochNumber];
return (_epoch.firstBlock, _epoch.lastBlock, _epoch.startTimestamp, _epoch.rewardsBlock);
}

/**
* @notice Allocates rewards to elected validator accounts.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,22 @@ contract EpochManager_WithMocks is EpochManager(true) {
function _setPaymentAllocation(address validator, uint256 amount) external {
validatorPendingPayments[validator] = amount;
}

// mocks finishNextEpochProcess to increment the epoch number.
function finishNextEpochProcess(
address[] calldata groups,
address[] calldata lessers,
address[] calldata greaters
) external override nonReentrant {
require(isOnEpochProcess(), "Epoch process is not started");

epochs[currentEpochNumber].lastBlock = block.number - 1;

currentEpochNumber++;
epochs[currentEpochNumber].firstBlock = block.number;
epochs[currentEpochNumber].startTimestamp = block.timestamp;

EpochProcessState storage _epochProcessing = epochProcessing;
_epochProcessing.status = EpochProcessStatus.NotStarted;
}
}
1 change: 1 addition & 0 deletions packages/protocol/test-sol/constants.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ contract TestConstants {
uint256 public constant MONTH = 30 * DAY;
uint256 constant WEEK = 7 * DAY;
uint256 public constant YEAR = 365 * DAY;
uint256 public constant L2_BLOCK_IN_EPOCH = 43200;

// Contract names
string constant ElectionContract = "Election";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ contract EpochManagerIntegrationTest is IntegrationTest, MigrationsConstants {
function test_SetsCurrentRewardBlock() public {
_MockL2Migration(validatorsList);

blockTravel(vm, 43200);
blockTravel(vm, L2_BLOCK_IN_EPOCH);
timeTravel(vm, DAY);

epochManager.startNextEpochProcess();
Expand Down
93 changes: 91 additions & 2 deletions packages/protocol/test-sol/unit/common/EpochManager.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,7 @@ contract EpochManagerTest is Test, TestConstants, Utils08 {
vm.prank(epochManagerEnabler);
epochManager.initializeSystem(firstEpochNumber, firstEpochBlock, firstElected);

blockTravel(vm, 43200);
timeTravel(vm, DAY);
travelEpochL2(vm);
}
}

Expand Down Expand Up @@ -469,3 +468,93 @@ contract EpochManagerTest_sendValidatorPayment is EpochManagerTest {
assertEq(epochManagerBalanceAfter, epochManagerBalanceBefore - paymentAmount);
}
}

contract EpochManagerTest_getEpochByNumber is EpochManagerTest {
function _travelAndProcess_N_L2Epoch(uint256 n) public {
for (uint256 i = 0; i < n; i++) {
travelEpochL2(vm);
epochManager.startNextEpochProcess();

address[] memory groups = new address[](0);
address[] memory lessers = new address[](0);
address[] memory greaters = new address[](0);
epochManager.finishNextEpochProcess(groups, lessers, greaters);
}
}

function test_shouldReturnTheEpochInfoOfSpecifiedEpoch() public {
uint256 numberOfEpochsToTravel = 9;

initializeEpochManagerSystem();
uint256 _startingEpochNumber = epochManager.getCurrentEpochNumber();

(
uint256 startingEpochFirstBlock,
uint256 startingEpochLastBlock,
uint256 startingEpochStartTimestamp,
uint256 startingEpochRewardBlock
) = epochManager.getCurrentEpoch();

_travelAndProcess_N_L2Epoch(numberOfEpochsToTravel);

(
uint256 _firstBlock,
uint256 _lastBlock,
uint256 _startTimestamp,
uint256 _rewardBlock
) = epochManager.getEpochByNumber(_startingEpochNumber + numberOfEpochsToTravel);

assertEq(
startingEpochFirstBlock + (L2_BLOCK_IN_EPOCH * (numberOfEpochsToTravel + 1)) + 1,
_firstBlock
);
assertEq(_lastBlock, 0);
assertEq(startingEpochStartTimestamp + (DAY * (numberOfEpochsToTravel + 1)), _startTimestamp);
assertEq(_rewardBlock, 0);
}

function test_ReturnsHistoricalEpochInfoAfter_N_Epochs() public {
initializeEpochManagerSystem();
uint256 _startingEpochNumber = epochManager.getCurrentEpochNumber();
uint256 numberOfEpochsToTravel = 7;
(
uint256 _startingEpochFirstBlock,
uint256 _startingLastBlock,
uint256 _startingStartTimestamp,
uint256 _startingRewardBlock
) = epochManager.getCurrentEpoch();

_travelAndProcess_N_L2Epoch(numberOfEpochsToTravel);

(
uint256 _initialFirstBlock,
uint256 _initialLastBlock,
uint256 _initialStartTimestamp,
uint256 _initialRewardBlock
) = epochManager.getEpochByNumber(_startingEpochNumber);

assertEq(_initialFirstBlock, _startingEpochFirstBlock);
assertEq(_initialLastBlock, _startingLastBlock + (L2_BLOCK_IN_EPOCH * 2) + firstEpochBlock);
assertEq(_initialStartTimestamp, _startingStartTimestamp);
assertEq(
_initialRewardBlock,
_startingRewardBlock + (L2_BLOCK_IN_EPOCH * 2) + firstEpochBlock + 1
);
}

function test_ReturnsZeroForFutureEpochs() public {
initializeEpochManagerSystem();

(
uint256 _firstBlock,
uint256 _lastBlock,
uint256 _startTimestamp,
uint256 _rewardBlock
) = epochManager.getEpochByNumber(500);

assertEq(_firstBlock, 0);
assertEq(_lastBlock, 0);
assertEq(_startTimestamp, 0);
assertEq(_rewardBlock, 0);
}
}
17 changes: 13 additions & 4 deletions packages/protocol/test-sol/utils08.sol
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
pragma solidity >=0.5.13 <0.9.0;

import "celo-foundry-8/Test.sol";
import { TestConstants } from "@test-sol/constants.sol";

contract Utils08 {
contract Utils08 is TestConstants {
uint256 public constant secondsInOneBlock = 5;

function timeTravel(Vm vm, uint256 timeDelta) public {
Expand All @@ -20,12 +21,20 @@ contract Utils08 {
timeTravel(vm, timeDelta);
}

// This function can be also found in OpenZeppelin's library, but in a newer version than the one
function compareStrings(string memory a, string memory b) public pure returns (bool) {
return (keccak256(abi.encodePacked((a))) == keccak256(abi.encodePacked((b))));
// XXX: this function only increases the block number and timestamp, but does not actually change epoch.
// XXX: you must start and finish epoch processing to change epochs.
function travelEpochL2(Vm vm) public {
uint256 blocksInEpoch = L2_BLOCK_IN_EPOCH;
blockTravel(vm, blocksInEpoch);
timeTravel(vm, DAY);
}

function whenL2(Vm vm) public {
vm.etch(0x4200000000000000000000000000000000000018, abi.encodePacked(bytes1(0x01)));
}

// This function can be also found in OpenZeppelin's library, but in a newer version than the one
function compareStrings(string memory a, string memory b) public pure returns (bool) {
return (keccak256(abi.encodePacked((a))) == keccak256(abi.encodePacked((b))));
}
}
Loading