github.com/kisexp/xdchain@v0.0.0-20211206025815-490d6b732aa7/permission/v2/contract/VoterManager.sol (about)

     1  pragma solidity ^0.5.3;
     2  
     3  import "./PermissionsUpgradable.sol";
     4  
     5  /** @title Voter manager contract
     6    * @notice This contract holds implementation logic for all account voter and
     7      voting functionality. This can be called only by the implementation
     8      contract only. there are few view functions exposed as public and
     9      can be called directly. these are invoked by quorum for populating
    10      permissions data in cache
    11    * @dev each voting record has an attribute operation type (opType)
    12      which denotes the activity type which is pending approval. This can
    13      have the following values:
    14          0 - None - indicates no pending records for the org
    15          1 - New org add activity  
    16          2 - Org suspension activity
    17          3 - Revoke of org suspension
    18          4 - Assigning admin role for a new account
    19          5 - Blacklisted node recovery
    20          6 - Blacklisted account recovery
    21    */
    22  contract VoterManager {
    23      PermissionsUpgradable private permUpgradable;
    24      struct PendingOpDetails {
    25          string orgId;
    26          string enodeId;
    27          address account;
    28          uint256 opType;
    29      }
    30  
    31      struct Voter {
    32          address vAccount;
    33          bool active;
    34      }
    35  
    36      struct OrgVoterDetails {
    37          string orgId;
    38          uint256 voterCount;
    39          uint256 validVoterCount;
    40          uint256 voteCount;
    41          PendingOpDetails pendingOp;
    42          Voter [] voterList;
    43          mapping(address => uint256) voterIndex;
    44          mapping(uint256 => mapping(address => bool)) votingStatus;
    45      }
    46  
    47      OrgVoterDetails [] private orgVoterList;
    48      mapping(bytes32 => uint256) private VoterOrgIndex;
    49      uint256 private orgNum = 0;
    50  
    51      // events related to managing voting accounts for the org
    52      event VoterAdded(string _orgId, address _vAccount);
    53      event VoterDeleted(string _orgId, address _vAccount);
    54  
    55      event VotingItemAdded(string _orgId);
    56      event VoteProcessed(string _orgId);
    57  
    58      /** @notice confirms that the caller is the address of implementation
    59          contract
    60      */
    61      modifier onlyImplementation {
    62          require(msg.sender == permUpgradable.getPermImpl(), "invalid caller");
    63          _;
    64      }
    65  
    66      /** @notice checks if account is a valid voter record and belongs to the org
    67          passed
    68        * @param _orgId - org id
    69        * @param _vAccount - voter account passed
    70        */
    71      modifier voterExists(string memory _orgId, address _vAccount) {
    72          require(_checkVoterExists(_orgId, _vAccount) == true, "must be a voter");
    73          _;
    74      }
    75  
    76      /** @notice constructor. sets the permissions upgradable address
    77        */
    78      constructor (address _permUpgradable) public {
    79          permUpgradable = PermissionsUpgradable(_permUpgradable);
    80      }
    81  
    82      /** @notice function to add a new voter account to the organization
    83        * @param _orgId org id
    84        * @param _vAccount - voter account
    85        * @dev voter capability is currently enabled for network level activities
    86          only. voting is not available for org related activities
    87        */
    88      function addVoter(string calldata _orgId, address _vAccount) external
    89      onlyImplementation {
    90          // check if the org exists
    91          if (VoterOrgIndex[keccak256(abi.encode(_orgId))] == 0) {
    92              orgNum++;
    93              VoterOrgIndex[keccak256(abi.encode(_orgId))] = orgNum;
    94              uint256 id = orgVoterList.length++;
    95              orgVoterList[id].orgId = _orgId;
    96              orgVoterList[id].voterCount = 1;
    97              orgVoterList[id].validVoterCount = 1;
    98              orgVoterList[id].voteCount = 0;
    99              orgVoterList[id].pendingOp.orgId = "";
   100              orgVoterList[id].pendingOp.enodeId = "";
   101              orgVoterList[id].pendingOp.account = address(0);
   102              orgVoterList[id].pendingOp.opType = 0;
   103              orgVoterList[id].voterIndex[_vAccount] = orgVoterList[id].voterCount;
   104              orgVoterList[id].voterList.push(Voter(_vAccount, true));
   105          }
   106          else {
   107              uint256 id = _getVoterOrgIndex(_orgId);
   108              // check if the voter is already present in the list
   109              if (orgVoterList[id].voterIndex[_vAccount] == 0) {
   110                  orgVoterList[id].voterCount++;
   111                  orgVoterList[id].voterIndex[_vAccount] = orgVoterList[id].voterCount;
   112                  orgVoterList[id].voterList.push(Voter(_vAccount, true));
   113                  orgVoterList[id].validVoterCount++;
   114              }
   115              else {
   116                  uint256 vid = _getVoterIndex(_orgId, _vAccount);
   117                  require(orgVoterList[id].voterList[vid].active != true, "already a voter");
   118                  orgVoterList[id].voterList[vid].active = true;
   119                  orgVoterList[id].validVoterCount++;
   120              }
   121  
   122          }
   123          emit VoterAdded(_orgId, _vAccount);
   124      }
   125  
   126      /** @notice function to delete a voter account from the organization
   127        * @param _orgId org id
   128        * @param _vAccount - voter account
   129        * @dev voter capability is currently enabled for network level activities
   130          only. voting is not available for org related activities
   131        */
   132      function deleteVoter(string calldata _orgId, address _vAccount) external
   133      onlyImplementation
   134      voterExists(_orgId, _vAccount) {
   135          uint256 id = _getVoterOrgIndex(_orgId);
   136          uint256 vId = _getVoterIndex(_orgId, _vAccount);
   137          orgVoterList[id].validVoterCount --;
   138          orgVoterList[id].voterList[vId].active = false;
   139          emit VoterDeleted(_orgId, _vAccount);
   140      }
   141  
   142      /** @notice function to a voting item for network admin accounts to vote
   143        * @param _authOrg org id of the authorizing org. it will be network admin org
   144        * @param _orgId - org id for which the voting record is being created
   145        * @param _enodeId - enode id for which the voting record is being created
   146        * @param _account - account id for which the voting record is being created
   147        * @param _pendingOp - operation for which voting is being done
   148        */
   149      function addVotingItem(string calldata _authOrg, string calldata _orgId,
   150          string calldata _enodeId, address _account, uint256 _pendingOp)
   151      external onlyImplementation {
   152          // check if anything is pending approval for the org.
   153          // If yes another item cannot be added
   154          require((_checkPendingOp(_authOrg, 0)),
   155              "items pending for approval. new item cannot be added");
   156          uint256 id = _getVoterOrgIndex(_authOrg);
   157          orgVoterList[id].pendingOp.orgId = _orgId;
   158          orgVoterList[id].pendingOp.enodeId = _enodeId;
   159          orgVoterList[id].pendingOp.account = _account;
   160          orgVoterList[id].pendingOp.opType = _pendingOp;
   161          // initialize vote status for voter accounts
   162          for (uint256 i = 0; i < orgVoterList[id].voterList.length; i++) {
   163              if (orgVoterList[id].voterList[i].active) {
   164                  orgVoterList[id].votingStatus[id][orgVoterList[id].voterList[i].vAccount] = false;
   165              }
   166          }
   167          // set vote count to zero
   168          orgVoterList[id].voteCount = 0;
   169          emit VotingItemAdded(_authOrg);
   170  
   171      }
   172  
   173      /** @notice function processing vote of a voter account
   174        * @param _authOrg org id of the authorizing org. it will be network admin org
   175        * @param _vAccount - account id of the voter
   176        * @param _pendingOp - operation which is being approved
   177        * @return success of the voter process. either true or false
   178        */
   179      function processVote(string calldata _authOrg, address _vAccount, uint256 _pendingOp)
   180      external onlyImplementation voterExists(_authOrg, _vAccount) returns (bool) {
   181          // check something if anything is pending approval
   182          require(_checkPendingOp(_authOrg, _pendingOp) == true, "nothing to approve");
   183          uint256 id = _getVoterOrgIndex(_authOrg);
   184          // check if vote is already processed
   185          require(orgVoterList[id].votingStatus[id][_vAccount] != true, "cannot double vote");
   186          orgVoterList[id].voteCount++;
   187          orgVoterList[id].votingStatus[id][_vAccount] = true;
   188          emit VoteProcessed(_authOrg);
   189          if (orgVoterList[id].voteCount > orgVoterList[id].validVoterCount / 2) {
   190              // majority achieved, clean up pending op
   191              orgVoterList[id].pendingOp.orgId = "";
   192              orgVoterList[id].pendingOp.enodeId = "";
   193              orgVoterList[id].pendingOp.account = address(0);
   194              orgVoterList[id].pendingOp.opType = 0;
   195              return true;
   196          }
   197          return false;
   198      }
   199  
   200      /** @notice returns the details of any pending operation to be approved
   201        * @param _orgId org id. this will be the org id of network admin org
   202        */
   203      function getPendingOpDetails(string calldata _orgId) external view
   204      onlyImplementation returns (string memory, string memory, address, uint256){
   205          uint256 orgIndex = _getVoterOrgIndex(_orgId);
   206          return (orgVoterList[orgIndex].pendingOp.orgId, orgVoterList[orgIndex].pendingOp.enodeId,
   207          orgVoterList[orgIndex].pendingOp.account, orgVoterList[orgIndex].pendingOp.opType);
   208      }
   209  
   210      /** @notice checks if the voter account exists and is linked to the org
   211        * @param _orgId org id
   212        * @param _vAccount voter account id
   213        * @return true or false
   214        */
   215      function _checkVoterExists(string memory _orgId, address _vAccount)
   216      internal view returns (bool){
   217          uint256 orgIndex = _getVoterOrgIndex(_orgId);
   218          if (orgVoterList[orgIndex].voterIndex[_vAccount] == 0) {
   219              return false;
   220          }
   221          uint256 voterIndex = _getVoterIndex(_orgId, _vAccount);
   222          return orgVoterList[orgIndex].voterList[voterIndex].active;
   223      }
   224  
   225      /** @notice checks if the pending operation exists or not
   226        * @param _orgId org id
   227        * @param _pendingOp type of operation
   228        * @return true or false
   229        */
   230      function _checkPendingOp(string memory _orgId, uint256 _pendingOp)
   231      internal view returns (bool){
   232          return (orgVoterList[_getVoterOrgIndex(_orgId)].pendingOp.opType == _pendingOp);
   233      }
   234  
   235      /** @notice returns the voter account index
   236        */
   237      function _getVoterIndex(string memory _orgId, address _vAccount)
   238      internal view returns (uint256) {
   239          uint256 orgIndex = _getVoterOrgIndex(_orgId);
   240          return orgVoterList[orgIndex].voterIndex[_vAccount] - 1;
   241      }
   242  
   243      /** @notice returns the org index for the org from voter list
   244        */
   245      function _getVoterOrgIndex(string memory _orgId)
   246      internal view returns (uint256) {
   247          return VoterOrgIndex[keccak256(abi.encode(_orgId))] - 1;
   248      }
   249  
   250  }