Skip to content

Commit

Permalink
Make epoch period flexible (#118)
Browse files Browse the repository at this point in the history
* epoch period flexible

* test for epoch period flex

* add simulation test for flex period

* fix epoch period for prior blocks
  • Loading branch information
ChainDev931105 authored Jun 12, 2024
1 parent dfaf775 commit 81b7159
Show file tree
Hide file tree
Showing 8 changed files with 270 additions and 407 deletions.
5 changes: 0 additions & 5 deletions contracts/interfaces/ILagrangeCommittee.sol
Original file line number Diff line number Diff line change
Expand Up @@ -117,11 +117,6 @@ interface ILagrangeCommittee {
// Fired on successful rotation of committee
event UpdateCommittee(uint256 indexed chainID, uint256 indexed epochNumber, bytes32 current);

// Event fired on updating epoch period
event EpochPeriodUpdated(
uint32 indexed chainID, uint32 indexed epochPeriodIndex, uint256 flagBlock, uint256 flagEpoch, uint256 duration
);

// Event fired on updating sign address
event SignAddressUpdated(address indexed operator, address indexed signAddress);
}
132 changes: 50 additions & 82 deletions contracts/protocol/LagrangeCommittee.sol
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,6 @@ contract LagrangeCommittee is Initializable, OwnableUpgradeable, ILagrangeCommit
// ChainID => Committee
mapping(uint32 => CommitteeDef) public committeeParams;

// committees is also used for external storage for epoch period modification
// committees[chainID][uint256.max].leafCount = current index of epoch period
// committees[chainID][uint256.max - 1] : 1-index
// updatedBlock: (flagBlock << 112) | flagEpoch
// leafCount: epochPeriod
// committees[chainID][uint256.max - 2] : 2-index
// committees[chainID][uint256.max - 3] : 3-index
// ... ... ...
// ChainID => Epoch => CommitteeData
mapping(uint32 => mapping(uint256 => CommitteeData)) public committees;

Expand Down Expand Up @@ -67,16 +59,6 @@ contract LagrangeCommittee is Initializable, OwnableUpgradeable, ILagrangeCommit
_transferOwnership(initialOwner);
}

// Initializes epoch period
// @dev This function can be called for the chainID registered in the previous version
function setFirstEpochPeriod(uint32 chainID) public onlyOwner {
uint32 _count = getEpochPeriodCount(chainID);
if (_count != 0) return; // already initialized
CommitteeDef memory _committeeParam = committeeParams[chainID];

_writeEpochPeriod(chainID, _committeeParam.startBlock, 0, _committeeParam.duration);
}

// Adds a new operator to the committee
function addOperator(address operator, address signAddress, uint256[2][] calldata blsPubKeys)
external
Expand Down Expand Up @@ -366,7 +348,7 @@ contract LagrangeCommittee is Initializable, OwnableUpgradeable, ILagrangeCommit

epochNumber = _getEpochNumber(chainID, blockNumber);
// All the prior blocks belong to epoch 1
if (epochNumber == 0) epochNumber = 1;
if (epochNumber == 0 && blockNumber >= committeeParams[chainID].genesisBlock) epochNumber = 1;
}

// Get the operator's voting power for the given chainID
Expand Down Expand Up @@ -424,8 +406,6 @@ contract LagrangeCommittee is Initializable, OwnableUpgradeable, ILagrangeCommit

chainIDs.push(_chainID);

setFirstEpochPeriod(_chainID);

emit InitCommittee(_chainID, _quorumNumber, _genesisBlock, _duration, _freezeDuration, _minWeight, _maxWeight);
}

Expand All @@ -441,12 +421,6 @@ contract LagrangeCommittee is Initializable, OwnableUpgradeable, ILagrangeCommit
uint96 _minWeight,
uint96 _maxWeight
) internal {
if (committeeParams[_chainID].duration != _duration) {
uint256 _flagEpoch = _getEpochNumber(_chainID, block.number - 1) + 1;
(,, uint256 _endBlockPrv) = getEpochInterval(_chainID, _flagEpoch - 1);
_writeEpochPeriod(_chainID, _endBlockPrv, _flagEpoch, _duration);
}

committeeParams[_chainID] = CommitteeDef(
_startBlock, _l1Bias, _genesisBlock, _duration, _freezeDuration, _quorumNumber, _minWeight, _maxWeight
);
Expand All @@ -456,74 +430,68 @@ contract LagrangeCommittee is Initializable, OwnableUpgradeable, ILagrangeCommit
);
}

// ----------------- Functions for Epoch Number ----------------- //
function getEpochPeriodCount(uint32 chainID) public view returns (uint32) {
return committees[chainID][type(uint256).max].leafCount;
}

function getEpochPeriodByIndex(uint32 chainID, uint32 index)
public
view
returns (uint256 flagBlock, uint256 flagEpoch, uint256 duration)
{
CommitteeData memory _epochPeriodContext = committees[chainID][type(uint256).max - index];
return (
_epochPeriodContext.updatedBlock >> 112,
(_epochPeriodContext.updatedBlock << 112) >> 112,
_epochPeriodContext.leafCount
);
}

function getEpochInterval(uint32 _chainID, uint256 _epochNumber)
// Get epoch interval for a given chain
function getEpochInterval(uint32 chainID, uint256 epochNumber)
public
view
returns (uint256 _startBlock, uint256 _freezeBlock, uint256 _endBlock)
returns (uint256 startBlock, uint256 freezeBlock, uint256 endBlock)
{
// epoch period would be updated rarely
uint32 _index = getEpochPeriodCount(_chainID);
while (_index > 0) {
(uint256 _flagBlock, uint256 _flagEpoch, uint256 _duration) = getEpochPeriodByIndex(_chainID, _index);
if (_epochNumber >= _flagEpoch) {
_startBlock = (_epochNumber - _flagEpoch) * _duration + _flagBlock;
_endBlock = _startBlock + _duration;
_freezeBlock = _endBlock - committeeParams[_chainID].freezeDuration;
break;
}
unchecked {
_index--;
}
CommitteeDef memory committeeParam = committeeParams[chainID];
uint256 _lastEpoch = updatedEpoch[chainID];

if (epochNumber == 0) {
startBlock = committeeParam.startBlock;
endBlock = _lastEpoch == 0
? committeeParam.startBlock + committeeParam.duration
: committees[chainID][1].updatedBlock;
freezeBlock = endBlock - committeeParam.freezeDuration;
return (startBlock, freezeBlock, endBlock);
}
}

function _writeEpochPeriod(uint32 _chainID, uint256 _flagBlock, uint256 _flagEpoch, uint256 _duration) internal {
uint32 _index = committees[_chainID][type(uint256).max].leafCount + 1;
committees[_chainID][type(uint256).max - _index] = CommitteeData(
0,
(uint224(SafeCast.toUint112(_flagBlock)) << 112) + uint224(SafeCast.toUint112(_flagEpoch)),
SafeCast.toUint32(_duration)
);
committees[_chainID][type(uint256).max].leafCount = _index;
emit EpochPeriodUpdated(_chainID, _index, _flagBlock, _flagEpoch, _duration);
if (epochNumber <= _lastEpoch) {
startBlock = committees[chainID][epochNumber].updatedBlock;
endBlock = _lastEpoch == epochNumber
? startBlock + committeeParam.duration
: committees[chainID][epochNumber + 1].updatedBlock;
freezeBlock = endBlock - committeeParam.freezeDuration;
} else {
uint256 _lastEpochBlock =
_lastEpoch > 0 ? committees[chainID][_lastEpoch].updatedBlock : committeeParam.startBlock;
startBlock = _lastEpochBlock + (epochNumber - _lastEpoch) * committeeParam.duration;
endBlock = startBlock + committeeParam.duration;
freezeBlock = endBlock - committeeParam.freezeDuration;
}
}

function _getEpochNumber(uint32 _chainID, uint256 _blockNumber) internal view returns (uint256 _epochNumber) {
if (_blockNumber < committeeParams[_chainID].genesisBlock) {
CommitteeDef memory committeeParam = committeeParams[_chainID];
if (_blockNumber < committeeParam.startBlock) {
return 0;
}
// epoch period would be updated rarely
uint32 _index = getEpochPeriodCount(_chainID);
while (_index > 0) {
(uint256 _flagBlock, uint256 _flagEpoch, uint256 _duration) = getEpochPeriodByIndex(_chainID, _index);
if (_blockNumber >= _flagBlock) {
_epochNumber = _flagEpoch + (_blockNumber - _flagBlock) / _duration;
break;
}
unchecked {
_index--;

uint256 _lastEpoch = updatedEpoch[_chainID];
uint256 _lastEpochBlock =
_lastEpoch > 0 ? committees[_chainID][_lastEpoch].updatedBlock : committeeParam.startBlock;

if (_blockNumber >= _lastEpochBlock) {
_epochNumber = _lastEpoch + (_blockNumber - _lastEpochBlock) / committeeParam.duration;
} else if (_lastEpoch == 0) {
return 0;
} else {
// binary search
uint256 _low = 0;
uint256 _high = _lastEpoch;
while (_low < _high - 1) {
uint256 _mid = (_low + _high + 1) >> 1;
if (_blockNumber < committees[_chainID][_mid].updatedBlock) {
_high = _mid;
} else {
_low = _mid + 1;
}
}
_epochNumber = _high - 1;
}
}
// ------------------------------------------------------------- //

function _registerOperator(address _operator, address _signAddress, uint256[2][] memory _blsPubKeys) internal {
delete operatorsStatus[_operator];
Expand Down
30 changes: 0 additions & 30 deletions script/update/Redeploy_For_UpdateEpoch.s.sol

This file was deleted.

Loading

0 comments on commit 81b7159

Please sign in to comment.