Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

proposer set update logic for governable.sol #131

Merged
merged 8 commits into from
Mar 7, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 76 additions & 0 deletions contracts/utils/Governable.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,35 @@ contract Governable {
address private _governor;
uint32 public refreshNonce = 0;

// Storage values relevant to proposer set update
uint32 public proposerSetUpdateNonce = 0;
bytes32 public proposerSetRoot;
uint64 public averageSessionLengthInMillisecs = 2**64 - 1;
uint256 public sessionLengthMultiplier = 2;
uint32 public numOfProposers;
mapping (bytes => bool) alreadyVoted;
uint256 public currentVotingPeriod = 0;
mapping (uint256 => mapping(address => uint32)) numOfVotesForGovernor;


struct Vote {
bytes leaf;
uint32 leafIndex;
bytes32[] siblingPathNodes;
address proposedGovernor;
}

// Last time ownership was transferred to a new govenror
uint256 public lastGovernorUpdateTime;

event GovernanceOwnershipTransferred(address indexed previousOwner, address indexed newOwner);
event RecoveredAddress(address indexed recovered);

mapping (bytes32 => bool) private _usedHashes;

constructor (address governor) {
_governor = governor;
lastGovernorUpdateTime = block.timestamp;
emit GovernanceOwnershipTransferred(address(0), _governor);
}

Expand Down Expand Up @@ -98,5 +120,59 @@ contract Governable {
require(newOwner != address(0), "Governable: new owner is the zero address");
emit GovernanceOwnershipTransferred(_governor, newOwner);
_governor = newOwner;
lastGovernorUpdateTime = block.timestamp;
currentVotingPeriod++;
}

function updateProposerSetData(bytes32 _proposerSetRoot, uint64 _averageSessionLengthInMillisecs, uint32 _numOfProposers, uint32 _proposerSetUpdateNonce, bytes memory sig) public {
// Valid Nonce
require(proposerSetUpdateNonce < _proposerSetUpdateNonce, "Invalid nonce");
require(_proposerSetUpdateNonce <= proposerSetUpdateNonce + 1, "Nonce must increment by 1");

// Valid Signature
require(isSignatureFromGovernor(abi.encodePacked(_proposerSetRoot, bytes8(_averageSessionLengthInMillisecs), bytes4(_numOfProposers), bytes4(_proposerSetUpdateNonce)), sig), "Governable: caller is not the governor");

proposerSetRoot = _proposerSetRoot;
averageSessionLengthInMillisecs = _averageSessionLengthInMillisecs;
numOfProposers = _numOfProposers;
proposerSetUpdateNonce = _proposerSetUpdateNonce;
currentVotingPeriod++;
}

function voteInFavorForceSetGovernor(Vote memory vote) external {
// Check time
require(block.timestamp >= lastGovernorUpdateTime + sessionLengthMultiplier * (averageSessionLengthInMillisecs / 1000), "Invalid time for vote");

// Check merkle proof is valid
require(_isValidMerkleProof(vote.siblingPathNodes, vote.leaf, vote.leafIndex), "invalid merkle proof");

// Make sure not already voted
require(!alreadyVoted[vote.leaf], "already voted");

alreadyVoted[vote.leaf] = true;
numOfVotesForGovernor[currentVotingPeriod][vote.proposedGovernor] += 1;
_tryResolveVote(vote.proposedGovernor);
}

function _tryResolveVote(address proposedGovernor) internal {
if (numOfVotesForGovernor[currentVotingPeriod][proposedGovernor] > numOfProposers / 2) {
_transferOwnership(proposedGovernor);
}
}

function _isValidMerkleProof(bytes32[] memory siblingPathNodes, bytes memory leaf, uint32 leafIndex) internal view returns (bool) {
bytes32 leafHash = keccak256(leaf);
bytes32 currNodeHash = leafHash;
uint32 nodeIndex = leafIndex;

for (uint8 i = 0; i < siblingPathNodes.length; i++) {
if (nodeIndex % 2 == 0) {
currNodeHash = keccak256(abi.encodePacked(currNodeHash, siblingPathNodes[i]));
} else {
currNodeHash = keccak256(abi.encodePacked(siblingPathNodes[i], currNodeHash));
}
nodeIndex = nodeIndex / 2;
}
return proposerSetRoot == currNodeHash;
}
}
Loading