Skip to content

Commit e75fb26

Browse files
committed
wip
1 parent 42beb45 commit e75fb26

File tree

3 files changed

+161
-255
lines changed

3 files changed

+161
-255
lines changed

src/contracts/core/ReleaseManager.sol

Lines changed: 113 additions & 140 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,10 @@ import "@openzeppelin-upgrades/contracts/proxy/utils/Initializable.sol";
55
import "@openzeppelin/contracts/utils/Strings.sol";
66
import "../mixins/PermissionControllerMixin.sol";
77
import "../mixins/SemVerMixin.sol";
8-
import "../libraries/Snapshots.sol";
98
import "./ReleaseManagerStorage.sol";
109

1110
contract ReleaseManager is Initializable, ReleaseManagerStorage, PermissionControllerMixin, SemVerMixin {
12-
using Snapshots for Snapshots.DefaultZeroHistory;
1311
using EnumerableSet for EnumerableSet.Bytes32Set;
14-
using EnumerableMap for EnumerableMap.Bytes32ToUintMap;
1512
using OperatorSetLib for OperatorSet;
1613
using Strings for uint16;
1714

@@ -37,180 +34,156 @@ contract ReleaseManager is Initializable, ReleaseManagerStorage, PermissionContr
3734
* EXTERNAL FUNCTIONS
3835
*
3936
*/
40-
41-
/// @inheritdoc IReleaseManager
4237
function publishRelease(
4338
OperatorSet calldata operatorSet,
44-
bytes32 releaseDigest,
45-
string calldata registryUrl,
46-
Version calldata version
47-
) external checkCanCall(operatorSet.avs) {
48-
// Parse the next releaseId (equal to the total number of releases).
49-
uint256 releaseId = getTotalOperatorSetReleases(operatorSet);
50-
51-
// Push the release digest and set the version.
52-
_setReleaseInfo(operatorSet, releaseDigest, version, uint32(0));
53-
54-
// Push the release snapshot.
55-
_releaseSnapshots[operatorSet.key()].push(uint32(block.timestamp), releaseId);
56-
57-
// Set the release registry URL for the release digest.
58-
_releaseRegistryUrls[operatorSet.key()][releaseDigest] = registryUrl;
59-
60-
emit ReleasePublished(operatorSet, releaseDigest, registryUrl, version);
39+
Artifacts[] calldata artifacts,
40+
uint32 upgradeWindow,
41+
ReleaseType releaseType
42+
) external checkCanCall(operatorSet.avs) returns (Version memory) {
43+
Version memory version = getLatestVersion(operatorSet);
44+
45+
uint32 upgradeByTime = uint32(block.timestamp + upgradeWindow);
46+
47+
if (releaseType == ReleaseType.MAJOR) {
48+
++version.major;
49+
version.minor = 0;
50+
version.patch = 0;
51+
_upgradeByTimes[operatorSet.key()][version.major] = upgradeByTime;
52+
} else if (releaseType == ReleaseType.MINOR) {
53+
++version.minor;
54+
version.patch = 0;
55+
} else if (releaseType == ReleaseType.PATCH) {
56+
++version.patch;
57+
}
58+
59+
bytes32 versionKey = _encodeVersion(version);
60+
61+
// Append the version to the operator set's version history.
62+
_versions[operatorSet.key()].add(versionKey);
63+
// Map the version to the release artifacts and deprecation time.
64+
Release storage release = _releases[operatorSet.key()][versionKey];
65+
for (uint256 i = 0; i < artifacts.length; i++) {
66+
release.artifacts.push(artifacts[i]);
67+
}
68+
69+
emit ReleasePublished(operatorSet.key(), versionKey, releaseType, upgradeByTime, artifacts);
70+
71+
return version;
6172
}
6273

63-
/// @inheritdoc IReleaseManager
6474
function deprecateRelease(
6575
OperatorSet calldata operatorSet,
66-
bytes32 releaseDigest,
67-
uint32 deprecationTimestamp
68-
) external checkCanCall(operatorSet.avs) {
69-
// Get the deprecation timestamp and version for the provided digest.
70-
(uint32 currentDeprecationTimestamp, Version memory version) = _getReleaseInfo(operatorSet, releaseDigest);
71-
72-
// Assert that the release is not already deprecated.
73-
require(currentDeprecationTimestamp != uint32(0), ReleaseAlreadyDeprecated());
74-
75-
// Set the deprecation timestamp for the release digest.
76-
_setReleaseInfo(operatorSet, releaseDigest, version, uint32(deprecationTimestamp));
77-
78-
emit DeprecationScheduled(operatorSet, releaseDigest, deprecationTimestamp);
76+
Version calldata version,
77+
uint32 deprecationDelay
78+
) public checkCanCall(operatorSet.avs) {
79+
bytes32 versionKey = _encodeVersion(version);
80+
81+
// Check that the release is not already deprecated and modify state.
82+
Release storage release = _releases[operatorSet.key()][versionKey];
83+
require(release.deprecateAtTime == 0, ReleaseAlreadyDeprecated());
84+
uint32 deprecateAtTime = uint32(block.timestamp + deprecationDelay);
85+
release.deprecateAtTime = deprecateAtTime;
86+
87+
// Checked that there is at least one stable version after deprecating this release.
88+
Version memory lastStableVersion = getLatestStableVersion(operatorSet);
89+
require(lastStableVersion.major != type(uint16).max, MustHaveAtLeastOneStableVersion());
90+
91+
emit ReleaseDeprecated(operatorSet.key(), versionKey, deprecateAtTime);
7992
}
8093

8194
/**
8295
*
8396
* INTERNAL FUNCTIONS
8497
*
8598
*/
86-
87-
/// @dev Returns the deprecation timestamp and version for a release digest.
88-
function _getReleaseInfo(
89-
OperatorSet memory operatorSet,
90-
bytes32 releaseDigest
91-
) internal view returns (uint32, Version memory) {
92-
uint256 encoded = _releaseDigests[operatorSet.key()].get(releaseDigest);
93-
94-
uint32 deprecationTimestamp = uint32(encoded >> 224);
95-
96-
Version memory version = Version({
97-
major: uint16((encoded >> 208) & type(uint16).max),
98-
minor: uint16((encoded >> 192) & type(uint16).max),
99-
patch: uint16((encoded >> 176) & type(uint16).max)
100-
});
101-
102-
return (deprecationTimestamp, version);
99+
function _encodeVersion(
100+
Version memory version
101+
) internal pure returns (bytes32) {
102+
return bytes32(abi.encodePacked(version.major, version.minor, version.patch));
103103
}
104104

105-
/// @dev Sets the release info for a release digest.
106-
function _setReleaseInfo(
107-
OperatorSet memory operatorSet,
108-
bytes32 releaseDigest,
109-
Version memory version,
110-
uint32 deprecationTimestamp
111-
) internal {
112-
// Push the release digest and set the version.
113-
require(
114-
_releaseDigests[operatorSet.key()].set(
115-
releaseDigest,
116-
uint256(bytes32(abi.encodePacked(deprecationTimestamp, version.major, version.minor, version.patch)))
117-
),
118-
ReleaseAlreadyExists()
119-
);
105+
function _decodeVersion(
106+
bytes32 encoded
107+
) internal pure returns (Version memory) {
108+
return Version({
109+
major: uint16((uint256(encoded) >> 208) & type(uint16).max),
110+
minor: uint16((uint256(encoded) >> 192) & type(uint16).max),
111+
patch: uint16((uint256(encoded) >> 176) & type(uint16).max)
112+
});
120113
}
121114

122115
/**
123116
*
124117
* VIEW FUNCTIONS
125118
*
126119
*/
127-
128-
/// @inheritdoc IReleaseManager
129-
function isOperatorSetRelease(OperatorSet memory operatorSet, bytes32 releaseDigest) external view returns (bool) {
130-
return _releaseDigests[operatorSet.key()].contains(releaseDigest);
131-
}
132-
133-
/// @inheritdoc IReleaseManager
134-
function getOperatorSetReleases(
135-
OperatorSet memory operatorSet,
136-
uint160 releaseId
137-
) external view returns (bytes32) {
138-
(bytes32 releaseDigest,) = _releaseDigests[operatorSet.key()].at(releaseId);
139-
140-
return releaseDigest;
141-
}
142-
143-
/// @inheritdoc IReleaseManager
144-
function getOperatorSetReleases(
120+
function getTotalReleaseCount(
145121
OperatorSet memory operatorSet
146-
) external view returns (bytes32[] memory) {
147-
return _releaseDigests[operatorSet.key()].keys();
122+
) external view returns (uint256) {
123+
return _versions[operatorSet.key()].length();
148124
}
149125

150-
/// @inheritdoc IReleaseManager
151-
function getTotalOperatorSetReleases(
152-
OperatorSet memory operatorSet
153-
) public view returns (uint256) {
154-
return _releaseDigests[operatorSet.key()].length();
155-
}
156-
157-
/// @inheritdoc IReleaseManager
158-
function getLastOperatorSetRelease(
159-
OperatorSet memory operatorSet
160-
) public view returns (bytes32) {
161-
uint256 lastReleaseId = getTotalOperatorSetReleases(operatorSet) - 1;
162-
163-
(bytes32 releaseDigest,) = _releaseDigests[operatorSet.key()].at(lastReleaseId);
164-
165-
return releaseDigest;
126+
function getVersion(OperatorSet memory operatorSet, uint256 index) external view returns (Version memory) {
127+
return _decodeVersion(_versions[operatorSet.key()].at(index));
166128
}
167129

168-
/// @inheritdoc IReleaseManager
169-
function getReleaseAtTime(
130+
function getRelease(
170131
OperatorSet memory operatorSet,
171-
uint32 previousTimestamp
172-
) external view returns (bytes32) {
173-
// Get the most recent snapshot that was published at or before the provided timestamp.
174-
uint256 releaseId = _releaseSnapshots[operatorSet.key()].upperLookup(previousTimestamp);
175-
176-
// Return the release releaseDigest for the `releaseId`, revert if nonexistent.
177-
(bytes32 releaseDigest,) = _releaseDigests[operatorSet.key()].at(releaseId);
178-
179-
return releaseDigest;
132+
Version memory version
133+
) external view returns (Release memory) {
134+
return _releases[operatorSet.key()][_encodeVersion(version)];
180135
}
181136

182-
/// @inheritdoc IReleaseManager
183-
function isReleaseDeprecated(OperatorSet memory operatorSet, bytes32 releaseDigest) external view returns (bool) {
184-
// Get the deprecation timestamp and version for the provided digest.
185-
(uint32 deprecationTimestamp, Version memory version) = _getReleaseInfo(operatorSet, releaseDigest);
137+
function getReleaseStatus(
138+
OperatorSet memory operatorSet,
139+
Version memory version
140+
) external view returns (ReleaseStatus) {
141+
// First, check whether the version exists.
142+
bool exists = _versions[operatorSet.key()].contains(_encodeVersion(version));
186143

187-
// Get the the current major version for the operator set.
188-
(, Version memory currentVersion) = _getReleaseInfo(operatorSet, getLastOperatorSetRelease(operatorSet));
144+
// If the version does not exist, it is not valid.
145+
if (!exists) return ReleaseStatus.NONEXISTENT;
189146

190-
// If the deprecation timestamp is in the future, the release is not deprecated.
191-
if (deprecationTimestamp > block.timestamp) return false;
147+
// Second, check whether the version is deprecated by a force deprecation.
148+
uint32 deprecateAtTime = _releases[operatorSet.key()][_encodeVersion(version)].deprecateAtTime;
149+
if (deprecateAtTime != 0 && block.timestamp >= deprecateAtTime) return (ReleaseStatus.DEPRECATED);
192150

193-
// If the major version is the same as the current major version, the release is not deprecated.
194-
if (version.major == currentVersion.major) return false;
151+
// Third, check whether the version is deprecated by a major version upgrade.
152+
uint32 lastUpgradeByTime = _upgradeByTimes[operatorSet.key()][getLatestStableVersion(operatorSet).major];
153+
if (lastUpgradeByTime != 0 && block.timestamp >= lastUpgradeByTime) return (ReleaseStatus.OUTDATED);
195154

196-
return true;
155+
// Otherwise, the version is live.
156+
return (ReleaseStatus.LIVE);
197157
}
198158

199-
/// @inheritdoc IReleaseManager
200-
function getReleaseRegistryUrl(
201-
OperatorSet memory operatorSet,
202-
bytes32 releaseDigest
203-
) external view returns (string memory) {
204-
return _releaseRegistryUrls[operatorSet.key()][releaseDigest];
159+
function getLatestVersion(
160+
OperatorSet memory operatorSet
161+
) public view returns (Version memory) {
162+
EnumerableSet.Bytes32Set storage versions = _versions[operatorSet.key()];
163+
return _decodeVersion(versions.at(versions.length() - 1));
205164
}
206165

207-
/// @inheritdoc IReleaseManager
208-
function getReleaseVersion(
209-
OperatorSet memory operatorSet,
210-
bytes32 releaseDigest
211-
) external view returns (string memory) {
212-
(, Version memory version) = _getReleaseInfo(operatorSet, releaseDigest);
213-
214-
return string.concat(version.major.toString(), ".", version.minor.toString(), ".", version.patch.toString());
166+
function getLatestStableVersion(
167+
OperatorSet memory operatorSet
168+
) public view returns (Version memory) {
169+
EnumerableSet.Bytes32Set storage versions = _versions[operatorSet.key()];
170+
uint256 versionCount = versions.length();
171+
172+
// Linear search backwards for the latest stable version.
173+
for (uint256 i = versionCount - 1; i >= 0; i--) {
174+
bytes32 versionKey = versions.at(i);
175+
uint32 deprecateAtTime = _releases[operatorSet.key()][versionKey].deprecateAtTime;
176+
177+
// If the release is deprecated, skip it.
178+
if (block.timestamp >= deprecateAtTime) {
179+
continue;
180+
}
181+
182+
// Othersise, return the release version.
183+
return _decodeVersion(versionKey);
184+
}
185+
186+
// No version has been published.
187+
return Version({major: type(uint16).max, minor: type(uint16).max, patch: type(uint16).max});
215188
}
216189
}
Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
// SPDX-License-Identifier: BUSL-1.1
22
pragma solidity ^0.8.27;
33

4-
import "@openzeppelin/contracts/utils/structs/EnumerableMap.sol";
5-
import "../libraries/Snapshots.sol";
4+
import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
65
import "../interfaces/IReleaseManager.sol";
76
import "../interfaces/IAllocationManager.sol";
87

@@ -14,23 +13,17 @@ abstract contract ReleaseManagerStorage is IReleaseManager {
1413

1514
// Mutables
1615

17-
/// @notice A set of all release digests for an operator set.
18-
/// @dev operatorSet, releaseId, releaseDigest => (uint32(deprecationTimestamp), version))
19-
mapping(bytes32 operatorSetKey => EnumerableMap.Bytes32ToUintMap releaseDigests) internal _releaseDigests;
16+
mapping(bytes32 operatorSetKey => EnumerableSet.Bytes32Set versions) internal _versions;
2017

21-
/// @notice The deployment deadline for a release digest.
22-
/// @dev operatorSet => (uint224(releaseId))
23-
mapping(bytes32 operatorSetKey => Snapshots.DefaultZeroHistory) internal _releaseSnapshots;
18+
mapping(bytes32 operatorSetKey => mapping(bytes32 versionKey => Release release)) internal _releases;
2419

25-
/// @notice The registry URL for a release digest.
26-
mapping(bytes32 operatorSetKey => mapping(bytes32 releaseDigest => string registryUrl)) internal
27-
_releaseRegistryUrls;
20+
mapping(bytes32 operatorSetKey => mapping(uint16 major => uint32 upgradeByTime)) internal _upgradeByTimes;
2821

2922
constructor(
3023
IAllocationManager _allocationManager
3124
) {
3225
allocationManager = _allocationManager;
3326
}
3427

35-
uint256[45] private __gap;
28+
uint256[48] private __gap;
3629
}

0 commit comments

Comments
 (0)