pragma solidity ^0.4.18; import "../VotingMachines/IntVoteInterface.sol"; import "./UniversalScheme.sol"; /** * @title A scheme to manage the upgrade of an organization. * @dev The scheme is used to upgrade the controller of an organization to a new controller. */ contract UpgradeScheme is UniversalScheme, ExecutableInterface { event NewUpgradeProposal( address indexed _avatar, bytes32 indexed _proposalId, address indexed _intVoteInterface, address _newController ); event ChangeUpgradeSchemeProposal( address indexed _avatar, bytes32 indexed _proposalId, address indexed _intVoteInterface, address newUpgradeScheme, bytes32 _params ); event ProposalExecuted(address indexed _avatar, bytes32 indexed _proposalId); event ProposalDeleted(address indexed _avatar, bytes32 indexed _proposalId); // Details of an upgrade proposal: struct UpgradeProposal { address upgradeContract; // Either the new controller we upgrade to, or the new upgrading scheme. bytes32 params; // Params for the new upgrading scheme. uint proposalType; // 1: Upgrade controller, 2: change upgrade scheme. } // A mapping from the organization's (Avatar) address to the saved data of the organization: mapping(address=>mapping(bytes32=>UpgradeProposal)) public organizationsProposals; // A mapping from hashes to parameters (use to store a particular configuration on the controller) struct Parameters { bytes32 voteParams; IntVoteInterface intVote; } mapping(bytes32=>Parameters) public parameters; /** * @dev Constructor */ function UpgradeScheme() public {} /** * @dev hash the parameters, save them if necessary, and return the hash value */ function setParameters( bytes32 _voteParams, IntVoteInterface _intVote ) public returns(bytes32) { bytes32 paramsHash = getParametersHash(_voteParams, _intVote); parameters[paramsHash].voteParams = _voteParams; parameters[paramsHash].intVote = _intVote; return paramsHash; } /** * @dev return a hash of the given parameters */ function getParametersHash( bytes32 _voteParams, IntVoteInterface _intVote ) public pure returns(bytes32) { return (keccak256(_voteParams, _intVote)); } /** * @dev propose an upgrade of the organization's controller * @param _avatar avatar of the organization * @param _newController address of the new controller that is being proposed * @return an id which represents the proposal */ function proposeUpgrade(Avatar _avatar, address _newController) public returns(bytes32) { Parameters memory params = parameters[getParametersFromController(_avatar)]; bytes32 proposalId = params.intVote.propose(2, params.voteParams, _avatar, ExecutableInterface(this),msg.sender); organizationsProposals[_avatar][proposalId].proposalType = 1; organizationsProposals[_avatar][proposalId].upgradeContract = _newController; NewUpgradeProposal(_avatar, proposalId, params.intVote, _newController); params.intVote.ownerVote(proposalId, 1, msg.sender); // Automatically votes `yes` in the name of the proposal submitter.*/ return proposalId; } /** * @dev propose to replace this scheme by another upgrading scheme * @param _avatar avatar of the organization * @param _scheme address of the new upgrading scheme * @param _params ??? * @return an id which represents the proposal */ function proposeChangeUpgradingScheme( Avatar _avatar, address _scheme, bytes32 _params ) public returns(bytes32) { Parameters memory params = parameters[getParametersFromController(_avatar)]; IntVoteInterface intVote = params.intVote; bytes32 proposalId = intVote.propose(2, params.voteParams, _avatar, ExecutableInterface(this),msg.sender); if (organizationsProposals[_avatar][proposalId].proposalType != 0) { revert(); } UpgradeProposal memory proposal = UpgradeProposal({ proposalType: 2, upgradeContract: _scheme, params: _params }); organizationsProposals[_avatar][proposalId] = proposal; ChangeUpgradeSchemeProposal( _avatar, proposalId, params.intVote, _scheme, _params ); intVote.ownerVote(proposalId, 1, msg.sender); // Automatically votes `yes` in the name of the opener. return proposalId; } /** * @dev execution of proposals, can only be called by the voting machine in which the vote is held. * @param _proposalId the ID of the voting in the voting machine * @param _avatar address of the controller * @param _param a parameter of the voting result, 0 is no and 1 is yes. */ function execute(bytes32 _proposalId, address _avatar, int _param) public returns(bool) { // Check the caller is indeed the voting machine: require(parameters[getParametersFromController(Avatar(_avatar))].intVote == msg.sender); UpgradeProposal memory proposal = organizationsProposals[_avatar][_proposalId]; delete organizationsProposals[_avatar][_proposalId]; // Check if vote was successful: if (_param == 1) { // Define controller and get the params: ControllerInterface controller = ControllerInterface(Avatar(_avatar).owner()); // Upgrading controller: if (proposal.proposalType == 1) { if (!controller.upgradeController(proposal.upgradeContract,_avatar)) { revert(); } } // Changing upgrade scheme: if (proposal.proposalType == 2) { bytes4 permissions = controller.getSchemePermissions(this,_avatar); if (!controller.registerScheme(proposal.upgradeContract, proposal.params, permissions,_avatar)) { revert(); } if (proposal.upgradeContract != address(this) ) { if (!controller.unregisterSelf(_avatar)) { revert(); } } } } return true; } }