Skip to content

Commit

Permalink
Merge pull request #520 from ava-labs/delegation-track-uptime
Browse files Browse the repository at this point in the history
Track uptimes for delegation period
  • Loading branch information
cam-schultz authored Sep 5, 2024
2 parents 24b9c61 + 0834d6c commit 666f5d7
Show file tree
Hide file tree
Showing 7 changed files with 87 additions and 395 deletions.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

75 changes: 44 additions & 31 deletions contracts/staking/PoSValidatorManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,6 @@ abstract contract PoSValidatorManager is IPoSValidatorManager, ValidatorManager
/// @notice Maps the validationID to a mapping of delegator address to pending end delegator messages.
mapping(bytes32 validationID => mapping(address delegator => bytes))
_pendingEndDelegatorMessages;
/// @notice Maps the validationID to the uptime of the validator.
mapping(bytes32 validationID => uint64) _validatorUptimes;
}
// solhint-enable private-vars-leading-underscore

Expand Down Expand Up @@ -79,11 +77,11 @@ abstract contract PoSValidatorManager is IPoSValidatorManager, ValidatorManager
uint64 minimumStakeDuration,
IRewardCalculator rewardCalculator
) internal onlyInitializing {
PoSValidatorManagerStorage storage s = _getPoSValidatorManagerStorage();
s._minimumStakeAmount = minimumStakeAmount;
s._maximumStakeAmount = maximumStakeAmount;
s._minimumStakeDuration = minimumStakeDuration;
s._rewardCalculator = rewardCalculator;
PoSValidatorManagerStorage storage $ = _getPoSValidatorManagerStorage();
$._minimumStakeAmount = minimumStakeAmount;
$._maximumStakeAmount = maximumStakeAmount;
$._minimumStakeDuration = minimumStakeDuration;
$._rewardCalculator = rewardCalculator;
}

Check warning

Code scanning / Slither

Conformance to Solidity naming conventions Warning


function initializeEndValidation(
Expand All @@ -92,34 +90,36 @@ abstract contract PoSValidatorManager is IPoSValidatorManager, ValidatorManager
uint32 messageIndex
) external {
if (includeUptimeProof) {
PoSValidatorManagerStorage storage $ = _getPoSValidatorManagerStorage();
(WarpMessage memory warpMessage, bool valid) =
WARP_MESSENGER.getVerifiedWarpMessage(messageIndex);
require(valid, "PoSValidatorManager: invalid warp message");

require(
warpMessage.sourceChainID == WARP_MESSENGER.getBlockchainID(),
"PoSValidatorManager: invalid source chain ID"
);
require(
warpMessage.originSenderAddress == address(0),
"PoSValidatorManager: invalid origin sender address"
);

(bytes32 uptimeValidationID, uint64 uptime) =
ValidatorMessages.unpackValidationUptimeMessage(warpMessage.payload);
require(
validationID == uptimeValidationID,
"PoSValidatorManager: invalid uptime validation ID"
);

$._validatorUptimes[validationID] = uptime;
emit ValidationUptimeUpdated(validationID, uptime);
_getUptime(validationID, messageIndex);
}
// TODO: Calculate the reward for the validator, but do not unlock it

_initializeEndValidation(validationID);
}

function _getUptime(bytes32 validationID, uint32 messageIndex) internal view returns (uint64) {
(WarpMessage memory warpMessage, bool valid) =
WARP_MESSENGER.getVerifiedWarpMessage(messageIndex);
require(valid, "PoSValidatorManager: invalid warp message");

require(
warpMessage.sourceChainID == WARP_MESSENGER.getBlockchainID(),
"PoSValidatorManager: invalid source chain ID"
);
require(
warpMessage.originSenderAddress == address(0),
"PoSValidatorManager: invalid origin sender address"
);

(bytes32 uptimeValidationID, uint64 uptime) =
ValidatorMessages.unpackValidationUptimeMessage(warpMessage.payload);
require(
validationID == uptimeValidationID, "PoSValidatorManager: invalid uptime validation ID"
);

return uptime;
}

function _processStake(uint256 stakeAmount) internal virtual returns (uint64) {
PoSValidatorManagerStorage storage $ = _getPoSValidatorManagerStorage();
// Lock the stake in the contract.
Expand Down Expand Up @@ -241,7 +241,18 @@ abstract contract PoSValidatorManager is IPoSValidatorManager, ValidatorManager
});
}

function initializeEndDelegation(bytes32 validationID) external {
function initializeEndDelegation(
bytes32 validationID,
bool includeUptimeProof,
uint32 messageIndex
) external {
uint64 uptime;
if (includeUptimeProof) {
uptime = _getUptime(validationID, messageIndex);
}

// TODO: Calculate the delegator's reward, but do not unlock it

PoSValidatorManagerStorage storage $ = _getPoSValidatorManagerStorage();

// Ensure the delegator is active
Expand Down Expand Up @@ -310,6 +321,8 @@ abstract contract PoSValidatorManager is IPoSValidatorManager, ValidatorManager
// Update the delegator status
$._delegatorStakes[validationID][delegator].status = DelegatorStatus.Completed;

// TODO: Unlock the delegator's stake and their reward

emit DelegationEnded(validationID, delegator, nonce);
}

Expand Down
4 changes: 1 addition & 3 deletions contracts/staking/ValidatorManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -304,9 +304,7 @@ abstract contract ValidatorManager is
validator.status = endStatus;
$._validationPeriods[validationID] = validator;

// Unlock the stake.

// Calculate the reward for the validator.
// TODO: Unlock the stake.

// Emit event.
emit ValidationPeriodEnded(validationID, validator.status);
Expand Down
17 changes: 9 additions & 8 deletions contracts/staking/interfaces/IPoSValidatorManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,6 @@ struct Delegator {
}

interface IPoSValidatorManager is IValidatorManager {
/**
* @notice Event emitted when a validator's uptime is updated.
* @param validationID The ID of the validation period
* @param uptime The new uptime of the validator
*/
event ValidationUptimeUpdated(bytes32 indexed validationID, uint64 uptime);

/**
* @notice Event emitted when a delegator registration is initiated
* @param validationID The ID of the validation period
Expand Down Expand Up @@ -139,8 +132,16 @@ interface IPoSValidatorManager is IValidatorManager {
* @notice Begins the process of removing a delegator from a validation period. The delegator must have been previously
* registered with the given validationID.
* @param validationID The ID of the validation period being removed.
* @param includeUptimeProof Whether or not an uptime proof is provided for the validation period.
* If no uptime proof is provided, the validation uptime for the delegation period will be assumed to be 0.
* @param messageIndex If {includeUptimeProof} is true, the index of the Warp message to be received providing the
* uptime proof.
*/
function initializeEndDelegation(bytes32 validationID) external;
function initializeEndDelegation(
bytes32 validationID,
bool includeUptimeProof,
uint32 messageIndex
) external;

/**
* @notice Resubmits a delegator end message to be sent to the P-Chain.
Expand Down
36 changes: 1 addition & 35 deletions contracts/staking/tests/PoSValidatorManagerTests.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@ abstract contract PoSValidatorManagerTest is ValidatorManagerTest {

PoSValidatorManager public posValidatorManager;

event ValidationUptimeUpdated(bytes32 indexed validationID, uint64 uptime);

event DelegatorAdded(
bytes32 indexed validationID,
bytes32 indexed setWeightMessageID,
Expand Down Expand Up @@ -55,38 +53,6 @@ abstract contract PoSValidatorManagerTest is ValidatorManagerTest {
bytes32 indexed validationID, address indexed delegator, uint64 indexed nonce
);

function testInitializeEndValidationWithUptimeProof() public {
bytes32 validationID = _setUpCompleteValidatorRegistration({
nodeID: DEFAULT_NODE_ID,
subnetID: DEFAULT_SUBNET_ID,
weight: DEFAULT_WEIGHT,
registrationExpiry: DEFAULT_EXPIRY,
blsPublicKey: DEFAULT_BLS_PUBLIC_KEY,
registrationTimestamp: DEFAULT_REGISTRATION_TIMESTAMP
});

_mockGetBlockchainID();
vm.mockCall(
WARP_PRECOMPILE_ADDRESS,
abi.encodeWithSelector(IWarpMessenger.getVerifiedWarpMessage.selector, uint32(0)),
abi.encode(
WarpMessage({
sourceChainID: DEFAULT_SOURCE_BLOCKCHAIN_ID,
originSenderAddress: address(0),
payload: ValidatorMessages.packValidationUptimeMessage(validationID, DEFAULT_UPTIME)
}),
true
)
);
vm.expectCall(
WARP_PRECOMPILE_ADDRESS, abi.encodeCall(IWarpMessenger.getVerifiedWarpMessage, 0)
);

vm.expectEmit(true, true, true, true, address(posValidatorManager));
emit ValidationUptimeUpdated(validationID, DEFAULT_UPTIME);
posValidatorManager.initializeEndValidation(validationID, true, 0);
}

function testInvalidUptimeWarpMessage() public {
bytes32 validationID = _setUpCompleteValidatorRegistration({
nodeID: DEFAULT_NODE_ID,
Expand Down Expand Up @@ -683,7 +649,7 @@ abstract contract PoSValidatorManagerTest is ValidatorManagerTest {
endTime: endDelegationTimestamp
});
vm.prank(delegator);
posValidatorManager.initializeEndDelegation(validationID);
posValidatorManager.initializeEndDelegation(validationID, false, 0);
return validationID;
}

Expand Down
4 changes: 4 additions & 0 deletions tests/utils/staking.go
Original file line number Diff line number Diff line change
Expand Up @@ -745,6 +745,8 @@ func InitializeEndERC20Delegation(
tx, err := stakingManager.InitializeEndDelegation(
opts,
validationID,
false,
0,
)
Expect(err).Should(BeNil())
return WaitForTransactionSuccess(context.Background(), subnet, tx.Hash())
Expand Down Expand Up @@ -826,6 +828,8 @@ func InitializeEndNativeDelegation(
tx, err := stakingManager.InitializeEndDelegation(
opts,
validationID,
false,
0,
)
Expect(err).Should(BeNil())
return WaitForTransactionSuccess(context.Background(), subnet, tx.Hash())
Expand Down

0 comments on commit 666f5d7

Please sign in to comment.