@@ -8,15 +8,11 @@ pragma solidity ^0.8.18;
8
8
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol " ;
9
9
10
10
/// @title The Vote struct that defines a vote in the governance mechanism
11
- /// @param nonce nonce of the proposal
12
- /// @param leafIndex leafIndex of the proposer in the proposer set Merkle tree
13
- /// @param siblingPathNodes Merkle proof path of sibling nodes
11
+ /// @param jobId JobId of the proposaed governor.
14
12
/// @param proposedGovernor the governor that the voter wants to force reset to
15
13
struct Vote {
16
- uint32 nonce;
17
- uint32 leafIndex;
14
+ uint32 jobId;
18
15
address proposedGovernor;
19
- bytes32 [] siblingPathNodes;
20
16
}
21
17
22
18
/// @title The Governable contract that defines the governance mechanism
@@ -25,26 +21,14 @@ struct Vote {
25
21
contract Governable {
26
22
address public governor;
27
23
28
- /// Refresh nonce is for rotating the DKG
29
- uint32 public refreshNonce = 0 ;
24
+ /// Job Id of the rotating the DKG
25
+ uint32 public jobId = 0 ;
30
26
31
27
/// Last time ownership was transferred to a new governor
32
28
uint256 public lastGovernorUpdateTime;
33
29
34
- /// The root of the proposer set Merkle tree
35
- bytes32 public voterMerkleRoot;
36
-
37
- /// The average session length in millisecs
38
- /// Note: This default is set to the max value of a uint64 so that there
39
- /// is no chance of a new governor being voted for before the governance has successfully
40
- /// been transferred. In this first transferral, the actual session length will be set.
41
- uint64 public averageSessionLengthInMillisecs = 2 ** 64 - 1 ;
42
-
43
- /// The session length multiplier (see the voteInFavorForceSetGovernor function below)
44
- uint256 public sessionLengthMultiplier = 2 ;
45
-
46
- /// The number of proposers
47
- uint32 public voterCount;
30
+ /// Threshold for the number of votes required to force set the governor.
31
+ uint32 public votingThreshold = 1 ;
48
32
49
33
/// (votingPeriod/refreshNonce => (proposer => (vote of new governor)))
50
34
/// whether a proposer has voted in this period and who they're voting for
@@ -56,17 +40,20 @@ contract Governable {
56
40
57
41
event GovernanceOwnershipTransferred (
58
42
address indexed previousOwner ,
43
+ uint32 previousOwnerJobId ,
59
44
address indexed newOwner ,
60
- uint256 timestamp ,
61
- uint32 indexed refreshNonce
45
+ uint32 indexed jobId ,
46
+ uint256 timestamp
47
+
62
48
);
63
49
event RecoveredAddress (address indexed recovered );
64
50
65
- constructor (address _governor , uint32 _refreshNonce ) {
51
+ constructor (address _governor , uint32 _jobId , uint32 _votingThreshold ) {
66
52
governor = _governor;
67
- refreshNonce = _refreshNonce;
53
+ jobId = _jobId;
54
+ votingThreshold = _votingThreshold;
68
55
lastGovernorUpdateTime = block .timestamp ;
69
- emit GovernanceOwnershipTransferred (address (0 ), _governor, block .timestamp , refreshNonce );
56
+ emit GovernanceOwnershipTransferred (address (0 ), 0 , _governor, _jobId, block .timestamp );
70
57
}
71
58
72
59
/// @notice Throws if called by any account other than the owner.
@@ -75,25 +62,13 @@ contract Governable {
75
62
_;
76
63
}
77
64
78
- /// @notice Checks if its a valid time to vote.
79
- modifier isValidTimeToVote () {
80
- // Check block time stamp is some length greater than the last time
81
- // ownership transferred
82
- require (
83
- block .timestamp >
84
- lastGovernorUpdateTime +
85
- ((sessionLengthMultiplier * averageSessionLengthInMillisecs) / 1000 ),
86
- "Governable: Invalid time for vote "
87
- );
88
- _;
89
- }
90
65
91
66
/// @notice Checks if the vote nonces are valid.
92
67
modifier areValidVotes (Vote[] memory votes ) {
93
68
for (uint i = 0 ; i < votes.length ; i++ ) {
94
69
require (
95
- votes[i].nonce == refreshNonce ,
96
- "Governable: Nonce of vote must match refreshNonce "
70
+ votes[i].jobId < jobId ,
71
+ "Governable: JobId of vote must match jobId "
97
72
);
98
73
require (
99
74
votes[i].proposedGovernor != address (0x0 ),
@@ -129,74 +104,51 @@ contract Governable {
129
104
/// @notice Renouncing ownership will leave the contract without an owner,
130
105
/// thereby removing any functionality that is only available to the owner.
131
106
function renounceOwnership () public onlyGovernor {
132
- voterMerkleRoot = bytes32 (0 );
133
- averageSessionLengthInMillisecs = 1 << (64 - 1 );
134
- voterCount = 0 ;
135
- refreshNonce++ ;
107
+ votingThreshold = 0 ;
108
+ jobId = 0 ;
136
109
governor = address (0 );
137
- emit GovernanceOwnershipTransferred (governor, address (0 ), block .timestamp , refreshNonce );
110
+ emit GovernanceOwnershipTransferred (governor, jobId, address (0 ), jobId, block .timestamp );
138
111
}
139
112
140
113
/// @notice Transfers ownership of the contract to a new account (`newOwner`).
141
114
/// @param newOwner The new owner of the contract.
142
- /// @param nonce The nonce of the proposal .
115
+ /// @param jobId JobId of the new governor .
143
116
/// @notice Can only be called by the current owner.
144
- function transferOwnership (address newOwner , uint32 nonce ) public onlyGovernor {
145
- _transferOwnership (newOwner);
146
- refreshNonce = nonce;
117
+ function transferOwnership (address newOwner , uint32 jobId ) public onlyGovernor {
118
+ _transferOwnership (newOwner, jobId);
147
119
}
148
120
149
121
/// @notice Transfers ownership of the contract to a new account associated with the publicKey
150
- /// and update other storage values relevant to the emergency voting process.
151
- /// @param _voterMerkleRoot The new voter merkle root.
152
- /// @param _averageSessionLengthInMillisecs The new average session length in milliseconds.
153
- /// @param _voterCount The new number of voters.
154
- /// @param _nonce The nonce of the proposal.
122
+ /// @param _jobId The nonce of the proposal.
155
123
/// @param _publicKey The public key of the new governor.
156
124
/// @param _sig The signature of the propsal data.
157
125
function transferOwnershipWithSignature (
158
- bytes32 _voterMerkleRoot ,
159
- uint64 _averageSessionLengthInMillisecs ,
160
- uint32 _voterCount ,
161
- uint32 _nonce ,
126
+ uint32 _jobId ,
162
127
bytes memory _publicKey ,
163
128
bytes memory _sig
164
129
) public {
165
- require (_nonce == refreshNonce + 1 , "Governable: Nonce must increment by 1 " );
166
- require (_averageSessionLengthInMillisecs > 0 , "Governable: Invalid session length " );
130
+ require (_jobId > jobId, "Governable: JobId must be greater than current jobId " );
167
131
bytes32 pubKeyHash = keccak256 (_publicKey);
168
132
address newOwner = address (uint160 (uint256 (pubKeyHash)));
169
133
require (
170
134
isSignatureFromGovernor (
171
135
abi.encodePacked (
172
- _voterMerkleRoot,
173
- _averageSessionLengthInMillisecs,
174
- _voterCount,
175
- _nonce,
176
136
_publicKey
177
137
),
178
138
_sig
179
139
),
180
140
"Governable: caller is not the governor "
181
141
);
182
- voterMerkleRoot = _voterMerkleRoot;
183
- averageSessionLengthInMillisecs = _averageSessionLengthInMillisecs;
184
- voterCount = _voterCount;
185
- _transferOwnership (newOwner);
142
+ _transferOwnership (newOwner, _jobId);
186
143
}
187
144
188
145
/// @notice Casts a vote in favor of force refreshing the governor
189
146
/// @param vote A vote struct
190
147
function voteInFavorForceSetGovernor (
191
148
Vote memory vote
192
- ) external isValidTimeToVote areValidVotes (arrayifyVote (vote)) {
149
+ ) external areValidVotes (arrayifyVote (vote)) {
193
150
// Check merkle proof is valid
194
151
address proposerAddress = msg .sender ;
195
- require (
196
- _isValidMerkleProof (vote.siblingPathNodes, proposerAddress, vote.leafIndex),
197
- "Governable: Invalid merkle proof "
198
- );
199
-
200
152
_processVote (vote, proposerAddress);
201
153
}
202
154
@@ -206,96 +158,63 @@ contract Governable {
206
158
function voteInFavorForceSetGovernorWithSig (
207
159
Vote[] memory votes ,
208
160
bytes [] memory sigs
209
- ) external isValidTimeToVote areValidVotes (votes) {
161
+ ) external areValidVotes (votes) {
210
162
require (votes.length == sigs.length , "Governable: Invalid number of votes and signatures " );
211
163
for (uint i = 0 ; i < votes.length ; i++ ) {
212
164
// Recover the address from the signature
213
165
address proposerAddress = recover (abi.encode (votes[i]), sigs[i]);
214
-
215
- // Check merkle proof is valid
216
- bool isValid = _isValidMerkleProof (
217
- votes[i].siblingPathNodes,
218
- proposerAddress,
219
- votes[i].leafIndex
220
- );
221
- if (isValid) {
222
- // Since we require voterCount / 2 votes to be in favor of a new governor,
223
- // we can stop processing votes if we have enough votes for a new governor.
224
- // Since we have nonces on votes, we can safely assume that the votes from
225
- // previous rounds cannot be processed. We process and terminate the vote early
226
- // even if the vote is not the last vote in the array by choice.
227
- if (_processVote (votes[i], proposerAddress)) {
228
- return ;
229
- }
166
+ // Since we require voterCount / 2 votes to be in favor of a new governor,
167
+ // we can stop processing votes if we have enough votes for a new governor.
168
+ // Since we have nonces on votes, we can safely assume that the votes from
169
+ // previous rounds cannot be processed. We process and terminate the vote early
170
+ // even if the vote is not the last vote in the array by choice.
171
+ if (_processVote (votes[i], proposerAddress)) {
172
+ return ;
230
173
}
231
174
}
232
175
}
233
-
176
+
234
177
/// @notice Process a vote
235
178
/// @param vote A vote struct
236
179
/// @param voter The address of the voter
237
180
function _processVote (Vote memory vote , address voter ) internal returns (bool ) {
238
181
// If the proposer has already voted, remove their previous vote
239
- if (alreadyVoted[vote.nonce ][voter] != address (0x0 )) {
240
- address previousVote = alreadyVoted[vote.nonce ][voter];
241
- numOfVotesForGovernor[vote.nonce ][previousVote] -= 1 ;
182
+ if (alreadyVoted[vote.jobId ][voter] != address (0x0 )) {
183
+ address previousVote = alreadyVoted[vote.jobId ][voter];
184
+ numOfVotesForGovernor[vote.jobId ][previousVote] -= 1 ;
242
185
}
243
186
// Update the vote mappings
244
- alreadyVoted[vote.nonce ][voter] = vote.proposedGovernor;
245
- numOfVotesForGovernor[vote.nonce ][vote.proposedGovernor] += 1 ;
187
+ alreadyVoted[vote.jobId ][voter] = vote.proposedGovernor;
188
+ numOfVotesForGovernor[vote.jobId ][vote.proposedGovernor] += 1 ;
246
189
// Try to resolve the vote if enough votes for a proposed governor have been cast.
247
190
// Note: `voterCount` is also assumed to be the maximum # of voters in the system.
248
191
// Therefore, if `voterCount / 2` votes are in favor of a new governor, we can
249
192
// safely assume that there is no other governor that has more votes.
250
- if (numOfVotesForGovernor[vote.nonce ][vote.proposedGovernor] > voterCount / 2 ) {
251
- _transferOwnership (vote.proposedGovernor);
193
+ if (numOfVotesForGovernor[vote.jobId ][vote.proposedGovernor] > votingThreshold ) {
194
+ _transferOwnership (vote.proposedGovernor, vote.jobId );
252
195
// If we transferred ownership, we return true to indicate the election is over.
253
196
return true ;
254
197
}
255
198
256
199
return false ;
257
200
}
258
201
259
- /// @notice Checks a merkle proof given a leaf and merkle path of sibling nodes.
260
- /// @param siblingPathNodes the path of sibling nodes of the Merkle proof
261
- /// @param leaf the leaf to prove membership of in the Merkle tree
262
- /// @param leafIndex the index of the leaf in the Merkle tree
263
- function _isValidMerkleProof (
264
- bytes32 [] memory siblingPathNodes ,
265
- address leaf ,
266
- uint32 leafIndex
267
- ) internal view returns (bool ) {
268
- require (
269
- siblingPathNodes.length == getVoterMerkleTreeDepth (),
270
- "Governable: Invalid merkle proof length "
271
- );
272
- bytes32 leafHash = keccak256 (abi.encodePacked (leaf));
273
- bytes32 currNodeHash = leafHash;
274
- uint32 nodeIndex = leafIndex;
275
- for (uint8 i = 0 ; i < siblingPathNodes.length ; i++ ) {
276
- if (nodeIndex % 2 == 0 ) {
277
- currNodeHash = keccak256 (abi.encodePacked (currNodeHash, siblingPathNodes[i]));
278
- } else {
279
- currNodeHash = keccak256 (abi.encodePacked (siblingPathNodes[i], currNodeHash));
280
- }
281
- nodeIndex = nodeIndex / 2 ;
282
- }
283
- return voterMerkleRoot == currNodeHash;
284
- }
285
-
286
202
/// @notice Transfers ownership of the contract to a new account (`newOwner`).
287
203
/// @param newOwner The new owner of the contract
288
- function _transferOwnership (address newOwner ) internal {
204
+ /// @param _jobId JobId of the new governor.
205
+ function _transferOwnership (address newOwner , uint32 _jobId ) internal {
289
206
require (newOwner != address (0 ), "Governable: New governor is the zero address " );
290
207
address previousGovernor = governor;
208
+ uint32 previousGovernorJobId = jobId;
291
209
governor = newOwner;
292
210
lastGovernorUpdateTime = block .timestamp ;
293
- refreshNonce ++ ;
211
+ jobId = _jobId ;
294
212
emit GovernanceOwnershipTransferred (
295
213
previousGovernor,
214
+ previousGovernorJobId,
296
215
newOwner,
297
- lastGovernorUpdateTime ,
298
- refreshNonce
216
+ _jobId ,
217
+ lastGovernorUpdateTime
299
218
);
300
219
}
301
220
@@ -319,48 +238,15 @@ contract Governable {
319
238
}
320
239
321
240
/// @notice Helper function for creating a vote struct
322
- /// @param _nonce The nonce of the proposal
323
- /// @param _leafIndex The leaf index of the vote
241
+ /// @param _jobId Job id of the proposed governor
324
242
/// @param _proposedGovernor The proposed governor
325
- /// @param _siblingPathNodes The sibling path nodes of the vote
326
243
/// @return Vote The vote struct
327
244
function createVote (
328
- uint32 _nonce ,
329
- uint32 _leafIndex ,
330
- address _proposedGovernor ,
331
- bytes32 [] memory _siblingPathNodes
245
+ uint32 _jobId ,
246
+ address _proposedGovernor
332
247
) public pure returns (Vote memory ) {
333
- return Vote (_nonce, _leafIndex, _proposedGovernor, _siblingPathNodes );
248
+ return Vote (_jobId, _proposedGovernor);
334
249
}
335
250
336
- /// @notice Helper function to return the depth of the voter merkle tree.
337
- /// @return uint8 The depth of the voter merkle tree
338
- /// @notice It is assumed that the number of voters never exceeds 4096.
339
- function getVoterMerkleTreeDepth () public view returns (uint8 ) {
340
- if (voterCount <= 2 ) {
341
- return 1 ;
342
- } else if (voterCount <= 4 ) {
343
- return 2 ;
344
- } else if (voterCount <= 8 ) {
345
- return 3 ;
346
- } else if (voterCount <= 16 ) {
347
- return 4 ;
348
- } else if (voterCount <= 32 ) {
349
- return 5 ;
350
- } else if (voterCount <= 64 ) {
351
- return 6 ;
352
- } else if (voterCount <= 128 ) {
353
- return 7 ;
354
- } else if (voterCount <= 256 ) {
355
- return 8 ;
356
- } else if (voterCount <= 512 ) {
357
- return 9 ;
358
- } else if (voterCount <= 1024 ) {
359
- return 10 ;
360
- } else if (voterCount <= 2048 ) {
361
- return 11 ;
362
- } else {
363
- return 12 ;
364
- }
365
- }
251
+
366
252
}
0 commit comments