-
Notifications
You must be signed in to change notification settings - Fork 0
Description
Summary
The ValidatorManagement contract does not enforce uniqueness of consensusPubkey across validators. Multiple validators can register or rotate to the same consensus public key, which could cause issues at the consensus layer.
Severity
Medium - Potential consensus layer impact
Description
When registering a new validator via registerValidator() or rotating keys via rotateConsensusKey(), there is no validation to ensure the consensusPubkey is not already in use by another validator.
Current Behavior
The _validateRegistration() function checks:
- ✅ StakePool is valid (created by factory)
- ✅ Caller is the pool's operator
- ✅ StakePool is not already registered as validator
- ✅ Voting power meets minimum bond
- ✅ Moniker length is valid
- ❌ Missing: consensusPubkey uniqueness
// ValidatorManagement.sol - _createValidatorRecord()
// No check for duplicate pubkey before assignment
record.consensusPubkey = consensusPubkey;Expected Behavior
The contract should reject registration or key rotation if the consensus public key is already assigned to another active validator.
Impact
- Signature Ambiguity: Two validators signing blocks with the same key could cause the consensus engine to be unable to distinguish the source
- Equivocation Detection: May trigger false-positive equivocation (double-signing) detection
- Security: A malicious actor could intentionally use another validator's pubkey to cause disruption
Suggested Fix
- Add a mapping to track pubkey usage:
/// @notice Tracks which validator is using each consensus pubkey
/// @dev keccak256(pubkey) => stakePool address (address(0) if unused)
mapping(bytes32 => address) internal _pubkeyToValidator;- Add validation in
_validateRegistration():
bytes32 keyHash = keccak256(consensusPubkey);
if (_pubkeyToValidator[keyHash] != address(0)) {
revert Errors.DuplicateConsensusPubkey(consensusPubkey);
}- Update mapping on registration and key rotation:
// In _createValidatorRecord()
_pubkeyToValidator[keccak256(consensusPubkey)] = stakePool;
// In rotateConsensusKey() - clear old, set new
delete _pubkeyToValidator[keccak256(validator.consensusPubkey)];
_pubkeyToValidator[keccak256(newPubkey)] = stakePool;-
Clear mapping when validator is removed (if applicable)
-
Add new error to
Errors.sol:
/// @notice Consensus public key is already in use by another validator
/// @param pubkey The duplicate consensus public key
error DuplicateConsensusPubkey(bytes pubkey);Reference
Aptos's stake.move enforces consensus key uniqueness - this aligns with that security model.
Files Affected
src/staking/ValidatorManagement.solsrc/foundation/Errors.sol