diff --git a/src/contracts/interfaces/IBLSPubkeyRegistry.sol b/src/contracts/interfaces/IBLSPubkeyRegistry.sol index 8d45e1dc4..3f273acda 100644 --- a/src/contracts/interfaces/IBLSPubkeyRegistry.sol +++ b/src/contracts/interfaces/IBLSPubkeyRegistry.sol @@ -60,7 +60,7 @@ interface IBLSPubkeyRegistry is IRegistry { * 2) `quorumNumbers.length` != 0 * 3) `quorumNumbers` is ordered in ascending order * 4) the operator is not already deregistered - * 5) `quorumNumbers` is the same as the parameter use when registering + * 5) `quorumNumbers` is a subset of the quorumNumbers that the operator is registered for * 6) `pubkey` is the same as the parameter used when registering */ function deregisterOperator(address operator, bool completeDeregistration, bytes calldata quorumNumbers, BN254.G1Point memory pubkey) external returns(bytes32); diff --git a/src/contracts/interfaces/IIndexRegistry.sol b/src/contracts/interfaces/IIndexRegistry.sol index b1748c4ac..19978815b 100644 --- a/src/contracts/interfaces/IIndexRegistry.sol +++ b/src/contracts/interfaces/IIndexRegistry.sol @@ -53,7 +53,7 @@ interface IIndexRegistry is IRegistry { * 2) `quorumNumbers.length` != 0 * 3) `quorumNumbers` is ordered in ascending order * 4) the operator is not already deregistered - * 5) `quorumNumbers` is the same as the parameter use when registering + * 5) `quorumNumbers` is a subset of the quorumNumbers that the operator is registered for */ function deregisterOperator(bytes32 operatorId, bool completeDeregistration, bytes calldata quorumNumbers, bytes32[] memory operatorIdsToSwap, uint32 globalOperatorListIndex) external; diff --git a/src/contracts/interfaces/IRegistryCoordinator.sol b/src/contracts/interfaces/IRegistryCoordinator.sol index d55183b93..0097224bf 100644 --- a/src/contracts/interfaces/IRegistryCoordinator.sol +++ b/src/contracts/interfaces/IRegistryCoordinator.sol @@ -31,7 +31,7 @@ interface IRegistryCoordinator { // the id of the operator, which is likely the keccak256 hash of the operator's public key if using BLSRegsitry bytes32 operatorId; // start taskNumber from which the operator has been registered - uint32 fromTaskNumber; + uint32 fromTaskNumber; // TODO: REMOVE // indicates whether the operator is actively registered for serving the middleware or not OperatorStatus status; } diff --git a/src/contracts/interfaces/IStakeRegistry.sol b/src/contracts/interfaces/IStakeRegistry.sol index c430d544b..4f8f257ca 100644 --- a/src/contracts/interfaces/IStakeRegistry.sol +++ b/src/contracts/interfaces/IStakeRegistry.sol @@ -56,7 +56,7 @@ interface IStakeRegistry is IRegistry { * 2) `quorumNumbers.length` != 0 * 3) `quorumNumbers` is ordered in ascending order * 4) the operator is not already deregistered - * 5) `quorumNumbers` is the same as the parameter use when registering + * 5) `quorumNumbers` is a subset of the quorumNumbers that the operator is registered for */ function deregisterOperator(bytes32 operatorId, bytes memory quorumNumbers) external; @@ -136,50 +136,6 @@ interface IStakeRegistry is IRegistry { */ function getCurrentTotalStakeForQuorum(uint8 quorumNumber) external view returns (uint96); - /** - * @notice Checks that the `operator` was active at the `blockNumber`, using the specified `stakeHistoryIndex` as proof. - * @param operatorId is the id of the operator of interest - * @param blockNumber is the block number of interest - * @param quorumNumber is the quorum number which the operator had stake in - * @param stakeHistoryIndex specifies the index in `operatorIdToStakeHistory[operatorId]` at which to check the claim of the operator's activity - * @return 'true' if it is succesfully proven that the `operator` was active at the `blockNumber`, and 'false' otherwise - * @dev In order for this function to return 'true', the inputs must satisfy all of the following list: - * 1) `operatorIdToStakeHistory[operatorId][quorumNumber][index].updateBlockNumber <= blockNumber` - * 2) `operatorIdToStakeHistory[operatorId][quorumNumber][index].nextUpdateBlockNumber` must be either `0` (signifying no next update) or - * is must be strictly greater than `blockNumber` - * 3) `operatorIdToStakeHistory[operatorId][quorumNumber][index].stake > 0` i.e. the operator had nonzero stake - * @dev Note that a return value of 'false' does not guarantee that the `operator` was inactive at `blockNumber`, since a - * bad `stakeHistoryIndex` can be supplied in order to obtain a response of 'false'. - */ - function checkOperatorActiveAtBlockNumber( - bytes32 operatorId, - uint256 blockNumber, - uint8 quorumNumber, - uint256 stakeHistoryIndex - ) external view returns (bool); - - /** - * @notice Checks that the `operator` was inactive at the `blockNumber`, using the specified `stakeHistoryIndex` for `quorumNumber` as proof. - * @param operatorId is the id of the operator of interest - * @param blockNumber is the block number of interest - * @param quorumNumber is the quorum number which the operator had no stake in - * @param stakeHistoryIndex specifies the index in `operatorIdToStakeHistory[operatorId]` at which to check the claim of the operator's inactivity - * @return 'true' if it is succesfully proven that the `operator` was inactive at the `blockNumber`, and 'false' otherwise - * @dev In order for this function to return 'true', the inputs must satisfy all of the following list: - * 1) `operatorIdToStakeHistory[operatorId][quorumNumber][index].updateBlockNumber <= blockNumber` - * 2) `operatorIdToStakeHistory[operatorId][quorumNumber][index].nextUpdateBlockNumber` must be either `0` (signifying no next update) or - * is must be strictly greater than `blockNumber` - * 3) `operatorIdToStakeHistory[operatorId][quorumNumber][index].stake == 0` i.e. the operator had zero stake - * @dev Note that a return value of 'false' does not guarantee that the `operator` was active at `blockNumber`, since a - * bad `stakeHistoryIndex` can be supplied in order to obtain a response of 'false'. - */ - function checkOperatorInactiveAtBlockNumber( - bytes32 operatorId, - uint256 blockNumber, - uint8 quorumNumber, - uint256 stakeHistoryIndex - ) external view returns (bool); - /** * @notice Used for updating information on deposits of nodes. * @param operators are the addresses of the operators whose stake information is getting updated diff --git a/src/contracts/middleware/BLSPubkeyRegistry.sol b/src/contracts/middleware/BLSPubkeyRegistry.sol index 64b713eac..55308c2b1 100644 --- a/src/contracts/middleware/BLSPubkeyRegistry.sol +++ b/src/contracts/middleware/BLSPubkeyRegistry.sol @@ -83,7 +83,7 @@ contract BLSPubkeyRegistry is IBLSPubkeyRegistry, Test { * 2) `quorumNumbers.length` != 0 * 3) `quorumNumbers` is ordered in ascending order * 4) the operator is not already deregistered - * 5) `quorumNumbers` is the same as the parameter use when registering + * 5) `quorumNumbers` is a subset of the quorumNumbers that the operator is registered for * 6) `pubkey` is the same as the parameter used when registering */ function deregisterOperator(address operator, bool completeDeregistration, bytes memory quorumNumbers, BN254.G1Point memory pubkey) external onlyRegistryCoordinator returns(bytes32){ diff --git a/src/contracts/middleware/IndexRegistry.sol b/src/contracts/middleware/IndexRegistry.sol index b01dad7d8..d89c48fcd 100644 --- a/src/contracts/middleware/IndexRegistry.sol +++ b/src/contracts/middleware/IndexRegistry.sol @@ -69,7 +69,7 @@ contract IndexRegistry is IIndexRegistry { * 2) `quorumNumbers.length` != 0 * 3) `quorumNumbers` is ordered in ascending order * 4) the operator is not already deregistered - * 5) `quorumNumbers` is the same as the parameter use when registering + * 5) `quorumNumbers` is a subset of the quorumNumbers that the operator is registered for */ function deregisterOperator(bytes32 operatorId, bool completeDeregistration, bytes calldata quorumNumbers, bytes32[] memory operatorIdsToSwap, uint32 globalOperatorListIndex) external onlyRegistryCoordinator { require(quorumNumbers.length == operatorIdsToSwap.length, "IndexRegistry.deregisterOperator: quorumNumbers and operatorIdsToSwap must be the same length"); diff --git a/src/contracts/middleware/StakeRegistry.sol b/src/contracts/middleware/StakeRegistry.sol index e741877a9..ef47b4818 100644 --- a/src/contracts/middleware/StakeRegistry.sol +++ b/src/contracts/middleware/StakeRegistry.sol @@ -196,85 +196,6 @@ contract StakeRegistry is StakeRegistryStorage { return _totalStakeHistory[quorumNumber].length; } - /** - * @notice Checks that the `operator` was active at the `blockNumber`, using the specified `stakeHistoryIndex` as proof. - * @param operatorId is the id of the operator of interest - * @param blockNumber is the block number of interest - * @param quorumNumber is the quorum number which the operator had stake in - * @param stakeHistoryIndex specifies the index in `operatorIdToStakeHistory[operatorId]` at which to check the claim of the operator's activity - * @return 'true' if it is succesfully proven that the `operator` was active at the `blockNumber`, and 'false' otherwise - * @dev In order for this function to return 'true', the inputs must satisfy all of the following list: - * 1) `operatorIdToStakeHistory[operatorId][quorumNumber][index].updateBlockNumber <= blockNumber` - * 2) `operatorIdToStakeHistory[operatorId][quorumNumber][index].nextUpdateBlockNumber` must be either `0` (signifying no next update) or - * is must be strictly greater than `blockNumber` - * 3) `operatorIdToStakeHistory[operatorId][quorumNumber][index].stake > 0` i.e. the operator had nonzero stake - * @dev Note that a return value of 'false' does not guarantee that the `operator` was inactive at `blockNumber`, since a - * bad `stakeHistoryIndex` can be supplied in order to obtain a response of 'false'. - */ - function checkOperatorActiveAtBlockNumber( - bytes32 operatorId, - uint256 blockNumber, - uint8 quorumNumber, - uint256 stakeHistoryIndex - ) external view returns (bool) - { - // pull the stake history entry specified by `stakeHistoryIndex` - OperatorStakeUpdate memory operatorStakeUpdate = operatorIdToStakeHistory[operatorId][quorumNumber][stakeHistoryIndex]; - return ( - // check that the update specified by `stakeHistoryIndex` occurred at or prior to `blockNumber` - (operatorStakeUpdate.updateBlockNumber <= blockNumber) - && - // if there is a next update, then check that the next update occurred strictly after `blockNumber` - (operatorStakeUpdate.nextUpdateBlockNumber == 0 || operatorStakeUpdate.nextUpdateBlockNumber > blockNumber) - && - /// verify that the stake was non-zero at the time (note: here was use the assumption that the operator was 'inactive' - /// once their stake fell to zero) - operatorStakeUpdate.stake != 0 // this implicitly checks that the operator was a part of the quorum of interest - ); - } - - /** - * @notice Checks that the `operator` was inactive at the `blockNumber`, using the specified `stakeHistoryIndex` for `quorumNumber` as proof. - * @param operatorId is the id of the operator of interest - * @param blockNumber is the block number of interest - * @param quorumNumber is the quorum number which the operator had no stake in - * @param stakeHistoryIndex specifies the index in `operatorIdToStakeHistory[operatorId]` at which to check the claim of the operator's inactivity - * @return 'true' if it is succesfully proven that the `operator` was inactive at the `blockNumber`, and 'false' otherwise - * @dev In order for this function to return 'true', the inputs must satisfy all of the following list: - * 1) `operatorIdToStakeHistory[operatorId][quorumNumber][index].updateBlockNumber <= blockNumber` - * 2) `operatorIdToStakeHistory[operatorId][quorumNumber][index].nextUpdateBlockNumber` must be either `0` (signifying no next update) or - * is must be strictly greater than `blockNumber` - * 3) `operatorIdToStakeHistory[operatorId][quorumNumber][index].stake == 0` i.e. the operator had zero stake - * @dev Note that a return value of 'false' does not guarantee that the `operator` was active at `blockNumber`, since a - * bad `stakeHistoryIndex` can be supplied in order to obtain a response of 'false'. - * @dev One precondition that must be checked is that the operator is a part of the given `quorumNumber` - */ - function checkOperatorInactiveAtBlockNumber( - bytes32 operatorId, - uint256 blockNumber, - uint8 quorumNumber, - uint256 stakeHistoryIndex - ) external view returns (bool) - { - // special case for `operatorIdToStakeHistory[operatorId]` having length zero -- in which case we know the operator was never registered - if (operatorIdToStakeHistory[operatorId][quorumNumber].length == 0) { - return true; - } - // pull the stake history entry specified by `stakeHistoryIndex` - OperatorStakeUpdate memory operatorStakeUpdate = operatorIdToStakeHistory[operatorId][quorumNumber][stakeHistoryIndex]; - return ( - // check that the update specified by `stakeHistoryIndex` occurred at or prior to `blockNumber` - (operatorStakeUpdate.updateBlockNumber <= blockNumber) - && - // if there is a next update, then check that the next update occurred strictly after `blockNumber` - (operatorStakeUpdate.nextUpdateBlockNumber == 0 || operatorStakeUpdate.nextUpdateBlockNumber > blockNumber) - && - /// verify that the stake was zero at the time (note: here was use the assumption that the operator was 'inactive' - /// once their stake fell to zero) - operatorStakeUpdate.stake == 0 - ); - } - // MUTATING FUNCTIONS /// @notice Adjusts the `minimumStakeFirstQuorum` -- i.e. the node stake (weight) requirement for inclusion in the 1st quorum. @@ -308,7 +229,7 @@ contract StakeRegistry is StakeRegistryStorage { * 2) `quorumNumbers.length` != 0 * 3) `quorumNumbers` is ordered in ascending order * 4) the operator is not already deregistered - * 5) `quorumNumbers` is the same as the parameter use when registering + * 5) `quorumNumbers` is a subset of the quorumNumbers that the operator is registered for */ function deregisterOperator(bytes32 operatorId, bytes calldata quorumNumbers) external virtual onlyRegistryCoordinator { _deregisterOperator(operatorId, quorumNumbers); @@ -418,9 +339,7 @@ contract StakeRegistry is StakeRegistryStorage { * stake updates. These operator's individual stake updates will have a 0 stake value for the latest update. */ function _deregisterOperator(bytes32 operatorId, bytes memory quorumNumbers) internal { - uint8 quorumNumbersLength = uint8(quorumNumbers.length); // check the operator is deregistering from only valid quorums - require(uint8(quorumNumbers[quorumNumbersLength - 1]) < quorumCount, "StakeRegistry._registerOperator: greatest quorumNumber must be less than quorumCount"); OperatorStakeUpdate memory _operatorStakeUpdate; // add the `updateBlockNumber` info _operatorStakeUpdate.updateBlockNumber = uint32(block.number); @@ -428,7 +347,7 @@ contract StakeRegistry is StakeRegistryStorage { // add the `updateBlockNumber` info _newTotalStakeUpdate.updateBlockNumber = uint32(block.number); // loop through the operator's quorums and remove the operator's stake for each quorum - for (uint8 quorumNumbersIndex = 0; quorumNumbersIndex < quorumNumbersLength;) { + for (uint8 quorumNumbersIndex = 0; quorumNumbersIndex < quorumNumbers.length;) { uint8 quorumNumber = uint8(quorumNumbers[quorumNumbersIndex]); // update the operator's stake uint96 stakeBeforeUpdate = _recordOperatorStakeUpdate(operatorId, quorumNumber, _operatorStakeUpdate); @@ -465,6 +384,7 @@ contract StakeRegistry is StakeRegistryStorage { // check if minimum requirements have been met if (operatorStakeUpdate.stake < minimumStakeForQuorum[quorumNumber]) { + // set staker to 0 operatorStakeUpdate.stake = uint96(0); } // get stakeBeforeUpdate and update with new stake