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

Uptime e2e #637

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Open
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

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

24 changes: 20 additions & 4 deletions contracts/validator-manager/PoSValidatorManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ abstract contract PoSValidatorManager is
uint256 _weightToValueFactor;
/// @notice The reward calculator for this validator manager.
IRewardCalculator _rewardCalculator;
/// @notice The ID of the blockchain that submits uptime proofs. This must be a blockchain validated by the subnetID that this contract manages.
bytes32 _uptimeBlockchainID;
/// @notice Maps the validation ID to its requirements.
mapping(bytes32 validationID => PoSValidatorInfo) _posValidatorInfo;
/// @notice Maps the delegation ID to the delegator information.
Expand Down Expand Up @@ -92,6 +94,7 @@ abstract contract PoSValidatorManager is
error ValidatorIneligibleForRewards(bytes32 validationID);
error DelegatorIneligibleForRewards(bytes32 delegationID);
error ZeroWeightToValueFactor();
error InvalidUptimeBlockchainID(bytes32 uptimeBlockchainID);

// solhint-disable ordering
function _getPoSValidatorManagerStorage()
Expand Down Expand Up @@ -119,7 +122,8 @@ abstract contract PoSValidatorManager is
minimumDelegationFeeBips: settings.minimumDelegationFeeBips,
maximumStakeMultiplier: settings.maximumStakeMultiplier,
weightToValueFactor: settings.weightToValueFactor,
rewardCalculator: settings.rewardCalculator
rewardCalculator: settings.rewardCalculator,
uptimeBlockchainID: settings.uptimeBlockchainID
});
}

Expand All @@ -131,7 +135,8 @@ abstract contract PoSValidatorManager is
uint16 minimumDelegationFeeBips,
uint8 maximumStakeMultiplier,
uint256 weightToValueFactor,
IRewardCalculator rewardCalculator
IRewardCalculator rewardCalculator,
bytes32 uptimeBlockchainID
) internal onlyInitializing {
PoSValidatorManagerStorage storage $ = _getPoSValidatorManagerStorage();
if (minimumDelegationFeeBips == 0 || minimumDelegationFeeBips > MAXIMUM_DELEGATION_FEE_BIPS)
Expand All @@ -152,6 +157,9 @@ abstract contract PoSValidatorManager is
if (weightToValueFactor == 0) {
revert ZeroWeightToValueFactor();
}
if (uptimeBlockchainID == bytes32(0)) {
revert InvalidUptimeBlockchainID(uptimeBlockchainID);
}

$._minimumStakeAmount = minimumStakeAmount;
$._maximumStakeAmount = maximumStakeAmount;
Expand All @@ -160,6 +168,7 @@ abstract contract PoSValidatorManager is
$._maximumStakeMultiplier = maximumStakeMultiplier;
$._weightToValueFactor = weightToValueFactor;
$._rewardCalculator = rewardCalculator;
$._uptimeBlockchainID = uptimeBlockchainID;
}

/**
Expand Down Expand Up @@ -311,9 +320,17 @@ abstract contract PoSValidatorManager is
revert InvalidWarpMessage();
}

if (warpMessage.sourceChainID != WARP_MESSENGER.getBlockchainID()) {
PoSValidatorManagerStorage storage $ = _getPoSValidatorManagerStorage();
// The uptime proof must be from the specifed uptime blockchain
if (warpMessage.sourceChainID != $._uptimeBlockchainID) {
revert InvalidWarpSourceChainID(warpMessage.sourceChainID);
}

// The sender is required to be the zero address so that we know the validator node
// signed the proof directly, rather than as an arbitrary on-chain message
if (warpMessage.originSenderAddress != address(0)) {
revert InvalidWarpOriginSenderAddress(warpMessage.originSenderAddress);
}
if (warpMessage.originSenderAddress != address(0)) {
revert InvalidWarpOriginSenderAddress(warpMessage.originSenderAddress);
}
Expand All @@ -324,7 +341,6 @@ abstract contract PoSValidatorManager is
revert InvalidValidationID(validationID);
}

PoSValidatorManagerStorage storage $ = _getPoSValidatorManagerStorage();
if (uptime > $._posValidatorInfo[validationID].uptimeSeconds) {
$._posValidatorInfo[validationID].uptimeSeconds = uptime;
emit UptimeUpdated(validationID, uptime);
Expand Down
2 changes: 1 addition & 1 deletion contracts/validator-manager/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ Proof-of-Authority validator management is provided via `PoAValidatorManager`, w

### PoSValidatorManager

Proof-of-Stake validator management is provided by the abstract contract `PoSValidatorManager`, which has two concrete implementations: `NativeTokenStakingManager` and `ERC20TokenStakingManager`. In addition to basic validator management provided in `ValidatorManager`, `PoSValidatorManager` supports uptime-based validation rewards, as well as delegation to a chosen validator. This [state transition diagram](./StateTransition.md) illustrates the relationship between validators and delegators.
Proof-of-Stake validator management is provided by the abstract contract `PoSValidatorManager`, which has two concrete implementations: `NativeTokenStakingManager` and `ERC20TokenStakingManager`. In addition to basic validator management provided in `ValidatorManager`, `PoSValidatorManager` supports uptime-based validation rewards, as well as delegation to a chosen validator. The `uptimeBlockchainID` used to initialize the `PoSValidatorManager` **must** be validated by the L1 validator set that the contract manages. **There is no way to verify this from within the contract, so take care when setting this value.** This [state transition diagram](./StateTransition.md) illustrates the relationship between validators and delegators.

> [!NOTE]
> The `weightToValueFactor` fields of the `PoSValidatorManagerSettings` passed to `PoSValidatorManager`'s `initialize` function sets the factor used to convert between the weight that the validator is registered with on the P-Chain, and the value transferred to the contract as stake. This involves integer division, which may result in loss of precision. When selecting `weightToValueFactor`, it's important to make the following considerations:
Expand Down
4 changes: 2 additions & 2 deletions contracts/validator-manager/UptimeMessageSpec.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# `ValidationUptimeMessage` Warp Message Format Reference

Description: Provides a validator's uptime for calculating staking rewards
Description: Provides a validator's uptime for calculating staking rewards (`PoSValidatorManager` only)

Signed by: L1

Expand All @@ -16,4 +16,4 @@ Specification:
| `uptime` | `uint64` | 8 byte |
| | | 46 bytes |

This is defined within `Subnet-EVM` [here](https://github.com/ava-labs/subnet-evm/blob/323eb0c7dd7204521e662a3a355fe78a0e19c0be/warp/messages/validator_uptime.go#L14-L19).
This is defined within `Subnet-EVM` [here](https://github.com/ava-labs/subnet-evm/blob/323eb0c7dd7204521e662a3a355fe78a0e19c0be/warp/messages/validator_uptime.go#L14-L19). The `ValidationUptimeMessage` must be included as an `AddressedPayload` with the `sourceAddress` set to an empty byte array, to prove that it did not originate as an arbitrary on-chain message. The `sourceChainID` must match the `uptimeBlockchainID` used to initialize the `PoSValidatorManager`. `uptimeBlockchainID` must be validated by the L1 validator set managed by the `PoSValidatorManager`.
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,18 @@ enum DelegatorStatus {
}

/**
* @dev PoS Validator Manager settings, used to initialize the PoS Validator Manager
* @notice PoS Validator Manager settings, used to initialize the PoS Validator Manager
* @notice baseSettings specified the base settings for the Validator Manager. See {IValidatorManager-ValidatorManagerSettings}
* @notice minimumStakeAmount is the minimum amount of stake required to stake to a validator
* @notice maximumStakeAmount is the maximum amount of stake that can be staked to a validator
* @notice minimumStakeDuration is the minimum duration that validators must stake for
* @notice minimumDelegationFeeBips is the minimum delegation fee in basis points that validators can charge
* @notice maximumStakeMultiplier is multiplier applied to validator's initial stake amount to determine
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* @notice maximumStakeMultiplier is multiplier applied to validator's initial stake amount to determine
* @notice maximumStakeMultiplier is the multiplier applied to a validator's initial stake amount to determine

* the maximum amount of stake a validator can have with delegations.
* @notice weightToValueFactor is the factor used to convert validator weight to value
* @notice rewardCalculator is the reward calculator used to calculate rewards for this validator manager
* @notice uptimeBlockchainID is the ID of the blockchain that submits uptime proofs.
* This must be a blockchain validated by the subnetID that this contract manages.
*/
struct PoSValidatorManagerSettings {
ValidatorManagerSettings baseSettings;
Expand All @@ -30,6 +41,7 @@ struct PoSValidatorManagerSettings {
uint8 maximumStakeMultiplier;
uint256 weightToValueFactor;
IRewardCalculator rewardCalculator;
bytes32 uptimeBlockchainID;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,10 @@ struct ValidatorChurnPeriod {
}

/**
* @dev Validator Manager settings, used to initialize the Validator Manager
* @notice Validator Manager settings, used to initialize the Validator Manager
* @notice The subnetID is the ID of the subnet that the Validator Manager is managing
* @notice The churnPeriodSeconds is the duration of the churn period in seconds
* @notice The maximumChurnPercentage is the maximum percentage of the total weight that can be added or removed in a single churn period
*/
struct ValidatorManagerSettings {
bytes32 subnetID;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ contract ERC20TokenStakingManagerTest is PoSValidatorManagerTest {
minimumDelegationFeeBips: 0,
maximumStakeMultiplier: DEFAULT_MAXIMUM_STAKE_MULTIPLIER,
weightToValueFactor: DEFAULT_WEIGHT_TO_VALUE_FACTOR,
rewardCalculator: IRewardCalculator(address(0))
rewardCalculator: IRewardCalculator(address(0)),
uptimeBlockchainID: DEFAULT_SOURCE_BLOCKCHAIN_ID
}),
token
);
Expand All @@ -83,7 +84,8 @@ contract ERC20TokenStakingManagerTest is PoSValidatorManagerTest {
minimumDelegationFeeBips: minimumDelegationFeeBips,
maximumStakeMultiplier: DEFAULT_MAXIMUM_STAKE_MULTIPLIER,
weightToValueFactor: DEFAULT_WEIGHT_TO_VALUE_FACTOR,
rewardCalculator: IRewardCalculator(address(0))
rewardCalculator: IRewardCalculator(address(0)),
uptimeBlockchainID: DEFAULT_SOURCE_BLOCKCHAIN_ID
}),
token
);
Expand All @@ -109,7 +111,8 @@ contract ERC20TokenStakingManagerTest is PoSValidatorManagerTest {
minimumDelegationFeeBips: DEFAULT_MINIMUM_DELEGATION_FEE_BIPS,
maximumStakeMultiplier: DEFAULT_MAXIMUM_STAKE_MULTIPLIER,
weightToValueFactor: DEFAULT_WEIGHT_TO_VALUE_FACTOR,
rewardCalculator: IRewardCalculator(address(0))
rewardCalculator: IRewardCalculator(address(0)),
uptimeBlockchainID: DEFAULT_SOURCE_BLOCKCHAIN_ID
}),
token
);
Expand All @@ -133,7 +136,8 @@ contract ERC20TokenStakingManagerTest is PoSValidatorManagerTest {
minimumDelegationFeeBips: DEFAULT_MINIMUM_DELEGATION_FEE_BIPS,
maximumStakeMultiplier: 0,
weightToValueFactor: DEFAULT_WEIGHT_TO_VALUE_FACTOR,
rewardCalculator: IRewardCalculator(address(0))
rewardCalculator: IRewardCalculator(address(0)),
uptimeBlockchainID: DEFAULT_SOURCE_BLOCKCHAIN_ID
}),
token
);
Expand All @@ -160,7 +164,8 @@ contract ERC20TokenStakingManagerTest is PoSValidatorManagerTest {
minimumDelegationFeeBips: DEFAULT_MINIMUM_DELEGATION_FEE_BIPS,
maximumStakeMultiplier: DEFAULT_MAXIMUM_STAKE_MULTIPLIER,
weightToValueFactor: DEFAULT_WEIGHT_TO_VALUE_FACTOR,
rewardCalculator: IRewardCalculator(address(0))
rewardCalculator: IRewardCalculator(address(0)),
uptimeBlockchainID: DEFAULT_SOURCE_BLOCKCHAIN_ID
}),
token
);
Expand All @@ -187,7 +192,8 @@ contract ERC20TokenStakingManagerTest is PoSValidatorManagerTest {
minimumDelegationFeeBips: DEFAULT_MINIMUM_DELEGATION_FEE_BIPS,
maximumStakeMultiplier: maximumStakeMultiplier,
weightToValueFactor: DEFAULT_WEIGHT_TO_VALUE_FACTOR,
rewardCalculator: IRewardCalculator(address(0))
rewardCalculator: IRewardCalculator(address(0)),
uptimeBlockchainID: DEFAULT_SOURCE_BLOCKCHAIN_ID
}),
token
);
Expand All @@ -211,7 +217,8 @@ contract ERC20TokenStakingManagerTest is PoSValidatorManagerTest {
minimumDelegationFeeBips: DEFAULT_MINIMUM_DELEGATION_FEE_BIPS,
maximumStakeMultiplier: DEFAULT_MAXIMUM_STAKE_MULTIPLIER,
weightToValueFactor: 0,
rewardCalculator: IRewardCalculator(address(0))
rewardCalculator: IRewardCalculator(address(0)),
uptimeBlockchainID: DEFAULT_SOURCE_BLOCKCHAIN_ID
}),
token
);
Expand Down Expand Up @@ -315,7 +322,8 @@ contract ERC20TokenStakingManagerTest is PoSValidatorManagerTest {
minimumDelegationFeeBips: DEFAULT_MINIMUM_DELEGATION_FEE_BIPS,
maximumStakeMultiplier: DEFAULT_MAXIMUM_STAKE_MULTIPLIER,
weightToValueFactor: DEFAULT_WEIGHT_TO_VALUE_FACTOR,
rewardCalculator: rewardCalculator
rewardCalculator: rewardCalculator,
uptimeBlockchainID: DEFAULT_SOURCE_BLOCKCHAIN_ID
}),
token
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ contract NativeTokenStakingManagerTest is PoSValidatorManagerTest {
minimumDelegationFeeBips: 0,
maximumStakeMultiplier: DEFAULT_MAXIMUM_STAKE_MULTIPLIER,
weightToValueFactor: DEFAULT_WEIGHT_TO_VALUE_FACTOR,
rewardCalculator: IRewardCalculator(address(0))
rewardCalculator: IRewardCalculator(address(0)),
uptimeBlockchainID: DEFAULT_SOURCE_BLOCKCHAIN_ID
})
);
}
Expand All @@ -77,7 +78,8 @@ contract NativeTokenStakingManagerTest is PoSValidatorManagerTest {
minimumDelegationFeeBips: minimumDelegationFeeBips,
maximumStakeMultiplier: DEFAULT_MAXIMUM_STAKE_MULTIPLIER,
weightToValueFactor: DEFAULT_WEIGHT_TO_VALUE_FACTOR,
rewardCalculator: IRewardCalculator(address(0))
rewardCalculator: IRewardCalculator(address(0)),
uptimeBlockchainID: DEFAULT_SOURCE_BLOCKCHAIN_ID
})
);
}
Expand All @@ -102,7 +104,8 @@ contract NativeTokenStakingManagerTest is PoSValidatorManagerTest {
minimumDelegationFeeBips: DEFAULT_MINIMUM_DELEGATION_FEE_BIPS,
maximumStakeMultiplier: DEFAULT_MAXIMUM_STAKE_MULTIPLIER,
weightToValueFactor: DEFAULT_WEIGHT_TO_VALUE_FACTOR,
rewardCalculator: IRewardCalculator(address(0))
rewardCalculator: IRewardCalculator(address(0)),
uptimeBlockchainID: DEFAULT_SOURCE_BLOCKCHAIN_ID
})
);
}
Expand All @@ -125,7 +128,8 @@ contract NativeTokenStakingManagerTest is PoSValidatorManagerTest {
minimumDelegationFeeBips: DEFAULT_MINIMUM_DELEGATION_FEE_BIPS,
maximumStakeMultiplier: 0,
weightToValueFactor: DEFAULT_WEIGHT_TO_VALUE_FACTOR,
rewardCalculator: IRewardCalculator(address(0))
rewardCalculator: IRewardCalculator(address(0)),
uptimeBlockchainID: DEFAULT_SOURCE_BLOCKCHAIN_ID
})
);
}
Expand All @@ -151,7 +155,8 @@ contract NativeTokenStakingManagerTest is PoSValidatorManagerTest {
minimumDelegationFeeBips: DEFAULT_MINIMUM_DELEGATION_FEE_BIPS,
maximumStakeMultiplier: maximumStakeMultiplier,
weightToValueFactor: DEFAULT_WEIGHT_TO_VALUE_FACTOR,
rewardCalculator: IRewardCalculator(address(0))
rewardCalculator: IRewardCalculator(address(0)),
uptimeBlockchainID: DEFAULT_SOURCE_BLOCKCHAIN_ID
})
);
}
Expand All @@ -174,7 +179,8 @@ contract NativeTokenStakingManagerTest is PoSValidatorManagerTest {
minimumDelegationFeeBips: DEFAULT_MINIMUM_DELEGATION_FEE_BIPS,
maximumStakeMultiplier: DEFAULT_MAXIMUM_STAKE_MULTIPLIER,
weightToValueFactor: 0,
rewardCalculator: IRewardCalculator(address(0))
rewardCalculator: IRewardCalculator(address(0)),
uptimeBlockchainID: DEFAULT_SOURCE_BLOCKCHAIN_ID
})
);
}
Expand All @@ -200,7 +206,8 @@ contract NativeTokenStakingManagerTest is PoSValidatorManagerTest {
minimumDelegationFeeBips: DEFAULT_MINIMUM_DELEGATION_FEE_BIPS,
maximumStakeMultiplier: DEFAULT_MAXIMUM_STAKE_MULTIPLIER,
weightToValueFactor: DEFAULT_WEIGHT_TO_VALUE_FACTOR,
rewardCalculator: IRewardCalculator(address(0))
rewardCalculator: IRewardCalculator(address(0)),
uptimeBlockchainID: DEFAULT_SOURCE_BLOCKCHAIN_ID
})
);
}
Expand Down Expand Up @@ -282,7 +289,8 @@ contract NativeTokenStakingManagerTest is PoSValidatorManagerTest {
minimumDelegationFeeBips: DEFAULT_MINIMUM_DELEGATION_FEE_BIPS,
maximumStakeMultiplier: DEFAULT_MAXIMUM_STAKE_MULTIPLIER,
weightToValueFactor: DEFAULT_WEIGHT_TO_VALUE_FACTOR,
rewardCalculator: rewardCalculator
rewardCalculator: rewardCalculator,
uptimeBlockchainID: DEFAULT_SOURCE_BLOCKCHAIN_ID
})
);
validatorManager = app;
Expand Down
Loading