From 6310f6ec28369621c922777b1eba2442bbde1ef8 Mon Sep 17 00:00:00 2001 From: quaq <56312047+0x0aa0@users.noreply.github.com> Date: Wed, 4 Oct 2023 22:13:56 +0200 Subject: [PATCH] Add upgradability to IndexRegistry and PubkeyRegistry (#216) * init * fix storage gap --- .../middleware/BLSPubkeyRegistry.sol | 29 +++++---------- .../middleware/BLSPubkeyRegistryStorage.sol | 32 +++++++++++++++++ src/contracts/middleware/IndexRegistry.sol | 25 +++---------- .../middleware/IndexRegistryStorage.sol | 35 +++++++++++++++++++ .../middleware/StakeRegistryStorage.sol | 2 +- src/contracts/middleware/VoteWeigherBase.sol | 6 +--- .../middleware/VoteWeigherBaseStorage.sol | 3 +- 7 files changed, 83 insertions(+), 49 deletions(-) create mode 100644 src/contracts/middleware/BLSPubkeyRegistryStorage.sol create mode 100644 src/contracts/middleware/IndexRegistryStorage.sol diff --git a/src/contracts/middleware/BLSPubkeyRegistry.sol b/src/contracts/middleware/BLSPubkeyRegistry.sol index 01b588c54..e7a685e5c 100644 --- a/src/contracts/middleware/BLSPubkeyRegistry.sol +++ b/src/contracts/middleware/BLSPubkeyRegistry.sol @@ -1,27 +1,13 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity =0.8.12; -import "../interfaces/IBLSPubkeyRegistry.sol"; -import "../interfaces/IRegistryCoordinator.sol"; -import "../interfaces/IBLSPublicKeyCompendium.sol"; - +import "./BLSPubkeyRegistryStorage.sol"; import "../libraries/BN254.sol"; -contract BLSPubkeyRegistry is IBLSPubkeyRegistry { +contract BLSPubkeyRegistry is BLSPubkeyRegistryStorage { using BN254 for BN254.G1Point; - /// @notice the hash of the zero pubkey aka BN254.G1Point(0,0) - bytes32 internal constant ZERO_PK_HASH = hex"ad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5"; - /// @notice the registry coordinator contract - IRegistryCoordinator public immutable registryCoordinator; - /// @notice the BLSPublicKeyCompendium contract against which pubkey ownership is checked - IBLSPublicKeyCompendium public immutable pubkeyCompendium; - - // mapping of quorumNumber => ApkUpdate[], tracking the aggregate pubkey updates of every quorum - mapping(uint8 => ApkUpdate[]) public quorumApkUpdates; - // mapping of quorumNumber => current aggregate pubkey of quorum - mapping(uint8 => BN254.G1Point) private quorumApk; - + /// @notice when applied to a function, only allows the RegistryCoordinator to call it modifier onlyRegistryCoordinator() { require( msg.sender == address(registryCoordinator), @@ -30,10 +16,11 @@ contract BLSPubkeyRegistry is IBLSPubkeyRegistry { _; } - constructor(IRegistryCoordinator _registryCoordinator, IBLSPublicKeyCompendium _pubkeyCompendium) { - registryCoordinator = _registryCoordinator; - pubkeyCompendium = _pubkeyCompendium; - } + /// @notice Sets the (immutable) `registryCoordinator` and `pubkeyCompendium` addresses + constructor( + IRegistryCoordinator _registryCoordinator, + IBLSPublicKeyCompendium _pubkeyCompendium + ) BLSPubkeyRegistryStorage(_registryCoordinator, _pubkeyCompendium) {} /** * @notice Registers the `operator`'s pubkey for the specified `quorumNumbers`. diff --git a/src/contracts/middleware/BLSPubkeyRegistryStorage.sol b/src/contracts/middleware/BLSPubkeyRegistryStorage.sol new file mode 100644 index 000000000..0254d8105 --- /dev/null +++ b/src/contracts/middleware/BLSPubkeyRegistryStorage.sol @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity =0.8.12; + +import "../interfaces/IBLSPubkeyRegistry.sol"; +import "../interfaces/IRegistryCoordinator.sol"; +import "../interfaces/IBLSPublicKeyCompendium.sol"; + +import "@openzeppelin-upgrades/contracts/proxy/utils/Initializable.sol"; + +abstract contract BLSPubkeyRegistryStorage is Initializable, IBLSPubkeyRegistry { + /// @notice the hash of the zero pubkey aka BN254.G1Point(0,0) + bytes32 internal constant ZERO_PK_HASH = hex"ad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5"; + /// @notice the registry coordinator contract + IRegistryCoordinator public immutable registryCoordinator; + /// @notice the BLSPublicKeyCompendium contract against which pubkey ownership is checked + IBLSPublicKeyCompendium public immutable pubkeyCompendium; + + /// @notice mapping of quorumNumber => ApkUpdate[], tracking the aggregate pubkey updates of every quorum + mapping(uint8 => ApkUpdate[]) public quorumApkUpdates; + /// @notice mapping of quorumNumber => current aggregate pubkey of quorum + mapping(uint8 => BN254.G1Point) public quorumApk; + + constructor(IRegistryCoordinator _registryCoordinator, IBLSPublicKeyCompendium _pubkeyCompendium) { + registryCoordinator = _registryCoordinator; + pubkeyCompendium = _pubkeyCompendium; + // disable initializers so that the implementation contract cannot be initialized + _disableInitializers(); + } + + // storage gap for upgradeability + uint256[48] private __GAP; +} diff --git a/src/contracts/middleware/IndexRegistry.sol b/src/contracts/middleware/IndexRegistry.sol index e0fb104b6..ceb9bda10 100644 --- a/src/contracts/middleware/IndexRegistry.sol +++ b/src/contracts/middleware/IndexRegistry.sol @@ -1,36 +1,21 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity =0.8.12; - -import "../interfaces/IIndexRegistry.sol"; -import "../interfaces/IRegistryCoordinator.sol"; +import "./IndexRegistryStorage.sol"; import "../libraries/BN254.sol"; -contract IndexRegistry is IIndexRegistry { - - /// @notice The value that indices of deregistered operators are set to - uint32 public constant OPERATOR_DEREGISTERED_INDEX = type(uint32).max; - - IRegistryCoordinator public immutable registryCoordinator; - - // list of all operators ever registered, may include duplicates. used to avoid running an indexer on nodes - bytes32[] public globalOperatorList; - - // mapping of operatorId => quorumNumber => index history of that operator - mapping(bytes32 => mapping(uint8 => OperatorIndexUpdate[])) internal _operatorIdToIndexHistory; - // mapping of quorumNumber => history of numbers of unique registered operators - mapping(uint8 => OperatorIndexUpdate[]) internal _totalOperatorsHistory; +contract IndexRegistry is IndexRegistryStorage { + /// @notice when applied to a function, only allows the RegistryCoordinator to call it modifier onlyRegistryCoordinator() { require(msg.sender == address(registryCoordinator), "IndexRegistry.onlyRegistryCoordinator: caller is not the registry coordinator"); _; } + /// @notice sets the (immutable) `registryCoordinator` address constructor( IRegistryCoordinator _registryCoordinator - ){ - registryCoordinator = _registryCoordinator; - } + ) IndexRegistryStorage(_registryCoordinator) {} /** * @notice Registers the operator with the specified `operatorId` for the quorums specified by `quorumNumbers`. diff --git a/src/contracts/middleware/IndexRegistryStorage.sol b/src/contracts/middleware/IndexRegistryStorage.sol new file mode 100644 index 000000000..48b17ab69 --- /dev/null +++ b/src/contracts/middleware/IndexRegistryStorage.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity =0.8.12; + +import "../interfaces/IIndexRegistry.sol"; +import "../interfaces/IRegistryCoordinator.sol"; + +import "@openzeppelin-upgrades/contracts/proxy/utils/Initializable.sol"; + +abstract contract IndexRegistryStorage is Initializable, IIndexRegistry { + + /// @notice The value that indices of deregistered operators are set to + uint32 public constant OPERATOR_DEREGISTERED_INDEX = type(uint32).max; + + /// @notice The RegistryCoordinator contract for this middleware + IRegistryCoordinator public immutable registryCoordinator; + + /// @notice list of all operators ever registered, may include duplicates. used to avoid running an indexer on nodes + bytes32[] public globalOperatorList; + + /// @notice mapping of operatorId => quorumNumber => index history of that operator + mapping(bytes32 => mapping(uint8 => OperatorIndexUpdate[])) internal _operatorIdToIndexHistory; + /// @notice mapping of quorumNumber => history of numbers of unique registered operators + mapping(uint8 => OperatorIndexUpdate[]) internal _totalOperatorsHistory; + + constructor( + IRegistryCoordinator _registryCoordinator + ){ + registryCoordinator = _registryCoordinator; + // disable initializers so that the implementation contract cannot be initialized + _disableInitializers(); + } + + // storage gap for upgradeability + uint256[47] private __GAP; +} diff --git a/src/contracts/middleware/StakeRegistryStorage.sol b/src/contracts/middleware/StakeRegistryStorage.sol index f95037683..2e83f9a99 100644 --- a/src/contracts/middleware/StakeRegistryStorage.sol +++ b/src/contracts/middleware/StakeRegistryStorage.sol @@ -36,5 +36,5 @@ abstract contract StakeRegistryStorage is VoteWeigherBase, IStakeRegistry { } // storage gap for upgradeability - uint256[63] private __GAP; + uint256[65] private __GAP; } \ No newline at end of file diff --git a/src/contracts/middleware/VoteWeigherBase.sol b/src/contracts/middleware/VoteWeigherBase.sol index fc9904584..7dc902c1a 100644 --- a/src/contracts/middleware/VoteWeigherBase.sol +++ b/src/contracts/middleware/VoteWeigherBase.sol @@ -33,11 +33,7 @@ contract VoteWeigherBase is VoteWeigherBaseStorage { constructor( IStrategyManager _strategyManager, IServiceManager _serviceManager - ) VoteWeigherBaseStorage(_strategyManager, _serviceManager) - // solhint-disable-next-line no-empty-blocks - { - - } + ) VoteWeigherBaseStorage(_strategyManager, _serviceManager) {} /// @notice Returns the strategy and weight multiplier for the `index`'th strategy in the quorum `quorumNumber` function strategyAndWeightingMultiplierForQuorumByIndex(uint8 quorumNumber, uint256 index) diff --git a/src/contracts/middleware/VoteWeigherBaseStorage.sol b/src/contracts/middleware/VoteWeigherBaseStorage.sol index 2150d462d..7935e567d 100644 --- a/src/contracts/middleware/VoteWeigherBaseStorage.sol +++ b/src/contracts/middleware/VoteWeigherBaseStorage.sol @@ -53,7 +53,6 @@ abstract contract VoteWeigherBaseStorage is Initializable, IVoteWeigher { IStrategyManager _strategyManager, IServiceManager _serviceManager ) { - // sanity check that the VoteWeigher is being initialized with at least 1 quorum strategyManager = _strategyManager; delegation = _strategyManager.delegation(); slasher = _strategyManager.slasher(); @@ -63,5 +62,5 @@ abstract contract VoteWeigherBaseStorage is Initializable, IVoteWeigher { } // storage gap for upgradeability - uint256[47] private __GAP; + uint256[48] private __GAP; }