diff --git a/contracts/sfc/SFC.sol b/contracts/sfc/SFC.sol index 5a3aa63..0135406 100644 --- a/contracts/sfc/SFC.sol +++ b/contracts/sfc/SFC.sol @@ -138,7 +138,7 @@ contract SFC is SFCBase, Version { bytes memory pubkey = getValidatorPubkey[vid]; if (pubkey.length > 0 && pubkeyHashToValidatorID[keccak256(pubkey)] != vid) { if (pubkeyHashToValidatorID[keccak256(pubkey)] != 0) { - revert PubkeyExists(); + revert PubkeyUsedByOtherValidator(); } pubkeyHashToValidatorID[keccak256(pubkey)] = vid; } @@ -154,13 +154,13 @@ contract SFC is SFCBase, Version { revert ValidatorNotExists(); } if (keccak256(pubkey) == keccak256(getValidatorPubkey[validatorID])) { - revert SamePubkey(); + revert PubkeyNotChanged(); } if (pubkeyHashToValidatorID[keccak256(pubkey)] != 0) { - revert PubkeyExists(); + revert PubkeyUsedByOtherValidator(); } if (validatorPubkeyChanges[validatorID] != 0) { - revert PubkeyAllowedOnlyOnce(); + revert TooManyPubkeyUpdates(); } validatorPubkeyChanges[validatorID]++; @@ -187,7 +187,7 @@ contract SFC is SFCBase, Version { revert NotAuthorized(); } if (getRedirection[from] == to) { - revert RequestedCompleted(); + revert AlreadyRedirected(); } if (from == to) { revert SameAddress(); @@ -331,8 +331,6 @@ contract SFC is SFCBase, Version { } snapshot.epochFee = ctx.epochFee; - snapshot.totalBaseRewardWeight = ctx.totalBaseRewardWeight; - snapshot.totalTxRewardWeight = ctx.totalTxRewardWeight; if (totalSupply > snapshot.epochFee) { totalSupply -= snapshot.epochFee; } else { diff --git a/contracts/sfc/SFCBase.sol b/contracts/sfc/SFCBase.sol index 164404f..75016da 100644 --- a/contracts/sfc/SFCBase.sol +++ b/contracts/sfc/SFCBase.sol @@ -24,13 +24,14 @@ contract SFCBase is SFCState { error ZeroRewards(); // pubkeys - error PubkeyExists(); + error PubkeyUsedByOtherValidator(); error MalformedPubkey(); - error SamePubkey(); + error PubkeyNotChanged(); error EmptyPubkey(); - error PubkeyAllowedOnlyOnce(); + error TooManyPubkeyUpdates(); // redirections + error AlreadyRedirected(); error SameRedirectionAuthorizer(); error Redirected(); @@ -42,7 +43,6 @@ contract SFCBase is SFCState { error WrongValidatorStatus(); // requests - error RequestedCompleted(); error RequestExists(); error RequestNotExists(); diff --git a/contracts/sfc/SFCLib.sol b/contracts/sfc/SFCLib.sol index 47e1f36..33f660c 100644 --- a/contracts/sfc/SFCLib.sol +++ b/contracts/sfc/SFCLib.sol @@ -103,7 +103,7 @@ contract SFCLib is SFCBase { revert EmptyPubkey(); } if (pubkeyHashToValidatorID[keccak256(pubkey)] != 0) { - revert PubkeyExists(); + revert PubkeyUsedByOtherValidator(); } _createValidator(msg.sender, pubkey); _delegate(msg.sender, lastValidatorID, msg.value); @@ -316,7 +316,6 @@ contract SFCLib is SFCBase { uint256 penalty = getSlashingPenalty(amount, isCheater, slashingRefundRatio[toValidatorID]); delete getWithdrawalRequest[delegator][toValidatorID][wrID]; - totalSlashedStake += penalty; if (amount <= penalty) { revert StakeIsFullySlashed(); } diff --git a/contracts/sfc/SFCState.sol b/contracts/sfc/SFCState.sol index e19fadd..68906db 100644 --- a/contracts/sfc/SFCState.sol +++ b/contracts/sfc/SFCState.sol @@ -14,10 +14,10 @@ contract SFCState is Initializable, Ownable { uint256 status; uint256 deactivatedTime; uint256 deactivatedEpoch; - uint256 receivedStake; + uint256 receivedStake; // from all delegators (weight of the validator) uint256 createdEpoch; uint256 createdTime; - address auth; + address auth; // self-stake delegator } NodeDriverAuth internal node; @@ -28,26 +28,32 @@ contract SFCState is Initializable, Ownable { uint256 unlockedReward; } + // last sealed epoch (currentEpoch - 1) uint256 public currentSealedEpoch; mapping(uint256 => Validator) public getValidator; mapping(address => uint256) public getValidatorID; mapping(uint256 => bytes) public getValidatorPubkey; uint256 public lastValidatorID; + + // total stake of all validators - includes slashed/offline validators uint256 public totalStake; + // total stake of active (OK_STATUS) validators (total weight) uint256 public totalActiveStake; - uint256 public totalSlashedStake; - mapping(address => mapping(uint256 => Rewards)) internal _rewardsStash; // addr, validatorID -> Rewards + // delegator => validator ID => stashed rewards (to be claimed/restaked) + mapping(address => mapping(uint256 => Rewards)) internal _rewardsStash; + // delegator => validator ID => last epoch number for which were rewards stashed mapping(address => mapping(uint256 => uint256)) public stashedRewardsUntilEpoch; struct WithdrawalRequest { - uint256 epoch; - uint256 time; + uint256 epoch; // epoch where undelegated + uint256 time; // when undelegated uint256 amount; } + // delegator => validator ID => withdrawal ID => withdrawal request mapping(address => mapping(uint256 => mapping(uint256 => WithdrawalRequest))) public getWithdrawalRequest; struct LockedDelegation { @@ -57,43 +63,54 @@ contract SFCState is Initializable, Ownable { uint256 duration; } + // delegator => validator ID => current stake (locked+unlocked) mapping(address => mapping(uint256 => uint256)) public getStake; + // delegator => validator ID => locked stake info mapping(address => mapping(uint256 => LockedDelegation)) public getLockupInfo; mapping(address => mapping(uint256 => Rewards)) public getStashedLockupRewards; struct EpochSnapshot { + // validator ID => validator weight in the epoch mapping(uint256 => uint256) receivedStake; + // validator ID => accumulated ( delegatorsReward * 1e18 / receivedStake ) mapping(uint256 => uint256) accumulatedRewardPerToken; + // validator ID => accumulated online time mapping(uint256 => uint256) accumulatedUptime; + // validator ID => gas fees from txs originated by the validator mapping(uint256 => uint256) accumulatedOriginatedTxsFee; mapping(uint256 => uint256) offlineTime; mapping(uint256 => uint256) offlineBlocks; uint256[] validatorIDs; uint256 endTime; uint256 endBlock; - uint256 epochFee; - uint256 totalBaseRewardWeight; - uint256 totalTxRewardWeight; - uint256 baseRewardPerSecond; - uint256 totalStake; - uint256 totalSupply; + uint256 epochFee; // gas fees from txs in the epoch + uint256 baseRewardPerSecond; // the base reward to divide among validators for each second of the epoch + uint256 totalStake; // total weight of all validators + uint256 totalSupply; // total supply of native tokens } + // the total supply of native tokens in the chain uint256 public totalSupply; + // epoch id => epoch snapshot mapping(uint256 => EpochSnapshot) public getEpochSnapshot; - mapping(uint256 => uint256) public slashingRefundRatio; // validator ID -> (slashing refund ratio) + // validator ID -> slashing refund ratio (allows to withdraw slashed stake) + mapping(uint256 => uint256) public slashingRefundRatio; + // the minimal gas price calculated for the current epoch uint256 public minGasPrice; + // the treasure contract (receives unlock penalties and a part of epoch fees) address public treasuryAddress; + // the SFCLib contract address internal libAddress; ConstantsManager internal c; + // the governance contract (to recalculate votes when the stake changes) address public voteBookAddress; struct Penalty { @@ -103,13 +120,18 @@ contract SFCState is Initializable, Ownable { // delegator => validatorID => penalties info mapping(address => mapping(uint256 => Penalty[])) public getStashedPenalties; + // validator ID => amount of pubkey updates mapping(uint256 => uint256) internal validatorPubkeyChanges; + // keccak256(pubkey bytes) => validator ID (prevents using the same key by multiple validators) mapping(bytes32 => uint256) internal pubkeyHashToValidatorID; + // address authorized to initiate redirection address public redirectionAuthorizer; + // delegator => withdrawals receiver mapping(address => address) public getRedirectionRequest; + // delegator => withdrawals receiver mapping(address => address) public getRedirection; } diff --git a/contracts/test/UnitTestSFC.sol b/contracts/test/UnitTestSFC.sol index ef7d24d..db4176d 100644 --- a/contracts/test/UnitTestSFC.sol +++ b/contracts/test/UnitTestSFC.sol @@ -125,8 +125,6 @@ interface SFCUnitTestI { uint256 endTime, uint256 endBlock, uint256 epochFee, - uint256 totalBaseRewardWeight, - uint256 totalTxRewardWeight, uint256 _baseRewardPerSecond, uint256 totalStake, uint256 totalSupply