Skip to content

Commit ea4d0ec

Browse files
committed
remove none and simplify governance voting
1 parent 03a6c58 commit ea4d0ec

File tree

3 files changed

+68
-176
lines changed

3 files changed

+68
-176
lines changed

packages/contracts/contracts/SignatureBridge.sol

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,9 @@ contract SignatureBridge is Governable, ChainIdWithType, ProposalNonceTracker {
4646

4747
/// @notice Initializes SignatureBridge with a governor
4848
/// @param initialGovernor Addresses that should be initially granted the relayer role.
49-
constructor(address initialGovernor, uint32 nonce) Governable(initialGovernor, nonce) {}
49+
/// @param jobId JobId of the governor.
50+
/// @param votingThreshold Number of votes required to force set the governor.
51+
constructor(address initialGovernor, uint32 jobId, uint32 votingThreshold) Governable(initialGovernor, jobId, votingThreshold) {}
5052

5153
/// @notice Sets a new resource for handler contracts that use the IExecutor interface,
5254
/// and maps the {handlerAddress} to {newResourceID} in {_resourceIdToHandlerAddress}.

packages/contracts/contracts/utils/Governable.sol

Lines changed: 55 additions & 169 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,11 @@ pragma solidity ^0.8.18;
88
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
99

1010
/// @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.
1412
/// @param proposedGovernor the governor that the voter wants to force reset to
1513
struct Vote {
16-
uint32 nonce;
17-
uint32 leafIndex;
14+
uint32 jobId;
1815
address proposedGovernor;
19-
bytes32[] siblingPathNodes;
2016
}
2117

2218
/// @title The Governable contract that defines the governance mechanism
@@ -25,26 +21,14 @@ struct Vote {
2521
contract Governable {
2622
address public governor;
2723

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;
3026

3127
/// Last time ownership was transferred to a new governor
3228
uint256 public lastGovernorUpdateTime;
3329

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;
4832

4933
/// (votingPeriod/refreshNonce => (proposer => (vote of new governor)))
5034
/// whether a proposer has voted in this period and who they're voting for
@@ -56,17 +40,20 @@ contract Governable {
5640

5741
event GovernanceOwnershipTransferred(
5842
address indexed previousOwner,
43+
uint32 previousOwnerJobId,
5944
address indexed newOwner,
60-
uint256 timestamp,
61-
uint32 indexed refreshNonce
45+
uint32 indexed jobId,
46+
uint256 timestamp
47+
6248
);
6349
event RecoveredAddress(address indexed recovered);
6450

65-
constructor(address _governor, uint32 _refreshNonce) {
51+
constructor(address _governor, uint32 _jobId, uint32 _votingThreshold) {
6652
governor = _governor;
67-
refreshNonce = _refreshNonce;
53+
jobId = _jobId;
54+
votingThreshold = _votingThreshold;
6855
lastGovernorUpdateTime = block.timestamp;
69-
emit GovernanceOwnershipTransferred(address(0), _governor, block.timestamp, refreshNonce);
56+
emit GovernanceOwnershipTransferred(address(0), 0, _governor, _jobId, block.timestamp);
7057
}
7158

7259
/// @notice Throws if called by any account other than the owner.
@@ -75,25 +62,13 @@ contract Governable {
7562
_;
7663
}
7764

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-
}
9065

9166
/// @notice Checks if the vote nonces are valid.
9267
modifier areValidVotes(Vote[] memory votes) {
9368
for (uint i = 0; i < votes.length; i++) {
9469
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"
9772
);
9873
require(
9974
votes[i].proposedGovernor != address(0x0),
@@ -129,74 +104,51 @@ contract Governable {
129104
/// @notice Renouncing ownership will leave the contract without an owner,
130105
/// thereby removing any functionality that is only available to the owner.
131106
function renounceOwnership() public onlyGovernor {
132-
voterMerkleRoot = bytes32(0);
133-
averageSessionLengthInMillisecs = 1 << (64 - 1);
134-
voterCount = 0;
135-
refreshNonce++;
107+
votingThreshold = 0;
108+
jobId = 0;
136109
governor = address(0);
137-
emit GovernanceOwnershipTransferred(governor, address(0), block.timestamp, refreshNonce);
110+
emit GovernanceOwnershipTransferred(governor, jobId, address(0), jobId, block.timestamp);
138111
}
139112

140113
/// @notice Transfers ownership of the contract to a new account (`newOwner`).
141114
/// @param newOwner The new owner of the contract.
142-
/// @param nonce The nonce of the proposal.
115+
/// @param jobId JobId of the new governor.
143116
/// @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);
147119
}
148120

149121
/// @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.
155123
/// @param _publicKey The public key of the new governor.
156124
/// @param _sig The signature of the propsal data.
157125
function transferOwnershipWithSignature(
158-
bytes32 _voterMerkleRoot,
159-
uint64 _averageSessionLengthInMillisecs,
160-
uint32 _voterCount,
161-
uint32 _nonce,
126+
uint32 _jobId,
162127
bytes memory _publicKey,
163128
bytes memory _sig
164129
) 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");
167131
bytes32 pubKeyHash = keccak256(_publicKey);
168132
address newOwner = address(uint160(uint256(pubKeyHash)));
169133
require(
170134
isSignatureFromGovernor(
171135
abi.encodePacked(
172-
_voterMerkleRoot,
173-
_averageSessionLengthInMillisecs,
174-
_voterCount,
175-
_nonce,
176136
_publicKey
177137
),
178138
_sig
179139
),
180140
"Governable: caller is not the governor"
181141
);
182-
voterMerkleRoot = _voterMerkleRoot;
183-
averageSessionLengthInMillisecs = _averageSessionLengthInMillisecs;
184-
voterCount = _voterCount;
185-
_transferOwnership(newOwner);
142+
_transferOwnership(newOwner, _jobId);
186143
}
187144

188145
/// @notice Casts a vote in favor of force refreshing the governor
189146
/// @param vote A vote struct
190147
function voteInFavorForceSetGovernor(
191148
Vote memory vote
192-
) external isValidTimeToVote areValidVotes(arrayifyVote(vote)) {
149+
) external areValidVotes(arrayifyVote(vote)) {
193150
// Check merkle proof is valid
194151
address proposerAddress = msg.sender;
195-
require(
196-
_isValidMerkleProof(vote.siblingPathNodes, proposerAddress, vote.leafIndex),
197-
"Governable: Invalid merkle proof"
198-
);
199-
200152
_processVote(vote, proposerAddress);
201153
}
202154

@@ -206,96 +158,63 @@ contract Governable {
206158
function voteInFavorForceSetGovernorWithSig(
207159
Vote[] memory votes,
208160
bytes[] memory sigs
209-
) external isValidTimeToVote areValidVotes(votes) {
161+
) external areValidVotes(votes) {
210162
require(votes.length == sigs.length, "Governable: Invalid number of votes and signatures");
211163
for (uint i = 0; i < votes.length; i++) {
212164
// Recover the address from the signature
213165
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;
230173
}
231174
}
232175
}
233-
176+
234177
/// @notice Process a vote
235178
/// @param vote A vote struct
236179
/// @param voter The address of the voter
237180
function _processVote(Vote memory vote, address voter) internal returns (bool) {
238181
// 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;
242185
}
243186
// 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;
246189
// Try to resolve the vote if enough votes for a proposed governor have been cast.
247190
// Note: `voterCount` is also assumed to be the maximum # of voters in the system.
248191
// Therefore, if `voterCount / 2` votes are in favor of a new governor, we can
249192
// 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);
252195
// If we transferred ownership, we return true to indicate the election is over.
253196
return true;
254197
}
255198

256199
return false;
257200
}
258201

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-
286202
/// @notice Transfers ownership of the contract to a new account (`newOwner`).
287203
/// @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 {
289206
require(newOwner != address(0), "Governable: New governor is the zero address");
290207
address previousGovernor = governor;
208+
uint32 previousGovernorJobId = jobId;
291209
governor = newOwner;
292210
lastGovernorUpdateTime = block.timestamp;
293-
refreshNonce++;
211+
jobId = _jobId;
294212
emit GovernanceOwnershipTransferred(
295213
previousGovernor,
214+
previousGovernorJobId,
296215
newOwner,
297-
lastGovernorUpdateTime,
298-
refreshNonce
216+
_jobId,
217+
lastGovernorUpdateTime
299218
);
300219
}
301220

@@ -319,48 +238,15 @@ contract Governable {
319238
}
320239

321240
/// @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
324242
/// @param _proposedGovernor The proposed governor
325-
/// @param _siblingPathNodes The sibling path nodes of the vote
326243
/// @return Vote The vote struct
327244
function createVote(
328-
uint32 _nonce,
329-
uint32 _leafIndex,
330-
address _proposedGovernor,
331-
bytes32[] memory _siblingPathNodes
245+
uint32 _jobId,
246+
address _proposedGovernor
332247
) public pure returns (Vote memory) {
333-
return Vote(_nonce, _leafIndex, _proposedGovernor, _siblingPathNodes);
248+
return Vote(_jobId, _proposedGovernor);
334249
}
335250

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+
366252
}

0 commit comments

Comments
 (0)