github.com/kisexp/xdchain@v0.0.0-20211206025815-490d6b732aa7/permission/v2/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  
    24      struct NodeDetails {
    25          string enodeId;
    26          string ip;
    27          uint16 port;
    28          uint16 raftPort;
    29          string orgId;
    30          uint256 status;
    31      }
    32      // use an array to store node details
    33      // if we want to list all node one day, mapping is not capable
    34      NodeDetails[] private nodeList;
    35      // mapping of enode id to array index to track node
    36      mapping(bytes32 => uint256) private nodeIdToIndex;
    37      // mapping of enodeId to array index to track node
    38      mapping(bytes32 => uint256) private enodeIdToIndex;
    39      // tracking total number of nodes in network
    40      uint256 private numberOfNodes;
    41  
    42  
    43      // node permission events for new node propose
    44      event NodeProposed(string _enodeId, string _ip, uint16 _port, uint16 _raftport, string _orgId);
    45      event NodeApproved(string _enodeId, string _ip, uint16 _port, uint16 _raftport, string _orgId);
    46  
    47      // node permission events for node deactivation
    48      event NodeDeactivated(string _enodeId, string _ip, uint16 _port, uint16 _raftport, string _orgId);
    49  
    50      // node permission events for node activation
    51      event NodeActivated(string _enodeId, string _ip, uint16 _port, uint16 _raftport, string _orgId);
    52  
    53      // node permission events for node blacklist
    54      event NodeBlacklisted(string _enodeId, string _ip, uint16 _port, uint16 _raftport, string _orgId);
    55  
    56      // node permission events for initiating the recovery of blacklisted
    57      // node
    58      event NodeRecoveryInitiated(string _enodeId, string _ip, uint16 _port, uint16 _raftport, string _orgId);
    59  
    60      // node permission events for completing the recovery of blacklisted
    61      // node
    62      event NodeRecoveryCompleted(string _enodeId, string _ip, uint16 _port, uint16 _raftport, string _orgId);
    63  
    64      /** @notice confirms that the caller is the address of implementation
    65          contract
    66      */
    67      modifier onlyImplementation {
    68          require(msg.sender == permUpgradable.getPermImpl(), "invalid caller");
    69          _;
    70      }
    71  
    72      /** @notice  checks if the node exists in the network
    73        * @param _enodeId full enode id
    74        */
    75      modifier enodeExists(string memory _enodeId) {
    76          require(enodeIdToIndex[keccak256(abi.encode(_enodeId))] != 0,
    77              "passed enode id does not exist");
    78          _;
    79      }
    80  
    81      /** @notice  checks if the node does not exist in the network
    82        * @param _enodeId full enode id
    83        */
    84      modifier enodeDoesNotExists(string memory _enodeId) {
    85          require(enodeIdToIndex[keccak256(abi.encode(_enodeId))] == 0,
    86              "passed enode id exists");
    87          _;
    88      }
    89  
    90      /** @notice constructor. sets the permissions upgradable address
    91        */
    92      constructor (address _permUpgradable) public {
    93          permUpgradable = PermissionsUpgradable(_permUpgradable);
    94      }
    95  
    96      /** @notice fetches the node details given an enode id
    97        * @param _enodeId full enode id
    98        * @return org id
    99        * @return enode id
   100        * @return status of the node
   101        */
   102      function getNodeDetails(string calldata enodeId) external view
   103      returns (string memory _orgId, string memory _enodeId, string memory _ip, uint16 _port, uint16 _raftport, uint256 _nodeStatus) {
   104          if (nodeIdToIndex[keccak256(abi.encode(_enodeId))] == 0) {
   105              return ("", "", "", 0, 0, 0);
   106          }
   107          uint256 nodeIndex = _getNodeIndex(enodeId);
   108          return (nodeList[nodeIndex].orgId, nodeList[nodeIndex].enodeId, nodeList[nodeIndex].ip,
   109          nodeList[nodeIndex].port, nodeList[nodeIndex].raftPort,
   110          nodeList[nodeIndex].status);
   111      }
   112  
   113      /** @notice fetches the node details given the index of the enode
   114        * @param _nodeIndex node index
   115        * @return org id
   116        * @return enode id
   117        * @return ip of the node
   118        * @return port of the node
   119        * @return raftport of the node
   120        * @return status of the node
   121        */
   122      function getNodeDetailsFromIndex(uint256 _nodeIndex) external view
   123      returns (string memory _orgId, string memory _enodeId, string memory _ip, uint16 _port, uint16 _raftport, uint256 _nodeStatus) {
   124          return (nodeList[_nodeIndex].orgId, nodeList[_nodeIndex].enodeId, nodeList[_nodeIndex].ip,
   125          nodeList[_nodeIndex].port, nodeList[_nodeIndex].raftPort,
   126          nodeList[_nodeIndex].status);
   127      }
   128  
   129      /** @notice returns the total number of enodes in the network
   130        * @return number of nodes
   131        */
   132      function getNumberOfNodes() external view returns (uint256) {
   133          return numberOfNodes;
   134      }
   135  
   136      /** @notice called at the time of network initialization for adding
   137          admin nodes
   138        * @param _enodeId enode id
   139        * @param _ip IP of node
   140        * @param _port tcp port of node
   141        * @param _raftport raft port of node
   142        * @param _orgId org id to which the enode belongs
   143        */
   144      function addAdminNode(string memory _enodeId, string memory _ip, uint16 _port, uint16 _raftport, string memory _orgId) public
   145      onlyImplementation
   146      enodeDoesNotExists(_enodeId) {
   147          numberOfNodes++;
   148          enodeIdToIndex[keccak256(abi.encode(_enodeId))] = numberOfNodes;
   149          nodeList.push(NodeDetails(_enodeId, _ip, _port, _raftport, _orgId, 2));
   150          emit NodeApproved(_enodeId, _ip, _port, _raftport, _orgId);
   151      }
   152  
   153      /** @notice called at the time of new org creation to add node to org
   154        * @param _enodeId enode id
   155        * @param _ip IP of node
   156        * @param _port tcp port of node
   157        * @param _raftport raft port of node
   158        * @param _orgId org id to which the enode belongs
   159        */
   160      function addNode(string memory _enodeId, string memory _ip, uint16 _port, uint16 _raftport, string memory _orgId) public
   161      onlyImplementation
   162      enodeDoesNotExists(_enodeId) {
   163          numberOfNodes++;
   164          enodeIdToIndex[keccak256(abi.encode(_enodeId))] = numberOfNodes;
   165          nodeList.push(NodeDetails(_enodeId, _ip, _port, _raftport, _orgId, 1));
   166          emit NodeProposed(_enodeId, _ip, _port, _raftport, _orgId);
   167      }
   168  
   169      /** @notice called org admins to add new enodes to the org or sub orgs
   170        * @param _enodeId enode id
   171        * @param _ip IP of node
   172        * @param _port tcp port of node
   173        * @param _raftport raft port of node
   174        * @param _orgId org or sub org id to which the enode belongs
   175        */
   176      function addOrgNode(string memory _enodeId, string memory _ip, uint16 _port, uint16 _raftport, string memory _orgId) public
   177      onlyImplementation
   178      enodeDoesNotExists(_enodeId) {
   179          numberOfNodes++;
   180          enodeIdToIndex[keccak256(abi.encode(_enodeId))] = numberOfNodes;
   181          nodeList.push(NodeDetails(_enodeId, _ip, _port, _raftport, _orgId, 2));
   182          emit NodeApproved(_enodeId, _ip, _port, _raftport, _orgId);
   183      }
   184  
   185      /** @notice function to approve the node addition. only called at the time
   186          master org creation by network admin
   187        * @param _enodeId enode id
   188        * @param _ip IP of node
   189        * @param _port tcp port of node
   190        * @param _raftport raft port of node
   191        * @param _orgId org or sub org id to which the enode belongs
   192        */
   193      function approveNode(string memory _enodeId, string memory _ip, uint16 _port, uint16 _raftport, string memory _orgId) public
   194      onlyImplementation
   195      enodeExists(_enodeId) {
   196          // node should belong to the passed org
   197          require(_checkOrg(_enodeId, _orgId), "enode id does not belong to the passed org id");
   198          require(_getNodeStatus(_enodeId) == 1, "nothing pending for approval");
   199          uint256 nodeIndex = _getNodeIndex(_enodeId);
   200          if (keccak256(abi.encode(nodeList[nodeIndex].ip)) != keccak256(abi.encode(_ip)) || nodeList[nodeIndex].port != _port || nodeList[nodeIndex].raftPort != _raftport) {
   201              return;
   202          }
   203          nodeList[nodeIndex].status = 2;
   204          emit NodeApproved(nodeList[nodeIndex].enodeId, _ip, _port, _raftport, nodeList[nodeIndex].orgId);
   205      }
   206  
   207      /** @notice updates the node status. can be called for deactivating/
   208          blacklisting  and reactivating a deactivated node
   209        * @param _enodeId enode id
   210        * @param _ip IP of node
   211        * @param _port tcp port of node
   212        * @param _raftport raft port of node
   213        * @param _orgId org or sub org id to which the enode belong
   214        * @param _action action being performed
   215        * @dev action can have any of the following values
   216              1 - Suspend the node
   217              2 - Revoke suspension of a suspended node
   218              3 - blacklist a node
   219              4 - initiate the recovery of a blacklisted node
   220              5 - blacklisted node recovery fully approved. mark to active
   221        */
   222      function updateNodeStatus(string memory _enodeId, string memory _ip, uint16 _port, uint16 _raftport, string memory _orgId, uint256 _action) public
   223      onlyImplementation
   224      enodeExists(_enodeId) {
   225          // node should belong to the org
   226          require(_checkOrg(_enodeId, _orgId), "enode id does not belong to the passed org");
   227          require((_action == 1 || _action == 2 || _action == 3 || _action == 4 || _action == 5),
   228              "invalid operation. wrong action passed");
   229  
   230          uint256 nodeIndex = _getNodeIndex(_enodeId);
   231          if (keccak256(abi.encode(nodeList[nodeIndex].ip)) != keccak256(abi.encode(_ip)) || nodeList[nodeIndex].port != _port || nodeList[nodeIndex].raftPort != _raftport) {
   232              return;
   233          }
   234  
   235          if (_action == 1) {
   236              require(_getNodeStatus(_enodeId) == 2, "operation cannot be performed");
   237              nodeList[nodeIndex].status = 3;
   238              emit NodeDeactivated(_enodeId, _ip, _port, _raftport, _orgId);
   239          }
   240          else if (_action == 2) {
   241              require(_getNodeStatus(_enodeId) == 3, "operation cannot be performed");
   242              nodeList[nodeIndex].status = 2;
   243              emit NodeActivated(_enodeId, _ip, _port, _raftport, _orgId);
   244          }
   245          else if (_action == 3) {
   246              nodeList[nodeIndex].status = 4;
   247              emit NodeBlacklisted(_enodeId, _ip, _port, _raftport, _orgId);
   248          } else if (_action == 4) {
   249              // node should be in blacklisted state
   250              require(_getNodeStatus(_enodeId) == 4, "operation cannot be performed");
   251              nodeList[nodeIndex].status = 5;
   252              emit NodeRecoveryInitiated(_enodeId, _ip, _port, _raftport, _orgId);
   253          } else {
   254              // node should be in initiated recovery state
   255              require(_getNodeStatus(_enodeId) == 5, "operation cannot be performed");
   256              nodeList[nodeIndex].status = 2;
   257              emit NodeRecoveryCompleted(_enodeId, _ip, _port, _raftport, _orgId);
   258          }
   259      }
   260  
   261      // private functions
   262      /** @notice returns the node index for given enode id
   263        * @param _enodeId enode id
   264        * @return trur or false
   265        */
   266      function _getNodeIndex(string memory _enodeId) internal view
   267      returns (uint256) {
   268          return enodeIdToIndex[keccak256(abi.encode(_enodeId))] - 1;
   269      }
   270  
   271      /** @notice checks if enode id is linked to the org id passed
   272        * @param _enodeId enode id
   273        * @param _orgId org or sub org id to which the enode belongs
   274        * @return true or false
   275        */
   276      function _checkOrg(string memory _enodeId, string memory _orgId) internal view
   277      returns (bool) {
   278          return (keccak256(abi.encode(nodeList[_getNodeIndex(_enodeId)].orgId)) == keccak256(abi.encode(_orgId)));
   279      }
   280  
   281      /** @notice returns the node status for a given enode id
   282        * @param _enodeId enode id
   283        * @return node status
   284        */
   285      function _getNodeStatus(string memory _enodeId) internal view returns (uint256) {
   286          if (enodeIdToIndex[keccak256(abi.encode(_enodeId))] == 0) {
   287              return 0;
   288          }
   289          return nodeList[_getNodeIndex(_enodeId)].status;
   290      }
   291  
   292      /** @notice checks if the node is allowed to connect or not
   293      * @param _enodeId enode id
   294      * @param _ip IP of node
   295      * @param _port tcp port of node
   296      * @return bool indicating if the node is allowed to connect or not
   297      */
   298      function connectionAllowed(string memory _enodeId, string memory _ip, uint16 _port) public view onlyImplementation
   299      returns (bool){
   300          if (enodeIdToIndex[keccak256(abi.encode(_enodeId))] == 0) {
   301              return false;
   302          }
   303          uint256 nodeIndex = _getNodeIndex(_enodeId);
   304          if (nodeList[nodeIndex].status == 2 && keccak256(abi.encode(nodeList[nodeIndex].ip)) == keccak256(abi.encode(_ip))) {
   305              return true;
   306          }
   307  
   308          return false;
   309      }
   310  }