Skip to content

Commit

Permalink
Add average uptime for validators
Browse files Browse the repository at this point in the history
  • Loading branch information
Bernhard Scholz committed Oct 29, 2024
1 parent 1d315ce commit 8ad885c
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 0 deletions.
13 changes: 13 additions & 0 deletions contracts/sfc/ConstantsManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ contract ConstantsManager is Ownable {
uint256 public targetGasPowerPerSecond;
uint256 public gasPriceBalancingCounterweight;

// number of epochs for counting the average uptime of validators
int32 public numEpochsAliveThreshold;

/**
* @dev Given value is too small
*/
Expand Down Expand Up @@ -186,4 +189,14 @@ contract ConstantsManager is Ownable {
}
gasPriceBalancingCounterweight = v;
}

function updateNumEpochsAliveThreshold(int32 v) external virtual onlyOwner {
if (v < 10) {
revert ValueTooSmall();
}
if (v > 87600) {
revert ValueTooLarge();
}
numEpochsAliveThreshold = v;
}
}
42 changes: 42 additions & 0 deletions contracts/sfc/SFC.sol
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,47 @@ contract SFC is SFCBase, Version {
minGasPrice = newMinGasPrice;
}

function _sealEpochAverageUptime(
uint256 epochDuration,
EpochSnapshot storage snapshot,
EpochSnapshot storage prevSnapshot,
uint256[] memory validatorIDs,
uint256[] memory uptimes
) internal {
for (uint256 i = 0; i < validatorIDs.length; i++) {
uint256 validatorID = validatorIDs[i];
uint256 normalisedUptime = uptimes[i] * (1 << 30)/ epochDuration;
if (normalisedUptime < 0) {
normalisedUptime = 0;
} else if (normalisedUptime > 1 << 30) {
normalisedUptime = 1 << 30;
}
// Assumes that if in the previous snapshot the validator
// does not exist, the map returns zero.
int32 n = prevSnapshot.numEpochsAlive[validatorID];
int64 tmp;
if (n > 0) {
tmp = int64(n-1) * int64(snapshot.averageUptime[validatorID]) + int64(uint64(normalisedUptime));
if (n > 1) {
tmp += (int64(n) * int64(prevSnapshot.averageUptimeError[validatorID])) / int64(n-1);
}
snapshot.averageUptimeError[validatorID] = int32(tmp % int64(n));
tmp /= int64(n);
} else {
tmp = int64(uint64(normalisedUptime));
}
if (tmp < 0) {
tmp = 0;
} else if (tmp > 1 << 30){
tmp = 1 << 30;
}
snapshot.averageUptime[validatorID] = int32(tmp);
if (n < c.numEpochsAliveThreshold()) {
snapshot.numEpochsAlive[validatorID] = n + 1;
}
}
}

function sealEpoch(
uint256[] calldata offlineTime,
uint256[] calldata offlineBlocks,
Expand All @@ -387,6 +428,7 @@ contract SFC is SFCBase, Version {
}
_sealEpochRewards(epochDuration, snapshot, prevSnapshot, validatorIDs, uptimes, originatedTxsFee);
_sealEpochMinGasPrice(epochDuration, epochGas);
_sealEpochAverageUptime(epochDuration, snapshot, prevSnapshot, validatorIDs, uptimes);
}

currentSealedEpoch = currentEpoch();
Expand Down
6 changes: 6 additions & 0 deletions contracts/sfc/SFCState.sol
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,12 @@ contract SFCState is Initializable, Ownable {
mapping(uint256 => uint256) accumulatedRewardPerToken;
// validator ID => accumulated online time
mapping(uint256 => uint256) accumulatedUptime;
// validator ID => average uptime as a percentage
mapping(uint256 => int32) averageUptime;
// validator ID => error term of average uptime
mapping(uint256 => int32) averageUptimeError;
// validator ID => number of epochs alive for average uptime calculation
mapping(uint256 => int32) numEpochsAlive;
// validator ID => gas fees from txs originated by the validator
mapping(uint256 => uint256) accumulatedOriginatedTxsFee;
mapping(uint256 => uint256) offlineTime;
Expand Down

0 comments on commit 8ad885c

Please sign in to comment.