Skip to content

Commit 5e25244

Browse files
committed
fix: releaseManager audit fixes (#1608)
**Motivation:** Certora ReleaseManager audit fixes for Hourglass Part 1 and Part 2. **Modifications:** * `I-01. isValidRelease() and getLatestUpgradeByTime() may panic when no releases exist` : Added `NoReleases()` custom error to those 2 functions in the case of no error. * `I-04. Unused imports can be removed`: Removed unused imports * Support for signalling instant upgrades by setting `upgradeByTime` to `0`. * Updated unit tests * Updated docs * Updated bindings **Result:** Bug free code.
1 parent 2cae40e commit 5e25244

File tree

6 files changed

+69
-19
lines changed

6 files changed

+69
-19
lines changed

docs/core/ReleaseManager.md

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ An AVS in the context of `ReleaseManager` is defined as the `address` of the con
3131

3232
* **Latest Release Validity**: Only the latest release for an operator set is considered valid. Previous releases become obsolete as soon as a new release is published.
3333
* **Upgrade Deadlines**: The `upgradeByTime` timestamp (in Unix time) is a suggested deadline and is not enforced on-chain or off-chain. It serves as a communication mechanism for AVSs to indicate when operators should complete their upgrades.
34+
* **Instant Upgrades**: When `upgradeByTime` is set to 0, this signals an instant upgrade requirement.
3435
* **Multiple Releases in Same Block**: If multiple releases are published in the same block with the same `upgradeByTime`, the last transaction processed in that block will determine the latest valid release.
3536

3637
---
@@ -58,7 +59,8 @@ struct Artifact {
5859
/**
5960
* @notice Represents a release containing multiple artifacts and an upgrade deadline.
6061
* @param artifacts Array of artifacts included in this release.
61-
* @param upgradeByTime Timestamp by which operators must upgrade to this release.
62+
* @param upgradeByTime Timestamp by which operators must upgrade to this release.
63+
* A value of 0 signals an instant upgrade requirement.
6264
*/
6365
struct Release {
6466
Artifact[] artifacts;
@@ -90,6 +92,7 @@ mapping(bytes32 operatorSetKey => Release[]) internal _operatorSetReleases;
9092
```solidity
9193
/**
9294
* @notice Publishes a new release for an operator set.
95+
* @dev If the upgradeByTime is 0, the release is meant to signal an instant upgrade.
9396
* @param operatorSet The operator set this release is for.
9497
* @param release The release that was published.
9598
* @return releaseId The index of the newly published release.
@@ -107,6 +110,8 @@ _Note: this method can be called directly by an AVS, or by a caller authorized b
107110

108111
AVSs use this method to publish new software releases for their operator sets. Each release contains one or more artifacts that represent the software components operators must run (e.g., validator clients, network monitors, etc.). The AVS specifies a deadline (`upgradeByTime`) by which all operators in the operator set must upgrade to the new release.
109112

113+
**Special Case - Instant Upgrades**: Setting `upgradeByTime` to 0 signals that this is an instant upgrade that operators should apply immediately. This is typically used for critical security patches or emergency updates.
114+
110115
The `releaseId` returned is the zero-based index of the release in the operator set's release array. This ID can be used to query the release later using [`getRelease`](#getrelease).
111116

112117
*Effects*:
@@ -117,7 +122,8 @@ The `releaseId` returned is the zero-based index of the release in the operator
117122

118123
*Requirements*:
119124
* Caller MUST be authorized, either as the AVS itself or an admin/appointee (see [`PermissionController.md`](../permissions/PermissionController.md))
120-
* `release.upgradeByTime` MUST be greater than or equal to the current block timestamp
125+
* Operator set MUST have published metadata URI via `updateOperatorSetMetadataURI`
126+
* `release.upgradeByTime` MUST be either 0 (instant upgrade) or greater than or equal to the current block timestamp
121127
---
122128

123129
### View Functions
@@ -149,6 +155,7 @@ Returns the total number of releases that have been published for the specified
149155
```solidity
150156
/**
151157
* @notice Returns a specific release by index.
158+
* @dev If the upgradeByTime is 0, the release is meant to signal an instant upgrade.
152159
* @param operatorSet The operator set to query.
153160
* @param releaseId The id of the release to get.
154161
* @return The release at the specified index.
@@ -166,13 +173,15 @@ Retrieves a specific release by its ID for a given operator set. The `releaseId`
166173

167174
*Returns*:
168175
* The complete `Release` struct including all artifacts and the upgrade deadline
176+
* If `upgradeByTime` is 0, this indicates an instant upgrade requirement
169177
* Reverts if `releaseId` is out of bounds
170178

171179
#### `getLatestRelease`
172180

173181
```solidity
174182
/**
175183
* @notice Returns the latest release for an operator set.
184+
* @dev If the upgradeByTime is 0, the release is meant to signal an instant upgrade.
176185
* @param operatorSet The operator set to query.
177186
* @return The id of the latest release.
178187
* @return The latest release.
@@ -188,14 +197,16 @@ function getLatestRelease(
188197
Retrieves the most recently published release for an operator set. This is typically the release that operators should be running or upgrading to.
189198

190199
*Returns*:
191-
* The latest `Release` struct from the operator set's release array
192-
* Reverts if no releases have been published for the operator set
200+
* The release ID and the latest `Release` struct from the operator set's release array
201+
* If `upgradeByTime` is 0, this indicates an instant upgrade requirement
202+
* Reverts with `NoReleases()` if no releases have been published for the operator set
193203

194204
#### `getLatestUpgradeByTime`
195205

196206
```solidity
197207
/**
198208
* @notice Returns the upgrade by time for the latest release.
209+
* @dev If the upgradeByTime is 0, the release is meant to signal an instant upgrade.
199210
* @param operatorSet The operator set to query.
200211
* @return The upgrade by time for the latest release.
201212
*/
@@ -204,14 +215,15 @@ function getLatestUpgradeByTime(
204215
)
205216
external
206217
view
207-
returns (uint256)
218+
returns (uint32)
208219
```
209220

210221
A convenience function that returns just the upgrade deadline from the latest release. This can be useful for quickly checking when operators must complete their upgrades.
211222

212223
*Returns*:
213224
* The `upgradeByTime` timestamp from the latest release
214-
* Reverts if no releases have been published for the operator set
225+
* A value of 0 indicates an instant upgrade requirement
226+
* Reverts with `NoReleases()` if no releases have been published for the operator set
215227

216228
#### `isValidRelease`
217229

@@ -238,6 +250,17 @@ Checks whether a given release ID corresponds to the latest release for an opera
238250
*Returns*:
239251
* `true` if the `releaseId` matches the latest release index
240252
* `false` if the `releaseId` refers to an older release
241-
* Reverts if the operator set has no releases
253+
* Reverts with `NoReleases()` if the operator set has no releases
254+
255+
---
256+
257+
## Error Definitions
258+
259+
The `ReleaseManager` defines the following custom errors:
260+
261+
* `MustPublishMetadataURI()`: Thrown when attempting to publish a release for an operator set that hasn't published its metadata URI via `updateOperatorSetMetadataURI`.
262+
* `InvalidUpgradeByTime()`: Thrown when the `upgradeByTime` is in the past (not including 0, which is valid for instant upgrades).
263+
* `InvalidMetadataURI()`: Thrown when the metadata URI is empty.
264+
* `NoReleases()`: Thrown when querying release information for an operator set that has no published releases.
242265

243266
---

0 commit comments

Comments
 (0)