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 }