Skip to content

Commit

Permalink
Merge pull request #637 from ava-labs/uptime-e2e
Browse files Browse the repository at this point in the history
Uptime e2e
  • Loading branch information
cam-schultz authored Nov 18, 2024
2 parents d29f788 + ee68b4d commit 3f34205
Show file tree
Hide file tree
Showing 19 changed files with 438 additions and 124 deletions.

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 @@ -307,9 +316,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 @@ -320,7 +337,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`.
14 changes: 13 additions & 1 deletion contracts/validator-manager/interfaces/IPoSValidatorManager.sol
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 the multiplier applied to 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
5 changes: 4 additions & 1 deletion contracts/validator-manager/interfaces/IValidatorManager.sol
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 @@ -52,7 +52,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 @@ -78,7 +79,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 @@ -103,7 +105,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 @@ -126,7 +129,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 @@ -152,7 +156,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 @@ -175,7 +180,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 @@ -201,7 +207,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 @@ -273,7 +280,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

0 comments on commit 3f34205

Please sign in to comment.