github.com/hyperion-hyn/go-ethereum@v2.4.0+incompatible/permission/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          uint256 nodeIndex = _getNodeIndex(enodeId);
    99          return (nodeList[nodeIndex].orgId, nodeList[nodeIndex].enodeId,
   100          nodeList[nodeIndex].status);
   101      }
   102  
   103      /** @notice fetches the node details given the index of the enode
   104        * @param _nodeIndex node index
   105        * @return org id
   106        * @return enode id
   107        * @return status of the node
   108        */
   109      function getNodeDetailsFromIndex(uint256 _nodeIndex) external view
   110      returns (string memory _orgId, string memory _enodeId, uint256 _nodeStatus) {
   111          return (nodeList[_nodeIndex].orgId, nodeList[_nodeIndex].enodeId,
   112          nodeList[_nodeIndex].status);
   113      }
   114  
   115      /** @notice returns the total number of enodes in the network
   116        * @return number of nodes
   117        */
   118      function getNumberOfNodes() external view returns (uint256) {
   119          return numberOfNodes;
   120      }
   121  
   122      /** @notice called at the time of network initialization for adding
   123          admin nodes
   124        * @param _enodeId enode id
   125        * @param _orgId org id to which the enode belongs
   126        */
   127      function addAdminNode(string calldata _enodeId, string calldata _orgId) external
   128      onlyImplementation
   129      enodeDoesNotExists(_enodeId) {
   130          numberOfNodes++;
   131          nodeIdToIndex[keccak256(abi.encode(_enodeId))] = numberOfNodes;
   132          nodeList.push(NodeDetails(_enodeId, _orgId, 2));
   133          emit NodeApproved(_enodeId, _orgId);
   134      }
   135  
   136      /** @notice called at the time of new org creation to add node to org
   137        * @param _enodeId enode id
   138        * @param _orgId org id to which the enode belongs
   139        */
   140      function addNode(string calldata _enodeId, string calldata _orgId) external
   141      onlyImplementation
   142      enodeDoesNotExists(_enodeId) {
   143          numberOfNodes++;
   144          nodeIdToIndex[keccak256(abi.encode(_enodeId))] = numberOfNodes;
   145          nodeList.push(NodeDetails(_enodeId, _orgId, 1));
   146          emit NodeProposed(_enodeId, _orgId);
   147      }
   148  
   149      /** @notice called org admins to add new enodes to the org or sub orgs
   150        * @param _enodeId enode id
   151        * @param _orgId org or sub org id to which the enode belongs
   152        */
   153      function addOrgNode(string calldata _enodeId, string calldata _orgId) external
   154      onlyImplementation
   155      enodeDoesNotExists(_enodeId) {
   156          numberOfNodes++;
   157          nodeIdToIndex[keccak256(abi.encode(_enodeId))] = numberOfNodes;
   158          nodeList.push(NodeDetails(_enodeId, _orgId, 2));
   159          emit NodeApproved(_enodeId, _orgId);
   160      }
   161  
   162      /** @notice function to approve the node addition. only called at the time
   163          master org creation by network admin
   164        * @param _enodeId enode id
   165        * @param _orgId org or sub org id to which the enode belongs
   166        */
   167      function approveNode(string calldata _enodeId, string calldata _orgId) external
   168      onlyImplementation
   169      enodeExists(_enodeId) {
   170          // node should belong to the passed org
   171          require(_checkOrg(_enodeId, _orgId), "enode id does not belong to the passed org id");
   172          require(_getNodeStatus(_enodeId) == 1, "nothing pending for approval");
   173          uint256 nodeIndex = _getNodeIndex(_enodeId);
   174          nodeList[nodeIndex].status = 2;
   175          emit NodeApproved(nodeList[nodeIndex].enodeId, nodeList[nodeIndex].orgId);
   176      }
   177  
   178      /** @notice updates the node status. can be called for deactivating/
   179          blacklisting  and reactivating a deactivated node
   180        * @param _enodeId enode id
   181        * @param _orgId org or sub org id to which the enode belong
   182        * @param _action action being performed
   183        * @dev action can have any of the following values
   184              1 - Suspend the node
   185              2 - Revoke suspension of a suspended node
   186              3 - blacklist a node
   187              4 - initiate the recovery of a blacklisted node
   188              5 - blacklisted node recovery fully approved. mark to active
   189        */
   190      function updateNodeStatus(string calldata _enodeId, string calldata _orgId, uint256 _action) external
   191      onlyImplementation
   192      enodeExists(_enodeId) {
   193          // node should belong to the org
   194          require(_checkOrg(_enodeId, _orgId), "enode id does not belong to the passed org");
   195          require((_action == 1 || _action == 2 || _action == 3 || _action == 4 || _action == 5),
   196              "invalid operation. wrong action passed");
   197  
   198          if (_action == 1) {
   199              require(_getNodeStatus(_enodeId) == 2, "operation cannot be performed");
   200              nodeList[_getNodeIndex(_enodeId)].status = 3;
   201              emit NodeDeactivated(_enodeId, _orgId);
   202          }
   203          else if (_action == 2) {
   204              require(_getNodeStatus(_enodeId) == 3, "operation cannot be performed");
   205              nodeList[_getNodeIndex(_enodeId)].status = 2;
   206              emit NodeActivated(_enodeId, _orgId);
   207          }
   208          else if (_action == 3) {
   209              nodeList[_getNodeIndex(_enodeId)].status = 4;
   210              emit NodeBlacklisted(_enodeId, _orgId);
   211          } else if (_action == 4) {
   212              // node should be in blacklisted state
   213              require(_getNodeStatus(_enodeId) == 4, "operation cannot be performed");
   214              nodeList[_getNodeIndex(_enodeId)].status = 5;
   215              emit NodeRecoveryInitiated(_enodeId, _orgId);
   216          } else {
   217              // node should be in initiated recovery state
   218              require(_getNodeStatus(_enodeId) == 5, "operation cannot be performed");
   219              nodeList[_getNodeIndex(_enodeId)].status = 2;
   220              emit NodeRecoveryCompleted(_enodeId, _orgId);
   221          }
   222      }
   223  
   224      // private functions
   225      /** @notice returns the node index for given enode id
   226        * @param _enodeId enode id
   227        * @return trur or false
   228        */
   229      function _getNodeIndex(string memory _enodeId) internal view
   230      returns (uint256) {
   231          return nodeIdToIndex[keccak256(abi.encode(_enodeId))] - 1;
   232      }
   233  
   234      /** @notice checks if enode id is linked to the org id passed
   235        * @param _enodeId enode id
   236        * @param _orgId org or sub org id to which the enode belongs
   237        * @return true or false
   238        */
   239      function _checkOrg(string memory _enodeId, string memory _orgId) internal view
   240      returns (bool) {
   241          return (keccak256(abi.encode(nodeList[_getNodeIndex(_enodeId)].orgId)) == keccak256(abi.encode(_orgId)));
   242      }
   243  
   244      /** @notice returns the node status for a given enode id
   245        * @param _enodeId enode id
   246        * @return node status
   247        */
   248      function _getNodeStatus(string memory _enodeId) internal view returns (uint256) {
   249          if (nodeIdToIndex[keccak256(abi.encode(_enodeId))] == 0) {
   250              return 0;
   251          }
   252          return nodeList[_getNodeIndex(_enodeId)].status;
   253      }
   254  }