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 }