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

     1  pragma solidity ^0.5.3;
     2  
     3  import "./PermissionsUpgradable.sol";
     4  /** @title Node manager contract
     5    * @notice This contract holds implementation logic for all node management
     6      functionality. This can be called only by the implementation contract.
     7      There are few view functions exposed as public and can be called directly.
     8      These are invoked by quorum for populating permissions data in cache
     9    * @dev node status is denoted by a fixed integer value. The values are
    10      as below:
    11          0 - Not in list
    12          1 - Node pending approval
    13          2 - Active
    14          3 - Deactivated
    15          4 - Blacklisted
    16          5 - Blacklisted node recovery initiated. Once approved the node
    17              status will be updated to Active (2)
    18       Once the node is blacklisted no further activity on the node is
    19       possible.
    20    */
    21  contract NodeManager {
    22      PermissionsUpgradable private permUpgradable;
    23      struct NodeDetails {
    24          string enodeId; //e.g. 127.0.0.1:20005
    25          string orgId;
    26          uint256 status;
    27      }
    28      // use an array to store node details
    29      // if we want to list all node one day, mapping is not capable
    30      NodeDetails[] private nodeList;
    31      // mapping of enodeid to array index to track node
    32      mapping(bytes32 => uint256) private nodeIdToIndex;
    33      // tracking total number of nodes in network
    34      uint256 private numberOfNodes;
    35  
    36  
    37      // node permission events for new node propose
    38      event NodeProposed(string _enodeId, string _orgId);
    39      event NodeApproved(string _enodeId, string _orgId);
    40  
    41      // node permission events for node deactivation
    42      event NodeDeactivated(string _enodeId, string _orgId);
    43  
    44      // node permission events for node activation
    45      event NodeActivated(string _enodeId, string _orgId);
    46  
    47      // node permission events for node blacklist
    48      event NodeBlacklisted(string _enodeId, string _orgId);
    49  
    50      // node permission events for initiating the recovery of blacklisted
    51      // node
    52      event NodeRecoveryInitiated(string _enodeId, string _orgId);
    53  
    54      // node permission events for completing the recovery of blacklisted
    55      // node
    56      event NodeRecoveryCompleted(string _enodeId, 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 the node exists in the network
    67        * @param _enodeId full enode id
    68        */
    69      modifier enodeExists(string memory _enodeId) {
    70          require(nodeIdToIndex[keccak256(abi.encode(_enodeId))] != 0,
    71              "passed enode id does not exist");
    72          _;
    73      }
    74  
    75      /** @notice  checks if the node does not exist in the network
    76        * @param _enodeId full enode id
    77        */
    78      modifier enodeDoesNotExists(string memory _enodeId) {
    79          require(nodeIdToIndex[keccak256(abi.encode(_enodeId))] == 0,
    80              "passed enode id exists");
    81          _;
    82      }
    83  
    84      /** @notice constructor. sets the permissions upgradable address
    85        */
    86      constructor (address _permUpgradable) public {
    87          permUpgradable = PermissionsUpgradable(_permUpgradable);
    88      }
    89  
    90      /** @notice fetches the node details given an enode id
    91        * @param _enodeId full enode id
    92        * @return org id
    93        * @return enode id
    94        * @return status of the node
    95        */
    96      function getNodeDetails(string calldata enodeId) external view
    97      returns (string memory _orgId, string memory _enodeId, uint256 _nodeStatus) {
    98          if (nodeIdToIndex[keccak256(abi.encode(_enodeId))] == 0) {
    99              return ("", enodeId, 0);
   100          }
   101          uint256 nodeIndex = _getNodeIndex(enodeId);
   102          return (nodeList[nodeIndex].orgId, nodeList[nodeIndex].enodeId,
   103          nodeList[nodeIndex].status);
   104      }
   105  
   106      /** @notice fetches the node details given the index of the enode
   107        * @param _nodeIndex node index
   108        * @return org id
   109        * @return enode id
   110        * @return status of the node
   111        */
   112      function getNodeDetailsFromIndex(uint256 _nodeIndex) external view
   113      returns (string memory _orgId, string memory _enodeId, uint256 _nodeStatus) {
   114          return (nodeList[_nodeIndex].orgId, nodeList[_nodeIndex].enodeId,
   115          nodeList[_nodeIndex].status);
   116      }
   117  
   118      /** @notice returns the total number of enodes in the network
   119        * @return number of nodes
   120        */
   121      function getNumberOfNodes() external view returns (uint256) {
   122          return numberOfNodes;
   123      }
   124  
   125      /** @notice called at the time of network initialization for adding
   126          admin nodes
   127        * @param _enodeId enode id
   128        * @param _orgId org id to which the enode belongs
   129        */
   130      function addAdminNode(string calldata _enodeId, string calldata _orgId) external
   131      onlyImplementation
   132      enodeDoesNotExists(_enodeId) {
   133          numberOfNodes++;
   134          nodeIdToIndex[keccak256(abi.encode(_enodeId))] = numberOfNodes;
   135          nodeList.push(NodeDetails(_enodeId, _orgId, 2));
   136          emit NodeApproved(_enodeId, _orgId);
   137      }
   138  
   139      /** @notice called at the time of new org creation to add node to org
   140        * @param _enodeId enode id
   141        * @param _orgId org id to which the enode belongs
   142        */
   143      function addNode(string calldata _enodeId, string calldata _orgId) external
   144      onlyImplementation
   145      enodeDoesNotExists(_enodeId) {
   146          numberOfNodes++;
   147          nodeIdToIndex[keccak256(abi.encode(_enodeId))] = numberOfNodes;
   148          nodeList.push(NodeDetails(_enodeId, _orgId, 1));
   149          emit NodeProposed(_enodeId, _orgId);
   150      }
   151  
   152      /** @notice called org admins to add new enodes to the org or sub orgs
   153        * @param _enodeId enode id
   154        * @param _orgId org or sub org id to which the enode belongs
   155        */
   156      function addOrgNode(string calldata _enodeId, string calldata _orgId) external
   157      onlyImplementation
   158      enodeDoesNotExists(_enodeId) {
   159          numberOfNodes++;
   160          nodeIdToIndex[keccak256(abi.encode(_enodeId))] = numberOfNodes;
   161          nodeList.push(NodeDetails(_enodeId, _orgId, 2));
   162          emit NodeApproved(_enodeId, _orgId);
   163      }
   164  
   165      /** @notice function to approve the node addition. only called at the time
   166          master org creation by network admin
   167        * @param _enodeId enode id
   168        * @param _orgId org or sub org id to which the enode belongs
   169        */
   170      function approveNode(string calldata _enodeId, string calldata _orgId) external
   171      onlyImplementation
   172      enodeExists(_enodeId) {
   173          // node should belong to the passed org
   174          require(_checkOrg(_enodeId, _orgId), "enode id does not belong to the passed org id");
   175          require(_getNodeStatus(_enodeId) == 1, "nothing pending for approval");
   176          uint256 nodeIndex = _getNodeIndex(_enodeId);
   177          nodeList[nodeIndex].status = 2;
   178          emit NodeApproved(nodeList[nodeIndex].enodeId, nodeList[nodeIndex].orgId);
   179      }
   180  
   181      /** @notice updates the node status. can be called for deactivating/
   182          blacklisting  and reactivating a deactivated node
   183        * @param _enodeId enode id
   184        * @param _orgId org or sub org id to which the enode belong
   185        * @param _action action being performed
   186        * @dev action can have any of the following values
   187              1 - Suspend the node
   188              2 - Revoke suspension of a suspended node
   189              3 - blacklist a node
   190              4 - initiate the recovery of a blacklisted node
   191              5 - blacklisted node recovery fully approved. mark to active
   192        */
   193      function updateNodeStatus(string calldata _enodeId, string calldata _orgId, uint256 _action) external
   194      onlyImplementation
   195      enodeExists(_enodeId) {
   196          // node should belong to the org
   197          require(_checkOrg(_enodeId, _orgId), "enode id does not belong to the passed org");
   198          require((_action == 1 || _action == 2 || _action == 3 || _action == 4 || _action == 5),
   199              "invalid operation. wrong action passed");
   200  
   201          if (_action == 1) {
   202              require(_getNodeStatus(_enodeId) == 2, "operation cannot be performed");
   203              nodeList[_getNodeIndex(_enodeId)].status = 3;
   204              emit NodeDeactivated(_enodeId, _orgId);
   205          }
   206          else if (_action == 2) {
   207              require(_getNodeStatus(_enodeId) == 3, "operation cannot be performed");
   208              nodeList[_getNodeIndex(_enodeId)].status = 2;
   209              emit NodeActivated(_enodeId, _orgId);
   210          }
   211          else if (_action == 3) {
   212              nodeList[_getNodeIndex(_enodeId)].status = 4;
   213              emit NodeBlacklisted(_enodeId, _orgId);
   214          } else if (_action == 4) {
   215              // node should be in blacklisted state
   216              require(_getNodeStatus(_enodeId) == 4, "operation cannot be performed");
   217              nodeList[_getNodeIndex(_enodeId)].status = 5;
   218              emit NodeRecoveryInitiated(_enodeId, _orgId);
   219          } else {
   220              // node should be in initiated recovery state
   221              require(_getNodeStatus(_enodeId) == 5, "operation cannot be performed");
   222              nodeList[_getNodeIndex(_enodeId)].status = 2;
   223              emit NodeRecoveryCompleted(_enodeId, _orgId);
   224          }
   225      }
   226  
   227      // private functions
   228      /** @notice returns the node index for given enode id
   229        * @param _enodeId enode id
   230        * @return trur or false
   231        */
   232      function _getNodeIndex(string memory _enodeId) internal view
   233      returns (uint256) {
   234          return nodeIdToIndex[keccak256(abi.encode(_enodeId))] - 1;
   235      }
   236  
   237      /** @notice checks if enode id is linked to the org id passed
   238        * @param _enodeId enode id
   239        * @param _orgId org or sub org id to which the enode belongs
   240        * @return true or false
   241        */
   242      function _checkOrg(string memory _enodeId, string memory _orgId) internal view
   243      returns (bool) {
   244          return (keccak256(abi.encode(nodeList[_getNodeIndex(_enodeId)].orgId)) == keccak256(abi.encode(_orgId)));
   245      }
   246  
   247      /** @notice returns the node status for a given enode id
   248        * @param _enodeId enode id
   249        * @return node status
   250        */
   251      function _getNodeStatus(string memory _enodeId) internal view returns (uint256) {
   252          if (nodeIdToIndex[keccak256(abi.encode(_enodeId))] == 0) {
   253              return 0;
   254          }
   255          return nodeList[_getNodeIndex(_enodeId)].status;
   256      }
   257  }