Skip to content

Commit

Permalink
Add validator status (#5)
Browse files Browse the repository at this point in the history
* Add a test to prove bad behaviour

* Remove only flag

* Use status to track the state of a validator

* fix tests & add more

* add validation on whitelisting

* fix PR requests

* Add custom errors

* Remove duplicated checks in tests

* Generate latest docs

---------

Co-authored-by: Samuil Borisov <[email protected]>
  • Loading branch information
R-Santev and SamBorisov authored Apr 24, 2024
1 parent 56f51e8 commit e5b98fe
Show file tree
Hide file tree
Showing 22 changed files with 242 additions and 151 deletions.
11 changes: 8 additions & 3 deletions contracts/ValidatorSet/IValidatorSet.sol
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,18 @@ struct Epoch {
bytes32 epochRoot;
}

enum ValidatorStatus {
None,
Whitelisted,
Registered,
Banned
}

struct Validator {
uint256[4] blsKey;
uint256 liquidDebt;
uint256 commission;
bool active;
bool whitelisted;
bool registered; // TODO: use a single property for status instead active, whitelisted and registered
ValidatorStatus status;
}

interface IValidatorSet {
Expand Down
2 changes: 1 addition & 1 deletion contracts/ValidatorSet/ValidatorSet.sol
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ contract ValidatorSet is ValidatorSetBase, System, AccessControl, PowerExponent,
stake = totalStake - rewardPool.totalDelegationOf(validatorAddress);
commission = v.commission;
withdrawableRewards = rewardPool.getValidatorReward(validatorAddress);
active = v.active;
active = v.status == ValidatorStatus.Registered;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ import "./IAccessControl.sol";
import "./../../ValidatorSetBase.sol";

abstract contract AccessControl is IAccessControl, Ownable2StepUpgradeable, ValidatorSetBase {
error MustBeWhitelisted();
error PreviouslyWhitelisted();

// TODO: We must be able to enable/disable this feature
function __AccessControl_init(address governance) internal onlyInitializing {
__AccessControl_init_unchained(governance);
Expand Down Expand Up @@ -34,12 +37,14 @@ abstract contract AccessControl is IAccessControl, Ownable2StepUpgradeable, Vali
}

function _addToWhitelist(address account) internal {
validators[account].whitelisted = true;
if (validators[account].status != ValidatorStatus.None) revert PreviouslyWhitelisted();
validators[account].status = ValidatorStatus.Whitelisted;
emit AddedToWhitelist(account);
}

function _removeFromWhitelist(address account) internal {
validators[account].whitelisted = false;
if (validators[account].status != ValidatorStatus.Whitelisted) revert MustBeWhitelisted();
validators[account].status = ValidatorStatus.None;
emit RemovedFromWhitelist(account);
}

Expand Down
2 changes: 1 addition & 1 deletion contracts/ValidatorSet/modules/Delegation/Delegation.sol
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ abstract contract Delegation is
// _______________ Private functions _______________

function _delegate(address validator, address delegator, uint256 amount) private {
if (!validators[validator].active) revert Unauthorized("INVALID_VALIDATOR");
if (validators[validator].status != ValidatorStatus.Registered) revert Unauthorized("INVALID_VALIDATOR");

_mint(validator, amount); // increase validator power
StateSyncer._syncStake(validator, balanceOf(validator));
Expand Down
1 change: 0 additions & 1 deletion contracts/ValidatorSet/modules/Staking/IStaking.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ interface IStaking {
event CommissionUpdated(address indexed validator, uint256 oldCommission, uint256 newCommission);
event Staked(address indexed validator, uint256 amount);
event Unstaked(address indexed validator, uint256 amount);
event ValidatorDeactivated(address indexed validator);

/**
* @notice Sets commission for validator.
Expand Down
19 changes: 4 additions & 15 deletions contracts/ValidatorSet/modules/Staking/Staking.sol
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,9 @@ abstract contract Staking is

// _______________ Modifiers _______________

// Only address that is allowed to be a validator
modifier onlyValidator() {
if (!validators[msg.sender].active) revert Unauthorized("VALIDATOR");
if (validators[msg.sender].status != ValidatorStatus.Registered) revert Unauthorized("VALIDATOR");
_;
}

Expand Down Expand Up @@ -56,10 +57,8 @@ abstract contract Staking is
* @inheritdoc IStaking
*/
function register(uint256[2] calldata signature, uint256[4] calldata pubkey, uint256 commission) external {
if (validators[msg.sender].registered) revert AlreadyRegistered(msg.sender);
if (!validators[msg.sender].whitelisted) revert Unauthorized("WHITELIST");
if (validators[msg.sender].status != ValidatorStatus.Whitelisted) revert Unauthorized("WHITELIST");
_register(msg.sender, signature, pubkey, commission);
_removeFromWhitelist(msg.sender);

emit NewValidator(msg.sender, pubkey);
}
Expand Down Expand Up @@ -104,10 +103,8 @@ abstract contract Staking is
) internal {
_verifyValidatorRegistration(validator, signature, pubkey);
validators[validator].blsKey = pubkey;
validators[validator].active = true;
validators[validator].registered = true;
validators[validator].status = ValidatorStatus.Registered;
_setCommission(validator, commission);

validatorsAddresses.push(validator);
rewardPool.onNewValidator(validator);
}
Expand All @@ -134,18 +131,10 @@ abstract contract Staking is
revert StakeRequirement({src: "unstake", msg: "STAKE_TOO_LOW"});

_burn(msg.sender, amount);
_removeIfValidatorUnstaked(msg.sender, balanceAfterUnstake);

return balanceAfterUnstake;
}

function _removeIfValidatorUnstaked(address validator, uint256 newStake) private {
if (newStake == 0) {
validators[validator].active = false;
emit ValidatorDeactivated(validator);
}
}

function _ensureStakeIsInRange(uint256 amount, uint256 currentBalance) private view {
if (amount + currentBalance < minStake) revert StakeRequirement({src: "stake", msg: "STAKE_TOO_LOW"});
}
Expand Down
1 change: 0 additions & 1 deletion contracts/common/Errors.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,5 @@ error DelegateRequirement(string src, string msg);
error InvalidSignature(address signer);
error ZeroAddress();
error SendFailed();
error AlreadyRegistered(address validator);
error InvalidCommission(uint256 commission);
error InvalidMinStake(uint256 minStake);
2 changes: 1 addition & 1 deletion docs/RewardPool/modules/DelegationRewards.md
Original file line number Diff line number Diff line change
Expand Up @@ -379,7 +379,7 @@ Keeps the delegation pools
function delegationPositions(address, address) external view returns (uint256 duration, uint256 start, uint256 end, uint256 base, uint256 vestBonus, uint256 rsiBonus)
```

The vesting positions for every delegator.
The vesting positions for every delegator



Expand Down
2 changes: 1 addition & 1 deletion docs/RewardPool/modules/StakingRewards.md
Original file line number Diff line number Diff line change
Expand Up @@ -381,7 +381,7 @@ Historical Validator Delegation Pool&#39;s Params per delegator
function delegationPositions(address, address) external view returns (uint256 duration, uint256 start, uint256 end, uint256 base, uint256 vestBonus, uint256 rsiBonus)
```

The vesting positions for every delegator.
The vesting positions for every delegator



Expand Down
4 changes: 2 additions & 2 deletions docs/RewardPool/modules/Vesting.md
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ function beforeTopUpParams(address, address) external view returns (uint256 rewa



*Keep the account parameters before the top-up, so we can separately calculate the rewards made before a top-up is madeThis is because we need to apply the RSI bonus to the rewards made before the top-upand not apply the RSI bonus to the rewards made after the top-up*
*Keep the account parameters before the top-up, so we can separately calculate the rewards made before a top-up is made This is because we need to apply the RSI bonus to the rewards made before the top-up and not apply the RSI bonus to the rewards made after the top-up*

#### Parameters

Expand Down Expand Up @@ -225,7 +225,7 @@ Historical Validator Delegation Pool&#39;s Params per delegator
function delegationPositions(address, address) external view returns (uint256 duration, uint256 start, uint256 end, uint256 base, uint256 vestBonus, uint256 rsiBonus)
```

The vesting positions for every delegator.
The vesting positions for every delegator

*Validator =&gt; Delegator =&gt; VestingPosition*

Expand Down
60 changes: 24 additions & 36 deletions docs/ValidatorSet/ValidatorSet.md
Original file line number Diff line number Diff line change
Expand Up @@ -941,7 +941,7 @@ Additional mapping to store all vesting managers per user address for fast off-c
### validators

```solidity
function validators(address) external view returns (uint256 liquidDebt, uint256 commission, bool active, bool whitelisted, bool registered)
function validators(address) external view returns (uint256 liquidDebt, uint256 commission, enum ValidatorStatus status)
```


Expand All @@ -960,9 +960,7 @@ function validators(address) external view returns (uint256 liquidDebt, uint256
|---|---|---|
| liquidDebt | uint256 | undefined |
| commission | uint256 | undefined |
| active | bool | undefined |
| whitelisted | bool | undefined |
| registered | bool | undefined |
| status | enum ValidatorStatus | undefined |

### validatorsAddresses

Expand Down Expand Up @@ -1345,22 +1343,6 @@ event Unstaked(address indexed validator, uint256 amount)
| validator `indexed` | address | undefined |
| amount | uint256 | undefined |

### ValidatorDeactivated

```solidity
event ValidatorDeactivated(address indexed validator)
```





#### Parameters

| Name | Type | Description |
|---|---|---|
| validator `indexed` | address | undefined |

### WithdrawalFinished

```solidity
Expand Down Expand Up @@ -1400,22 +1382,6 @@ event WithdrawalRegistered(address indexed account, uint256 amount)

## Errors

### AlreadyRegistered

```solidity
error AlreadyRegistered(address validator)
```





#### Parameters

| Name | Type | Description |
|---|---|---|
| validator | address | undefined |

### DelegateRequirement

```solidity
Expand Down Expand Up @@ -1481,6 +1447,17 @@ error InvalidSignature(address signer)
|---|---|---|
| signer | address | undefined |

### MustBeWhitelisted

```solidity
error MustBeWhitelisted()
```






### NotVestingManager

```solidity
Expand All @@ -1492,6 +1469,17 @@ error NotVestingManager()



### PreviouslyWhitelisted

```solidity
error PreviouslyWhitelisted()
```






### StakeRequirement

```solidity
Expand Down
6 changes: 2 additions & 4 deletions docs/ValidatorSet/ValidatorSetBase.md
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ Returns the total supply
### validators

```solidity
function validators(address) external view returns (uint256 liquidDebt, uint256 commission, bool active, bool whitelisted, bool registered)
function validators(address) external view returns (uint256 liquidDebt, uint256 commission, enum ValidatorStatus status)
```


Expand All @@ -227,9 +227,7 @@ function validators(address) external view returns (uint256 liquidDebt, uint256
|---|---|---|
| liquidDebt | uint256 | undefined |
| commission | uint256 | undefined |
| active | bool | undefined |
| whitelisted | bool | undefined |
| registered | bool | undefined |
| status | enum ValidatorStatus | undefined |

### validatorsAddresses

Expand Down
31 changes: 27 additions & 4 deletions docs/ValidatorSet/modules/AccessControl/AccessControl.md
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,7 @@ function transferOwnership(address newOwner) external nonpayable
### validators

```solidity
function validators(address) external view returns (uint256 liquidDebt, uint256 commission, bool active, bool whitelisted, bool registered)
function validators(address) external view returns (uint256 liquidDebt, uint256 commission, enum ValidatorStatus status)
```


Expand All @@ -331,9 +331,7 @@ function validators(address) external view returns (uint256 liquidDebt, uint256
|---|---|---|
| liquidDebt | uint256 | undefined |
| commission | uint256 | undefined |
| active | bool | undefined |
| whitelisted | bool | undefined |
| registered | bool | undefined |
| status | enum ValidatorStatus | undefined |

### validatorsAddresses

Expand Down Expand Up @@ -464,3 +462,28 @@ event RemovedFromWhitelist(address indexed validator)



## Errors

### MustBeWhitelisted

```solidity
error MustBeWhitelisted()
```






### PreviouslyWhitelisted

```solidity
error PreviouslyWhitelisted()
```







6 changes: 2 additions & 4 deletions docs/ValidatorSet/modules/Delegation/Delegation.md
Original file line number Diff line number Diff line change
Expand Up @@ -486,7 +486,7 @@ Additional mapping to store all vesting managers per user address for fast off-c
### validators

```solidity
function validators(address) external view returns (uint256 liquidDebt, uint256 commission, bool active, bool whitelisted, bool registered)
function validators(address) external view returns (uint256 liquidDebt, uint256 commission, enum ValidatorStatus status)
```


Expand All @@ -505,9 +505,7 @@ function validators(address) external view returns (uint256 liquidDebt, uint256
|---|---|---|
| liquidDebt | uint256 | undefined |
| commission | uint256 | undefined |
| active | bool | undefined |
| whitelisted | bool | undefined |
| registered | bool | undefined |
| status | enum ValidatorStatus | undefined |

### validatorsAddresses

Expand Down
Loading

0 comments on commit e5b98fe

Please sign in to comment.