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

Revert "Feat: split churn limit into exited and appeared" #747

Merged
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
96 changes: 28 additions & 68 deletions contracts/0.8.9/sanity_checks/OracleReportSanityChecker.sol
Original file line number Diff line number Diff line change
Expand Up @@ -37,16 +37,10 @@ interface IWithdrawalQueue {
/// @notice The set of restrictions used in the sanity checks of the oracle report
/// @dev struct is loaded from the storage and stored in memory during the tx running
struct LimitsList {
/// @notice The max possible number of validators that might be reported as `exited`
/// per single day, depends on the Consensus Layer churn limit
/// @notice The max possible number of validators that might appear or exit on the Consensus
/// Layer during one day
/// @dev Must fit into uint16 (<= 65_535)
uint256 exitedValidatorsPerDayLimit;

/// @notice The max possible number of validators that might be reported as `appeared`
/// per single day, limited by the max daily deposits via DepositSecurityModule in practice
/// isn't limited by a consensus layer (because `appeared` includes `pending`, i.e., not `activated` yet)
/// @dev Must fit into uint16 (<= 65_535)
uint256 appearedValidatorsPerDayLimit;
uint256 churnValidatorsPerDayLimit;

/// @notice The max decrease of the total validators' balances on the Consensus Layer since
/// the previous oracle report
Expand Down Expand Up @@ -85,8 +79,7 @@ struct LimitsList {

/// @dev The packed version of the LimitsList struct to be effectively persisted in storage
struct LimitsListPacked {
uint16 exitedValidatorsPerDayLimit;
uint16 appearedValidatorsPerDayLimit;
uint16 churnValidatorsPerDayLimit;
uint16 oneOffCLBalanceDecreaseBPLimit;
uint16 annualBalanceIncreaseBPLimit;
uint16 simulatedShareRateDeviationBPLimit;
Expand All @@ -109,10 +102,8 @@ contract OracleReportSanityChecker is AccessControlEnumerable {
using PositiveTokenRebaseLimiter for TokenRebaseLimiterData;

bytes32 public constant ALL_LIMITS_MANAGER_ROLE = keccak256("ALL_LIMITS_MANAGER_ROLE");
bytes32 public constant EXITED_VALIDATORS_PER_DAY_LIMIT_MANAGER_ROLE =
keccak256("EXITED_VALIDATORS_PER_DAY_LIMIT_MANAGER_ROLE");
bytes32 public constant APPEARED_VALIDATORS_PER_DAY_LIMIT_MANAGER_ROLE =
keccak256("APPEARED_VALIDATORS_PER_DAY_LIMIT_MANAGER_ROLE");
bytes32 public constant CHURN_VALIDATORS_PER_DAY_LIMIT_MANAGER_ROLE =
keccak256("CHURN_VALIDATORS_PER_DAY_LIMIT_MANAGER_ROLE");
bytes32 public constant ONE_OFF_CL_BALANCE_DECREASE_LIMIT_MANAGER_ROLE =
keccak256("ONE_OFF_CL_BALANCE_DECREASE_LIMIT_MANAGER_ROLE");
bytes32 public constant ANNUAL_BALANCE_INCREASE_LIMIT_MANAGER_ROLE =
Expand All @@ -139,8 +130,7 @@ contract OracleReportSanityChecker is AccessControlEnumerable {

struct ManagersRoster {
address[] allLimitsManagers;
address[] exitedValidatorsPerDayLimitManagers;
address[] appearedValidatorsPerDayLimitManagers;
address[] churnValidatorsPerDayLimitManagers;
address[] oneOffCLBalanceDecreaseLimitManagers;
address[] annualBalanceIncreaseLimitManagers;
address[] shareRateDeviationLimitManagers;
Expand Down Expand Up @@ -168,9 +158,7 @@ contract OracleReportSanityChecker is AccessControlEnumerable {

_grantRole(DEFAULT_ADMIN_ROLE, _admin);
_grantRole(ALL_LIMITS_MANAGER_ROLE, _managersRoster.allLimitsManagers);
_grantRole(EXITED_VALIDATORS_PER_DAY_LIMIT_MANAGER_ROLE, _managersRoster.exitedValidatorsPerDayLimitManagers);
_grantRole(APPEARED_VALIDATORS_PER_DAY_LIMIT_MANAGER_ROLE,
_managersRoster.appearedValidatorsPerDayLimitManagers);
_grantRole(CHURN_VALIDATORS_PER_DAY_LIMIT_MANAGER_ROLE, _managersRoster.churnValidatorsPerDayLimitManagers);
_grantRole(ONE_OFF_CL_BALANCE_DECREASE_LIMIT_MANAGER_ROLE,
_managersRoster.oneOffCLBalanceDecreaseLimitManagers);
_grantRole(ANNUAL_BALANCE_INCREASE_LIMIT_MANAGER_ROLE, _managersRoster.annualBalanceIncreaseLimitManagers);
Expand Down Expand Up @@ -228,35 +216,14 @@ contract OracleReportSanityChecker is AccessControlEnumerable {
_updateLimits(_limitsList);
}

/// @notice Sets the new value for the exitedValidatorsPerDayLimit
///
/// NB: AccountingOracle reports validators as exited once they passed the `EXIT_EPOCH` on Consensus Layer
/// therefore, the value should be set in accordance to the consensus layer churn limit
///
/// @param _exitedValidatorsPerDayLimit new exitedValidatorsPerDayLimit value
function setExitedValidatorsPerDayLimit(uint256 _exitedValidatorsPerDayLimit)
/// @notice Sets the new value for the churnValidatorsPerDayLimit
/// @param _churnValidatorsPerDayLimit new churnValidatorsPerDayLimit value
function setChurnValidatorsPerDayLimit(uint256 _churnValidatorsPerDayLimit)
external
onlyRole(EXITED_VALIDATORS_PER_DAY_LIMIT_MANAGER_ROLE)
onlyRole(CHURN_VALIDATORS_PER_DAY_LIMIT_MANAGER_ROLE)
{
LimitsList memory limitsList = _limits.unpack();
limitsList.exitedValidatorsPerDayLimit = _exitedValidatorsPerDayLimit;
_updateLimits(limitsList);
}

/// @notice Sets the new value for the appearedValidatorsPerDayLimit
///
/// NB: AccountingOracle reports validators as appeared once they become `pending`
/// (might be not `activated` yet). Thus, this limit should be high enough because consensus layer
/// has no intrinsic churn limit for the amount of `pending` validators (only for `activated` instead).
/// For Lido it depends on the amount of deposits that can be made via DepositSecurityModule daily.
///
/// @param _appearedValidatorsPerDayLimit new appearedValidatorsPerDayLimit value
function setAppearedValidatorsPerDayLimit(uint256 _appearedValidatorsPerDayLimit)
external
onlyRole(APPEARED_VALIDATORS_PER_DAY_LIMIT_MANAGER_ROLE)
{
LimitsList memory limitsList = _limits.unpack();
limitsList.appearedValidatorsPerDayLimit = _appearedValidatorsPerDayLimit;
limitsList.churnValidatorsPerDayLimit = _churnValidatorsPerDayLimit;
_updateLimits(limitsList);
}

Expand Down Expand Up @@ -459,7 +426,7 @@ contract OracleReportSanityChecker is AccessControlEnumerable {

// 6. Appeared validators increase
if (_postCLValidators > _preCLValidators) {
_checkAppearedValidators(limitsList, (_postCLValidators - _preCLValidators), _timeElapsed);
_checkValidatorsChurnLimit(limitsList, (_postCLValidators - _preCLValidators), _timeElapsed);
}
}

Expand All @@ -481,9 +448,9 @@ contract OracleReportSanityChecker is AccessControlEnumerable {
external
view
{
uint256 exitedValidatorsLimit = _limits.unpack().exitedValidatorsPerDayLimit;
if (_exitedValidatorsCount > exitedValidatorsLimit) {
revert ExitedValidatorsLimitExceeded(exitedValidatorsLimit, _exitedValidatorsCount);
uint256 limit = _limits.unpack().churnValidatorsPerDayLimit;
if (_exitedValidatorsCount > limit) {
revert ExitedValidatorsLimitExceeded(limit, _exitedValidatorsCount);
}
}

Expand Down Expand Up @@ -622,7 +589,7 @@ contract OracleReportSanityChecker is AccessControlEnumerable {
}
}

function _checkAppearedValidators(
function _checkValidatorsChurnLimit(
LimitsList memory _limitsList,
uint256 _appearedValidators,
uint256 _timeElapsed
Expand All @@ -631,9 +598,9 @@ contract OracleReportSanityChecker is AccessControlEnumerable {
_timeElapsed = DEFAULT_TIME_ELAPSED;
}

uint256 appearedLimit = (_limitsList.appearedValidatorsPerDayLimit * _timeElapsed) / SECONDS_PER_DAY;
uint256 churnLimit = (_limitsList.churnValidatorsPerDayLimit * _timeElapsed) / SECONDS_PER_DAY;

if (_appearedValidators > appearedLimit) revert IncorrectAppearedValidators(_appearedValidators);
if (_appearedValidators > churnLimit) revert IncorrectAppearedValidators(_appearedValidators);
}

function _checkLastFinalizableId(
Expand Down Expand Up @@ -708,13 +675,9 @@ contract OracleReportSanityChecker is AccessControlEnumerable {

function _updateLimits(LimitsList memory _newLimitsList) internal {
LimitsList memory _oldLimitsList = _limits.unpack();
if (_oldLimitsList.exitedValidatorsPerDayLimit != _newLimitsList.exitedValidatorsPerDayLimit) {
_checkLimitValue(_newLimitsList.exitedValidatorsPerDayLimit, 0, type(uint16).max);
emit ExitedValidatorsPerDayLimitSet(_newLimitsList.exitedValidatorsPerDayLimit);
}
if (_oldLimitsList.appearedValidatorsPerDayLimit != _newLimitsList.appearedValidatorsPerDayLimit) {
_checkLimitValue(_newLimitsList.appearedValidatorsPerDayLimit, 0, type(uint16).max);
emit AppearedValidatorsPerDayLimitSet(_newLimitsList.appearedValidatorsPerDayLimit);
if (_oldLimitsList.churnValidatorsPerDayLimit != _newLimitsList.churnValidatorsPerDayLimit) {
_checkLimitValue(_newLimitsList.churnValidatorsPerDayLimit, 0, type(uint16).max);
emit ChurnValidatorsPerDayLimitSet(_newLimitsList.churnValidatorsPerDayLimit);
}
if (_oldLimitsList.oneOffCLBalanceDecreaseBPLimit != _newLimitsList.oneOffCLBalanceDecreaseBPLimit) {
_checkLimitValue(_newLimitsList.oneOffCLBalanceDecreaseBPLimit, 0, MAX_BASIS_POINTS);
Expand Down Expand Up @@ -757,8 +720,7 @@ contract OracleReportSanityChecker is AccessControlEnumerable {
}
}

event ExitedValidatorsPerDayLimitSet(uint256 exitedValidatorsPerDayLimit);
event AppearedValidatorsPerDayLimitSet(uint256 appearedValidatorsPerDayLimit);
event ChurnValidatorsPerDayLimitSet(uint256 churnValidatorsPerDayLimit);
event OneOffCLBalanceDecreaseBPLimitSet(uint256 oneOffCLBalanceDecreaseBPLimit);
event AnnualBalanceIncreaseBPLimitSet(uint256 annualBalanceIncreaseBPLimit);
event SimulatedShareRateDeviationBPLimitSet(uint256 simulatedShareRateDeviationBPLimit);
Expand All @@ -774,9 +736,9 @@ contract OracleReportSanityChecker is AccessControlEnumerable {
error IncorrectSharesRequestedToBurn(uint256 actualSharesToBurn);
error IncorrectCLBalanceDecrease(uint256 oneOffCLBalanceDecreaseBP);
error IncorrectCLBalanceIncrease(uint256 annualBalanceDiff);
error IncorrectAppearedValidators(uint256 appearedValidatorsLimit);
error IncorrectAppearedValidators(uint256 churnLimit);
error IncorrectNumberOfExitRequestsPerReport(uint256 maxRequestsCount);
error IncorrectExitedValidators(uint256 exitedValudatorsLimit);
error IncorrectExitedValidators(uint256 churnLimit);
error IncorrectRequestFinalization(uint256 requestCreationBlock);
error ActualShareRateIsZero();
error IncorrectSimulatedShareRate(uint256 simulatedShareRate, uint256 actualShareRate);
Expand All @@ -788,8 +750,7 @@ contract OracleReportSanityChecker is AccessControlEnumerable {

library LimitsListPacker {
function pack(LimitsList memory _limitsList) internal pure returns (LimitsListPacked memory res) {
res.exitedValidatorsPerDayLimit = SafeCast.toUint16(_limitsList.exitedValidatorsPerDayLimit);
res.appearedValidatorsPerDayLimit = SafeCast.toUint16(_limitsList.appearedValidatorsPerDayLimit);
res.churnValidatorsPerDayLimit = SafeCast.toUint16(_limitsList.churnValidatorsPerDayLimit);
res.oneOffCLBalanceDecreaseBPLimit = _toBasisPoints(_limitsList.oneOffCLBalanceDecreaseBPLimit);
res.annualBalanceIncreaseBPLimit = _toBasisPoints(_limitsList.annualBalanceIncreaseBPLimit);
res.simulatedShareRateDeviationBPLimit = _toBasisPoints(_limitsList.simulatedShareRateDeviationBPLimit);
Expand All @@ -808,8 +769,7 @@ library LimitsListPacker {

library LimitsListUnpacker {
function unpack(LimitsListPacked memory _limitsList) internal pure returns (LimitsList memory res) {
res.exitedValidatorsPerDayLimit = _limitsList.exitedValidatorsPerDayLimit;
res.appearedValidatorsPerDayLimit = _limitsList.appearedValidatorsPerDayLimit;
res.churnValidatorsPerDayLimit = _limitsList.churnValidatorsPerDayLimit;
res.oneOffCLBalanceDecreaseBPLimit = _limitsList.oneOffCLBalanceDecreaseBPLimit;
res.annualBalanceIncreaseBPLimit = _limitsList.annualBalanceIncreaseBPLimit;
res.simulatedShareRateDeviationBPLimit = _limitsList.simulatedShareRateDeviationBPLimit;
Expand Down
Loading