From d215bbb236560b3f34c445c353b5665b588c1d66 Mon Sep 17 00:00:00 2001 From: JK Date: Thu, 7 Nov 2024 15:41:34 +0100 Subject: [PATCH] Add deactivation procedure for minAverageUptime --- contracts/sfc/ConstantsManager.sol | 12 +++++++----- contracts/sfc/NetworkInitializer.sol | 4 ++-- contracts/sfc/SFC.sol | 21 +++++++++++++++++---- 3 files changed, 26 insertions(+), 11 deletions(-) diff --git a/contracts/sfc/ConstantsManager.sol b/contracts/sfc/ConstantsManager.sol index 0f15c2a..b3fabcd 100644 --- a/contracts/sfc/ConstantsManager.sol +++ b/contracts/sfc/ConstantsManager.sol @@ -29,10 +29,12 @@ contract ConstantsManager is Ownable { uint256 public targetGasPowerPerSecond; uint256 public gasPriceBalancingCounterweight; - // the number of epochs for counting the average uptime of validators - uint32 public averageUptimeEpochsWindow; + // Epoch threshold for stop counting alive epochs (avoid diminishing impact of new uptimes). + // Is also the minimum number of epochs necessary for deactivation of offline validators. + uint32 public averageUptimeEpochsThreshold; - // minimum average uptime + // Minimum average uptime in Q1.30 format; acceptable bounds [0,0.9] + // Zero to disable validators deactivation by this metric. uint32 public minAverageUptime; /** @@ -160,14 +162,14 @@ contract ConstantsManager is Ownable { gasPriceBalancingCounterweight = v; } - function updateAverageUptimeEpochsWindow(uint32 v) external virtual onlyOwner { + function updateAverageUptimeEpochsThreshold(uint32 v) external virtual onlyOwner { if (v < 10) { revert ValueTooSmall(); } if (v > 87600) { revert ValueTooLarge(); } - averageUptimeEpochsWindow = v; + averageUptimeEpochsThreshold = v; } function updateMinAverageUptime(uint32 v) external virtual onlyOwner { diff --git a/contracts/sfc/NetworkInitializer.sol b/contracts/sfc/NetworkInitializer.sol index 92d4f8f..4763239 100644 --- a/contracts/sfc/NetworkInitializer.sol +++ b/contracts/sfc/NetworkInitializer.sol @@ -37,8 +37,8 @@ contract NetworkInitializer { consts.updateOfflinePenaltyThresholdBlocksNum(1000); consts.updateTargetGasPowerPerSecond(2000000); consts.updateGasPriceBalancingCounterweight(3600); - consts.updateAverageUptimeEpochsWindow(20); - consts.updateMinAverageUptime(0); + consts.updateAverageUptimeEpochsThreshold(100); + consts.updateMinAverageUptime(0); // check disabled by default consts.transferOwnership(_owner); ISFC(_sfc).initialize(sealedEpoch, totalSupply, _auth, address(consts), _owner); diff --git a/contracts/sfc/SFC.sol b/contracts/sfc/SFC.sol index 1e29c4c..9069d47 100644 --- a/contracts/sfc/SFC.sol +++ b/contracts/sfc/SFC.sol @@ -17,6 +17,7 @@ contract SFC is Initializable, Ownable, Version { uint256 internal constant OK_STATUS = 0; uint256 internal constant WITHDRAWN_BIT = 1; uint256 internal constant OFFLINE_BIT = 1 << 3; + uint256 internal constant OFFLINE_AVG_BIT = 1 << 4; uint256 internal constant DOUBLESIGN_BIT = 1 << 7; uint256 internal constant CHEATER_MASK = DOUBLESIGN_BIT; @@ -929,16 +930,28 @@ contract SFC is Initializable, Ownable, Version { ) internal { for (uint256 i = 0; i < validatorIDs.length; i++) { uint256 validatorID = validatorIDs[i]; + // compute normalised uptime as a percentage in the Q1.30 fixed-point format uint256 normalisedUptime = (uptimes[i] * (1 << 30)) / epochDuration; if (normalisedUptime > 1 << 30) { normalisedUptime = 1 << 30; } - AverageUptime memory previousAverage = prevSnapshot.averageUptime[validatorID]; - snapshot.averageUptime[validatorID] = _addElementIntoAverageUptime(normalisedUptime, previousAverage); + AverageUptime memory previous = prevSnapshot.averageUptime[validatorID]; + AverageUptime memory current = _addElementIntoAverageUptime(uint32(normalisedUptime), previous); + snapshot.averageUptime[validatorID] = current; + + // remove validator if average uptime drops below min average uptime + // (by setting minAverageUptime to zero, this check is ignored) + if (current.averageUptime < c.minAverageUptime() && current.epochs >= c.averageUptimeEpochsThreshold()) { + _setValidatorDeactivated(validatorID, OFFLINE_AVG_BIT); + _syncValidator(validatorID, false); + } } } - function _addElementIntoAverageUptime(uint32 newValue, AverageUptime memory prev) private returns (AverageUptime memory) { + function _addElementIntoAverageUptime( + uint32 newValue, + AverageUptime memory prev + ) private view returns (AverageUptime memory) { AverageUptime memory cur; if (prev.epochs == 0) { // the only element for the average @@ -963,7 +976,7 @@ contract SFC is Initializable, Ownable, Version { if (cur.averageUptime > 1 << 30) { cur.averageUptime = 1 << 30; } - if (prev.epochs < c.averageUptimeEpochsWindow()) { + if (prev.epochs < c.averageUptimeEpochsThreshold()) { cur.epochs = prev.epochs + 1; } else { cur.epochs = prev.epochs;