@@ -5,13 +5,10 @@ import "@openzeppelin-upgrades/contracts/proxy/utils/Initializable.sol";
5
5
import "@openzeppelin/contracts/utils/Strings.sol " ;
6
6
import "../mixins/PermissionControllerMixin.sol " ;
7
7
import "../mixins/SemVerMixin.sol " ;
8
- import "../libraries/Snapshots.sol " ;
9
8
import "./ReleaseManagerStorage.sol " ;
10
9
11
10
contract ReleaseManager is Initializable , ReleaseManagerStorage , PermissionControllerMixin , SemVerMixin {
12
- using Snapshots for Snapshots.DefaultZeroHistory;
13
11
using EnumerableSet for EnumerableSet.Bytes32Set;
14
- using EnumerableMap for EnumerableMap.Bytes32ToUintMap;
15
12
using OperatorSetLib for OperatorSet;
16
13
using Strings for uint16 ;
17
14
@@ -37,180 +34,156 @@ contract ReleaseManager is Initializable, ReleaseManagerStorage, PermissionContr
37
34
* EXTERNAL FUNCTIONS
38
35
*
39
36
*/
40
-
41
- /// @inheritdoc IReleaseManager
42
37
function publishRelease (
43
38
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;
61
72
}
62
73
63
- /// @inheritdoc IReleaseManager
64
74
function deprecateRelease (
65
75
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);
79
92
}
80
93
81
94
/**
82
95
*
83
96
* INTERNAL FUNCTIONS
84
97
*
85
98
*/
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));
103
103
}
104
104
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
+ });
120
113
}
121
114
122
115
/**
123
116
*
124
117
* VIEW FUNCTIONS
125
118
*
126
119
*/
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 (
145
121
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 ();
148
124
}
149
125
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));
166
128
}
167
129
168
- /// @inheritdoc IReleaseManager
169
- function getReleaseAtTime (
130
+ function getRelease (
170
131
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)];
180
135
}
181
136
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));
186
143
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 ;
189
146
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);
192
150
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);
195
154
196
- return true ;
155
+ // Otherwise, the version is live.
156
+ return (ReleaseStatus.LIVE);
197
157
}
198
158
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 ));
205
164
}
206
165
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});
215
188
}
216
189
}
0 commit comments