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 }