| 
									
										
										
										
											2016-03-31 12:20:24 +03:00
										 |  |  | // Copyright 2016 The go-ethereum Authors
 | 
					
						
							|  |  |  | // This file is part of the go-ethereum library.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // The go-ethereum library is free software: you can redistribute it and/or modify
 | 
					
						
							|  |  |  | // it under the terms of the GNU Lesser General Public License as published by
 | 
					
						
							|  |  |  | // the Free Software Foundation, either version 3 of the License, or
 | 
					
						
							|  |  |  | // (at your option) any later version.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // The go-ethereum library is distributed in the hope that it will be useful,
 | 
					
						
							|  |  |  | // but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
					
						
							|  |  |  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 | 
					
						
							|  |  |  | // GNU Lesser General Public License for more details.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // You should have received a copy of the GNU Lesser General Public License
 | 
					
						
							|  |  |  | // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // ReleaseOracle is an Ethereum contract to store the current and previous
 | 
					
						
							|  |  |  | // versions of the go-ethereum implementation. Its goal is to allow Geth to
 | 
					
						
							|  |  |  | // check for new releases automatically without the need to consult a central
 | 
					
						
							|  |  |  | // repository.
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2016-04-28 12:00:11 +03:00
										 |  |  | // The contract takes a vote based approach on both assigning authorised signers
 | 
					
						
							| 
									
										
										
										
											2016-03-31 12:20:24 +03:00
										 |  |  | // as well as signing off on new Geth releases.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // Note, when a signer is demoted, the currently pending release is auto-nuked.
 | 
					
						
							|  |  |  | // The reason is to prevent suprises where a demotion actually tilts the votes
 | 
					
						
							|  |  |  | // in favor of one voter party and pushing out a new release as a consequence of
 | 
					
						
							|  |  |  | // a simple demotion.
 | 
					
						
							|  |  |  | contract ReleaseOracle { | 
					
						
							|  |  |  |   // Votes is an internal data structure to count votes on a specific proposal
 | 
					
						
							|  |  |  |   struct Votes { | 
					
						
							|  |  |  |     address[] pass; // List of signers voting to pass a proposal
 | 
					
						
							|  |  |  |     address[] fail; // List of signers voting to fail a proposal
 | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Version is the version details of a particular Geth release
 | 
					
						
							|  |  |  |   struct Version { | 
					
						
							|  |  |  |     uint32  major;  // Major version component of the release
 | 
					
						
							|  |  |  |     uint32  minor;  // Minor version component of the release
 | 
					
						
							|  |  |  |     uint32  patch;  // Patch version component of the release
 | 
					
						
							|  |  |  |     bytes20 commit; // Git SHA1 commit hash of the release
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     uint64  time;  // Timestamp of the release approval
 | 
					
						
							|  |  |  |     Votes   votes; // Votes that passed this release
 | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Oracle authorization details
 | 
					
						
							| 
									
										
										
										
											2016-04-28 12:00:11 +03:00
										 |  |  |   mapping(address => bool) authorised; // Set of accounts allowed to vote on updating the contract
 | 
					
						
							|  |  |  |   address[]                voters;     // List of addresses currently accepted as signers
 | 
					
						
							| 
									
										
										
										
											2016-03-31 12:20:24 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // Various proposals being voted on
 | 
					
						
							|  |  |  |   mapping(address => Votes) authProps; // Currently running user authorization proposals
 | 
					
						
							|  |  |  |   address[]                 authPend;  // List of addresses being voted on (map indexes)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Version   verProp;  // Currently proposed release being voted on
 | 
					
						
							|  |  |  |   Version[] releases; // All the positively voted releases
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // isSigner is a modifier to authorize contract transactions.
 | 
					
						
							|  |  |  |   modifier isSigner() { | 
					
						
							| 
									
										
										
										
											2016-04-28 12:00:11 +03:00
										 |  |  |     if (authorised[msg.sender]) { | 
					
						
							| 
									
										
										
										
											2016-03-31 12:20:24 +03:00
										 |  |  |       _ | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-28 12:00:11 +03:00
										 |  |  |   // Constructor to assign the initial set of signers.
 | 
					
						
							|  |  |  |   function ReleaseOracle(address[] signers) { | 
					
						
							|  |  |  |     // If no signers were specified, assign the creator as the sole signer
 | 
					
						
							|  |  |  |     if (signers.length == 0) { | 
					
						
							|  |  |  |       authorised[msg.sender] = true; | 
					
						
							|  |  |  |       voters.push(msg.sender); | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     // Otherwise assign the individual signers one by one
 | 
					
						
							|  |  |  |     for (uint i = 0; i < signers.length; i++) { | 
					
						
							|  |  |  |       authorised[signers[i]] = true; | 
					
						
							|  |  |  |       voters.push(signers[i]); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2016-03-31 12:20:24 +03:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-28 12:00:11 +03:00
										 |  |  |   // signers is an accessor method to retrieve all te signers (public accessor
 | 
					
						
							| 
									
										
										
										
											2017-01-06 19:44:35 +02:00
										 |  |  |   // generates an indexed one, not a retrieve-all version).
 | 
					
						
							| 
									
										
										
										
											2016-04-28 12:00:11 +03:00
										 |  |  |   function signers() constant returns(address[]) { | 
					
						
							|  |  |  |     return voters; | 
					
						
							| 
									
										
										
										
											2016-03-31 12:20:24 +03:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-28 12:00:11 +03:00
										 |  |  |   // authProposals retrieves the list of addresses that authorization proposals
 | 
					
						
							| 
									
										
										
										
											2016-03-31 12:20:24 +03:00
										 |  |  |   // are currently being voted on.
 | 
					
						
							| 
									
										
										
										
											2016-04-28 12:00:11 +03:00
										 |  |  |   function authProposals() constant returns(address[]) { | 
					
						
							| 
									
										
										
										
											2016-03-31 12:20:24 +03:00
										 |  |  |     return authPend; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-28 12:00:11 +03:00
										 |  |  |   // authVotes retrieves the current authorization votes for a particular user
 | 
					
						
							| 
									
										
										
										
											2016-03-31 12:20:24 +03:00
										 |  |  |   // to promote him into the list of signers, or demote him from there.
 | 
					
						
							| 
									
										
										
										
											2016-04-28 12:00:11 +03:00
										 |  |  |   function authVotes(address user) constant returns(address[] promote, address[] demote) { | 
					
						
							| 
									
										
										
										
											2016-03-31 12:20:24 +03:00
										 |  |  |     return (authProps[user].pass, authProps[user].fail); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-28 12:00:11 +03:00
										 |  |  |   // currentVersion retrieves the semantic version, commit hash and release time
 | 
					
						
							| 
									
										
										
										
											2016-03-31 12:20:24 +03:00
										 |  |  |   // of the currently votec active release.
 | 
					
						
							| 
									
										
										
										
											2016-04-28 12:00:11 +03:00
										 |  |  |   function currentVersion() constant returns (uint32 major, uint32 minor, uint32 patch, bytes20 commit, uint time) { | 
					
						
							| 
									
										
										
										
											2016-03-31 12:20:24 +03:00
										 |  |  |     if (releases.length == 0) { | 
					
						
							|  |  |  |       return (0, 0, 0, 0, 0); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     var release = releases[releases.length - 1]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return (release.major, release.minor, release.patch, release.commit, release.time); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-28 12:00:11 +03:00
										 |  |  |   // proposedVersion retrieves the semantic version, commit hash and the current
 | 
					
						
							| 
									
										
										
										
											2016-03-31 12:20:24 +03:00
										 |  |  |   // votes for the next proposed release.
 | 
					
						
							| 
									
										
										
										
											2016-04-28 12:00:11 +03:00
										 |  |  |   function proposedVersion() constant returns (uint32 major, uint32 minor, uint32 patch, bytes20 commit, address[] pass, address[] fail) { | 
					
						
							| 
									
										
										
										
											2016-03-31 12:20:24 +03:00
										 |  |  |     return (verProp.major, verProp.minor, verProp.patch, verProp.commit, verProp.votes.pass, verProp.votes.fail); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-28 12:00:11 +03:00
										 |  |  |   // promote pitches in on a voting campaign to promote a new user to a signer
 | 
					
						
							| 
									
										
										
										
											2016-03-31 12:20:24 +03:00
										 |  |  |   // position.
 | 
					
						
							| 
									
										
										
										
											2016-04-28 12:00:11 +03:00
										 |  |  |   function promote(address user) { | 
					
						
							| 
									
										
										
										
											2016-03-31 12:20:24 +03:00
										 |  |  |     updateSigner(user, true); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-28 12:00:11 +03:00
										 |  |  |   // demote pitches in on a voting campaign to demote an authorised user from
 | 
					
						
							| 
									
										
										
										
											2016-03-31 12:20:24 +03:00
										 |  |  |   // its signer position.
 | 
					
						
							| 
									
										
										
										
											2016-04-28 12:00:11 +03:00
										 |  |  |   function demote(address user) { | 
					
						
							| 
									
										
										
										
											2016-03-31 12:20:24 +03:00
										 |  |  |     updateSigner(user, false); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-28 12:00:11 +03:00
										 |  |  |   // release votes for a particular version to be included as the next release.
 | 
					
						
							|  |  |  |   function release(uint32 major, uint32 minor, uint32 patch, bytes20 commit) { | 
					
						
							| 
									
										
										
										
											2016-03-31 12:20:24 +03:00
										 |  |  |     updateRelease(major, minor, patch, commit, true); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-28 12:00:11 +03:00
										 |  |  |   // nuke votes for the currently proposed version to not be included as the next
 | 
					
						
							| 
									
										
										
										
											2016-03-31 12:20:24 +03:00
										 |  |  |   // release. Nuking doesn't require a specific version number for simplicity.
 | 
					
						
							| 
									
										
										
										
											2016-04-28 12:00:11 +03:00
										 |  |  |   function nuke() { | 
					
						
							| 
									
										
										
										
											2016-03-31 12:20:24 +03:00
										 |  |  |     updateRelease(0, 0, 0, 0, false); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // updateSigner marks a vote for changing the status of an Ethereum user, either
 | 
					
						
							| 
									
										
										
										
											2016-04-28 12:00:11 +03:00
										 |  |  |   // for or against the user being an authorised signer.
 | 
					
						
							|  |  |  |   function updateSigner(address user, bool authorize) internal isSigner { | 
					
						
							| 
									
										
										
										
											2016-03-31 12:20:24 +03:00
										 |  |  |     // Gather the current votes and ensure we don't double vote
 | 
					
						
							|  |  |  |     Votes votes = authProps[user]; | 
					
						
							|  |  |  |     for (uint i = 0; i < votes.pass.length; i++) { | 
					
						
							|  |  |  |       if (votes.pass[i] == msg.sender) { | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     for (i = 0; i < votes.fail.length; i++) { | 
					
						
							|  |  |  |       if (votes.fail[i] == msg.sender) { | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     // If no authorization proposal is open, add the user to the index for later lookups
 | 
					
						
							|  |  |  |     if (votes.pass.length == 0 && votes.fail.length == 0) { | 
					
						
							|  |  |  |       authPend.push(user); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     // Cast the vote and return if the proposal cannot be resolved yet
 | 
					
						
							|  |  |  |     if (authorize) { | 
					
						
							|  |  |  |       votes.pass.push(msg.sender); | 
					
						
							| 
									
										
										
										
											2016-04-28 12:00:11 +03:00
										 |  |  |       if (votes.pass.length <= voters.length / 2) { | 
					
						
							| 
									
										
										
										
											2016-03-31 12:20:24 +03:00
										 |  |  |         return; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       votes.fail.push(msg.sender); | 
					
						
							| 
									
										
										
										
											2016-04-28 12:00:11 +03:00
										 |  |  |       if (votes.fail.length <= voters.length / 2) { | 
					
						
							| 
									
										
										
										
											2016-03-31 12:20:24 +03:00
										 |  |  |         return; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     // Proposal resolved in our favor, execute whatever we voted on
 | 
					
						
							| 
									
										
										
										
											2016-04-28 12:00:11 +03:00
										 |  |  |     if (authorize && !authorised[user]) { | 
					
						
							|  |  |  |       authorised[user] = true; | 
					
						
							|  |  |  |       voters.push(user); | 
					
						
							|  |  |  |     } else if (!authorize && authorised[user]) { | 
					
						
							|  |  |  |       authorised[user] = false; | 
					
						
							| 
									
										
										
										
											2016-03-31 12:20:24 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-28 12:00:11 +03:00
										 |  |  |       for (i = 0; i < voters.length; i++) { | 
					
						
							|  |  |  |         if (voters[i] == user) { | 
					
						
							|  |  |  |           voters[i] = voters[voters.length - 1]; | 
					
						
							|  |  |  |           voters.length--; | 
					
						
							| 
									
										
										
										
											2016-03-31 12:20:24 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-06 19:44:35 +02:00
										 |  |  |           delete verProp; // Nuke any version proposal (no surprise releases!)
 | 
					
						
							| 
									
										
										
										
											2016-03-31 12:20:24 +03:00
										 |  |  |           break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     // Finally delete the resolved proposal, index and garbage collect
 | 
					
						
							|  |  |  |     delete authProps[user]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for (i = 0; i < authPend.length; i++) { | 
					
						
							|  |  |  |       if (authPend[i] == user) { | 
					
						
							|  |  |  |         authPend[i] = authPend[authPend.length - 1]; | 
					
						
							|  |  |  |         authPend.length--; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // updateRelease votes for a particular version to be included as the next release,
 | 
					
						
							|  |  |  |   // or for the currently proposed release to be nuked out.
 | 
					
						
							| 
									
										
										
										
											2016-04-28 12:00:11 +03:00
										 |  |  |   function updateRelease(uint32 major, uint32 minor, uint32 patch, bytes20 commit, bool release) internal isSigner { | 
					
						
							| 
									
										
										
										
											2016-03-31 12:20:24 +03:00
										 |  |  |     // Skip nuke votes if no proposal is pending
 | 
					
						
							|  |  |  |     if (!release && verProp.votes.pass.length == 0) { | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     // Mark a new release if no proposal is pending
 | 
					
						
							|  |  |  |     if (verProp.votes.pass.length == 0) { | 
					
						
							|  |  |  |       verProp.major  = major; | 
					
						
							|  |  |  |       verProp.minor  = minor; | 
					
						
							|  |  |  |       verProp.patch  = patch; | 
					
						
							|  |  |  |       verProp.commit = commit; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     // Make sure positive votes match the current proposal
 | 
					
						
							|  |  |  |     if (release && (verProp.major != major || verProp.minor != minor || verProp.patch != patch || verProp.commit != commit)) { | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     // Gather the current votes and ensure we don't double vote
 | 
					
						
							|  |  |  |     Votes votes = verProp.votes; | 
					
						
							|  |  |  |     for (uint i = 0; i < votes.pass.length; i++) { | 
					
						
							|  |  |  |       if (votes.pass[i] == msg.sender) { | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     for (i = 0; i < votes.fail.length; i++) { | 
					
						
							|  |  |  |       if (votes.fail[i] == msg.sender) { | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     // Cast the vote and return if the proposal cannot be resolved yet
 | 
					
						
							|  |  |  |     if (release) { | 
					
						
							|  |  |  |       votes.pass.push(msg.sender); | 
					
						
							| 
									
										
										
										
											2016-04-28 12:00:11 +03:00
										 |  |  |       if (votes.pass.length <= voters.length / 2) { | 
					
						
							| 
									
										
										
										
											2016-03-31 12:20:24 +03:00
										 |  |  |         return; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       votes.fail.push(msg.sender); | 
					
						
							| 
									
										
										
										
											2016-04-28 12:00:11 +03:00
										 |  |  |       if (votes.fail.length <= voters.length / 2) { | 
					
						
							| 
									
										
										
										
											2016-03-31 12:20:24 +03:00
										 |  |  |         return; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     // Proposal resolved in our favor, execute whatever we voted on
 | 
					
						
							|  |  |  |     if (release) { | 
					
						
							|  |  |  |       verProp.time = uint64(now); | 
					
						
							|  |  |  |       releases.push(verProp); | 
					
						
							|  |  |  |       delete verProp; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       delete verProp; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } |