Skip to content

Commit

Permalink
Make Epoch manager figure out epoch
Browse files Browse the repository at this point in the history
  • Loading branch information
martinvol committed Sep 19, 2024
1 parent 40f0930 commit 46aa009
Show file tree
Hide file tree
Showing 7 changed files with 145 additions and 91 deletions.
116 changes: 58 additions & 58 deletions packages/protocol/contracts-0.8/common/EpochManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,60 @@ contract EpochManager is
epochProcessing.status = EpochProcessStatus.NotStarted;
}

/**
* @notice Sends the allocated epoch payment to a validator, their group, and
* delegation beneficiary.
* @param validator Account of the validator.
*/
function sendValidatorPayment(address validator) external {
IAccounts accounts = IAccounts(getAccounts());
address signer = accounts.getValidatorSigner(validator);

FixidityLib.Fraction memory totalPayment = FixidityLib.newFixed(
validatorPendingPayments[signer]
);
validatorPendingPayments[signer] = 0;

IValidators validators = getValidators();
address group = validators.getValidatorsGroup(validator);
(, uint256 commissionUnwrapped, , , , , ) = validators.getValidatorGroup(group);

uint256 groupPayment = totalPayment.multiply(FixidityLib.wrap(commissionUnwrapped)).fromFixed();
FixidityLib.Fraction memory remainingPayment = FixidityLib.newFixed(
totalPayment.fromFixed() - groupPayment
);
(address beneficiary, uint256 delegatedFraction) = getAccounts().getPaymentDelegation(
validator
);
uint256 delegatedPayment = remainingPayment
.multiply(FixidityLib.wrap(delegatedFraction))
.fromFixed();
uint256 validatorPayment = remainingPayment.fromFixed() - delegatedPayment;

IStableToken stableToken = IStableToken(getStableToken());

if (validatorPayment > 0) {
require(stableToken.transfer(validator, validatorPayment), "transfer failed to validator");
}

if (groupPayment > 0) {
require(stableToken.transfer(group, groupPayment), "transfer failed to validator group");
}

if (delegatedPayment > 0) {
require(stableToken.transfer(beneficiary, delegatedPayment), "transfer failed to delegatee");
}

emit ValidatorEpochPaymentDistributed(
validator,
validatorPayment,
group,
groupPayment,
beneficiary,
delegatedPayment
);
}

/// returns the current epoch Info
function getCurrentEpoch() external view returns (uint256, uint256, uint256, uint256) {
Epoch storage _epoch = epochs[currentEpochNumber];
Expand Down Expand Up @@ -274,6 +328,10 @@ contract EpochManager is
);
}

function isBlocked() external view returns (bool) {
return isOnEpochProcess();
}

function getElected() external view returns (address[] memory) {
return elected;
}
Expand All @@ -290,10 +348,6 @@ contract EpochManager is
return epochs[epoch].lastBlock;
}

function isBlocked() external view returns (bool) {
return isOnEpochProcess();
}

/**
* @notice Returns the storage, major, minor, and patch version of the contract.
* @return Storage version of the contract.
Expand Down Expand Up @@ -359,58 +413,4 @@ contract EpochManager is
CELOequivalent
);
}

/**
* @notice Sends the allocated epoch payment to a validator, their group, and
* delegation beneficiary.
* @param validator Account of the validator.
*/
function sendValidatorPayment(address validator) external {
IAccounts accounts = IAccounts(getAccounts());
address signer = accounts.getValidatorSigner(validator);

FixidityLib.Fraction memory totalPayment = FixidityLib.newFixed(
validatorPendingPayments[signer]
);
validatorPendingPayments[signer] = 0;

IValidators validators = getValidators();
address group = validators.getValidatorsGroup(validator);
(, uint256 commissionUnwrapped, , , , , ) = validators.getValidatorGroup(group);

uint256 groupPayment = totalPayment.multiply(FixidityLib.wrap(commissionUnwrapped)).fromFixed();
FixidityLib.Fraction memory remainingPayment = FixidityLib.newFixed(
totalPayment.fromFixed() - groupPayment
);
(address beneficiary, uint256 delegatedFraction) = getAccounts().getPaymentDelegation(
validator
);
uint256 delegatedPayment = remainingPayment
.multiply(FixidityLib.wrap(delegatedFraction))
.fromFixed();
uint256 validatorPayment = remainingPayment.fromFixed() - delegatedPayment;

IStableToken stableToken = IStableToken(getStableToken());

if (validatorPayment > 0) {
require(stableToken.transfer(validator, validatorPayment), "transfer failed to validator");
}

if (groupPayment > 0) {
require(stableToken.transfer(group, groupPayment), "transfer failed to validator group");
}

if (delegatedPayment > 0) {
require(stableToken.transfer(beneficiary, delegatedPayment), "transfer failed to delegatee");
}

emit ValidatorEpochPaymentDistributed(
validator,
validatorPayment,
group,
groupPayment,
beneficiary,
delegatedPayment
);
}
}
27 changes: 13 additions & 14 deletions packages/protocol/contracts-0.8/common/EpochManagerEnabler.sol
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ contract EpochManagerEnabler is
uint256 public lastKnownFirstBlockOfEpoch;
address[] public lastKnownElectedAccounts;

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

/**
* @notice Sets initialized == true on implementation contracts
* @param test Set to true to skip implementation initialization
Expand Down Expand Up @@ -55,22 +59,21 @@ contract EpochManagerEnabler is
*/
function captureEpochAndValidators() external onlyL1 {
lastKnownEpochNumber = getEpochNumber();
emit LastKnownEpochNumberSet(lastKnownEpochNumber);

uint256 numberElectedValidators = numberValidatorsInCurrentSet();
lastKnownElectedAccounts = new address[](numberElectedValidators);
lastKnownFirstBlockOfEpoch = _getFirstBlockOfEpoch(lastKnownEpochNumber);
_setFirstBlockOfEpoch();

// TODO add emit
for (uint256 i = 0; i < numberElectedValidators; i++) {
// TODO: document how much gas this takes for 110 signers
address validatorAccountAddress = getAccounts().validatorSignerToAccount(
validatorSignerAddressFromCurrentSet(i)
);
lastKnownElectedAccounts[i] = validatorAccountAddress;
}
}

function getFirstBlockOfEpoch(uint256 currentEpoch) external view returns (uint256) {
return _getFirstBlockOfEpoch(currentEpoch);
emit LastKnownElectedAccountsSet();
}

/**
Expand All @@ -84,14 +87,10 @@ contract EpochManagerEnabler is
return (1, 1, 0, 0);
}

function _getFirstBlockOfEpoch(uint256 currentEpoch) internal view returns (uint256) {
uint256 blockToCheck = block.number - 1;
uint256 blockEpochNumber = getEpochNumberOfBlock(blockToCheck);

while (blockEpochNumber == currentEpoch) {
blockToCheck--;
blockEpochNumber = getEpochNumberOfBlock(blockToCheck);
}
return blockToCheck;
function _setFirstBlockOfEpoch() internal onlyL1 {
uint256 blocksSinceEpochBlock = block.number % getEpochSize();
uint256 epochBlock = block.number - blocksSinceEpochBlock;
lastKnownFirstBlockOfEpoch = epochBlock;
emit LastKnownFirstBlockOfEpochSet(lastKnownFirstBlockOfEpoch);
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity >=0.5.13 <0.9.0;

interface IEpochManagerEnablerInitializer {
function initialize(address registryAddress) external;
}
interface IEpochManagerEnablerInitializer {}
25 changes: 12 additions & 13 deletions packages/protocol/contracts-0.8/common/mocks/MockAccounts.sol
Original file line number Diff line number Diff line change
Expand Up @@ -16,28 +16,27 @@ contract MockAccounts {
mapping(address => PaymentDelegation) delegations;
mapping(address => address) accountToSigner;

function setPaymentDelegationFor(
address validator,
address beneficiary,
uint256 fraction
) public {
delegations[validator] = PaymentDelegation(beneficiary, FixidityLib.wrap(fraction));
function setValidatorSigner(address account, address signer) external {
accountToSigner[account] = signer;
}

function deletePaymentDelegationFor(address validator) public {
delete delegations[validator];
function getValidatorSigner(address account) external returns (address) {
return accountToSigner[account];
}

function getPaymentDelegation(address account) external view returns (address, uint256) {
PaymentDelegation storage delegation = delegations[account];
return (delegation.beneficiary, delegation.fraction.unwrap());
}

function setValidatorSigner(address account, address signer) external {
accountToSigner[account] = signer;
function setPaymentDelegationFor(
address validator,
address beneficiary,
uint256 fraction
) public {
delegations[validator] = PaymentDelegation(beneficiary, FixidityLib.wrap(fraction));
}

function getValidatorSigner(address account) external returns (address) {
return accountToSigner[account];
function deletePaymentDelegationFor(address validator) public {
delete delegations[validator];
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,5 @@ pragma solidity >=0.5.13 <0.9.0;

interface IEpochManagerEnabler {
function initEpochManager() external;
function getEpochNumber() external returns (uint256);
function captureEpochAndValidators() external;
}
10 changes: 8 additions & 2 deletions packages/protocol/test-sol/precompiles/EpochSizePrecompile.sol
Original file line number Diff line number Diff line change
@@ -1,17 +1,23 @@
// TODO move this to test folder
pragma solidity >=0.8.7 <0.8.20;

address constant EPOCH_SIZEPRE_COMPILE_ADDRESS = address(0xff - 7);

contract EpochSizePrecompile {
address constant ADDRESS = address(0xff - 7);
address constant ADDRESS = EPOCH_SIZEPRE_COMPILE_ADDRESS;

uint256 public constant EPOCH_SIZE = 100;
uint256 public EPOCH_SIZE = 100;

receive() external payable {}

fallback(bytes calldata) external payable returns (bytes memory) {
return abi.encodePacked(EPOCH_SIZE);
}

function setEpochSize(uint256 epochSize) public {
EPOCH_SIZE = epochSize;
}

function getAddress() public pure returns (address) {
return ADDRESS;
}
Expand Down
53 changes: 53 additions & 0 deletions packages/protocol/test-sol/unit/common/EpochManagerEnabler.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.8.7 <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/common/interfaces/IRegistry.sol";

import { EPOCH_SIZEPRE_COMPILE_ADDRESS, EpochSizePrecompile } from "@test-sol/precompiles/EpochSizePrecompile.sol";

contract EpochManagerEnablerMock is EpochManagerEnabler {
constructor(bool test) public EpochManagerEnabler(test) {}

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

contract EpochManagerEnablerTest is Test {
EpochManagerEnablerMock epochManagerEnabler;
uint256 EPOCH_SIZE_NEW = 17280;

function setUp() public virtual {
deployCodeTo("EpochSizePrecompile", EPOCH_SIZEPRE_COMPILE_ADDRESS);
address payable payableAddress = payable(EPOCH_SIZEPRE_COMPILE_ADDRESS);

EpochSizePrecompile(payableAddress).setEpochSize(EPOCH_SIZE_NEW);

epochManagerEnabler = new EpochManagerEnablerMock(true);
}

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

contract EpochManagerEnablerTest_getFirstBlockOfEpoch is EpochManagerEnablerTest {
function test_blockIsEpockBlock() public {
vm.roll(27803520);
epochManagerEnabler.setFirstBlockOfEpoch();
assertEq(epochManagerEnabler.lastKnownFirstBlockOfEpoch(), 27803520);
}

function test_blockIsNotEpochBlock() public {
vm.roll(27817229);
epochManagerEnabler.setFirstBlockOfEpoch();
assertEq(epochManagerEnabler.lastKnownFirstBlockOfEpoch(), 27803520);
}
}

0 comments on commit 46aa009

Please sign in to comment.