2019-03-14 23:41:04 -07:00
|
|
|
pragma solidity ^0.5.3;
|
2019-05-08 20:07:54 -07:00
|
|
|
|
2019-03-15 02:26:57 -07:00
|
|
|
import "./PermissionsUpgradable.sol";
|
2019-07-30 01:56:44 -07:00
|
|
|
/** @title Node manager contract
|
|
|
|
* @notice This contract holds implementation logic for all node management
|
|
|
|
functionality. This can be called only by the implementation contract.
|
|
|
|
There are few view functions exposed as public and can be called directly.
|
|
|
|
These are invoked by quorum for populating permissions data in cache
|
|
|
|
* @dev node status is denoted by a fixed integer value. The values are
|
|
|
|
as below:
|
|
|
|
0 - Not in list
|
|
|
|
1 - Node pending approval
|
|
|
|
2 - Active
|
|
|
|
3 - Deactivated
|
|
|
|
4 - Blacklisted
|
2019-07-31 20:10:50 -07:00
|
|
|
5 - Blacklisted node recovery initiated. Once approved the node
|
|
|
|
status will be updated to Active (2)
|
2019-07-30 01:56:44 -07:00
|
|
|
Once the node is blacklisted no further activity on the node is
|
|
|
|
possible.
|
|
|
|
*/
|
2019-03-14 23:41:04 -07:00
|
|
|
contract NodeManager {
|
2019-03-19 02:15:51 -07:00
|
|
|
PermissionsUpgradable private permUpgradable;
|
2019-03-14 23:41:04 -07:00
|
|
|
struct NodeDetails {
|
|
|
|
string enodeId; //e.g. 127.0.0.1:20005
|
|
|
|
string orgId;
|
2019-07-21 20:25:14 -07:00
|
|
|
uint256 status;
|
2019-03-14 23:41:04 -07:00
|
|
|
}
|
|
|
|
// use an array to store node details
|
|
|
|
// if we want to list all node one day, mapping is not capable
|
|
|
|
NodeDetails[] private nodeList;
|
2019-07-19 01:48:42 -07:00
|
|
|
// mapping of enodeid to array index to track node
|
2019-07-21 20:25:14 -07:00
|
|
|
mapping(bytes32 => uint256) private nodeIdToIndex;
|
2019-07-19 01:48:42 -07:00
|
|
|
// tracking total number of nodes in network
|
2019-07-21 20:25:14 -07:00
|
|
|
uint256 private numberOfNodes;
|
2019-03-14 23:41:04 -07:00
|
|
|
|
|
|
|
|
|
|
|
// node permission events for new node propose
|
2019-03-28 19:51:16 -07:00
|
|
|
event NodeProposed(string _enodeId, string _orgId);
|
|
|
|
event NodeApproved(string _enodeId, string _orgId);
|
2019-03-14 23:41:04 -07:00
|
|
|
|
2019-03-28 21:28:11 -07:00
|
|
|
// node permission events for node deactivation
|
2019-03-28 19:51:16 -07:00
|
|
|
event NodeDeactivated(string _enodeId, string _orgId);
|
2019-03-14 23:41:04 -07:00
|
|
|
|
|
|
|
// node permission events for node activation
|
2019-03-28 19:51:16 -07:00
|
|
|
event NodeActivated(string _enodeId, string _orgId);
|
2019-03-14 23:41:04 -07:00
|
|
|
|
|
|
|
// node permission events for node blacklist
|
2019-03-28 19:51:16 -07:00
|
|
|
event NodeBlacklisted(string _enodeId, string _orgId);
|
2019-03-14 23:41:04 -07:00
|
|
|
|
2019-07-31 20:10:50 -07:00
|
|
|
// node permission events for initiating the recovery of blacklisted
|
|
|
|
// node
|
|
|
|
event NodeRecoveryInitiated(string _enodeId, string _orgId);
|
|
|
|
|
2019-08-01 00:19:40 -07:00
|
|
|
// node permission events for completing the recovery of blacklisted
|
|
|
|
// node
|
|
|
|
event NodeRecoveryCompleted(string _enodeId, string _orgId);
|
|
|
|
|
2019-07-30 01:56:44 -07:00
|
|
|
/** @notice confirms that the caller is the address of implementation
|
|
|
|
contract
|
|
|
|
*/
|
2019-07-19 01:16:50 -07:00
|
|
|
modifier onlyImplementation {
|
2019-07-21 20:17:39 -07:00
|
|
|
require(msg.sender == permUpgradable.getPermImpl(), "invalid caller");
|
2019-03-15 02:26:57 -07:00
|
|
|
_;
|
|
|
|
}
|
|
|
|
|
2019-07-30 01:56:44 -07:00
|
|
|
/** @notice checks if the node exists in the network
|
|
|
|
* @param _enodeId full enode id
|
|
|
|
*/
|
2019-07-19 01:16:50 -07:00
|
|
|
modifier enodeExists(string memory _enodeId) {
|
|
|
|
require(nodeIdToIndex[keccak256(abi.encode(_enodeId))] != 0,
|
|
|
|
"passed enode id does not exist");
|
2019-03-14 23:41:04 -07:00
|
|
|
_;
|
|
|
|
}
|
|
|
|
|
2019-07-30 01:56:44 -07:00
|
|
|
/** @notice checks if the node does not exist in the network
|
|
|
|
* @param _enodeId full enode id
|
|
|
|
*/
|
2019-07-19 01:16:50 -07:00
|
|
|
modifier enodeDoesNotExists(string memory _enodeId) {
|
|
|
|
require(nodeIdToIndex[keccak256(abi.encode(_enodeId))] == 0,
|
|
|
|
"passed enode id exists");
|
2019-03-14 23:41:04 -07:00
|
|
|
_;
|
|
|
|
}
|
|
|
|
|
2019-07-30 01:56:44 -07:00
|
|
|
/** @notice constructor. sets the permissions upgradable address
|
|
|
|
*/
|
2019-03-15 02:26:57 -07:00
|
|
|
constructor (address _permUpgradable) public {
|
2019-03-19 02:15:51 -07:00
|
|
|
permUpgradable = PermissionsUpgradable(_permUpgradable);
|
2019-03-15 02:26:57 -07:00
|
|
|
}
|
|
|
|
|
2019-07-30 01:56:44 -07:00
|
|
|
/** @notice fetches the node details given an enode id
|
|
|
|
* @param _enodeId full enode id
|
|
|
|
* @return org id
|
|
|
|
* @return enode id
|
|
|
|
* @return status of the node
|
|
|
|
*/
|
2019-07-19 01:16:50 -07:00
|
|
|
function getNodeDetails(string calldata enodeId) external view
|
2019-07-21 20:25:14 -07:00
|
|
|
returns (string memory _orgId, string memory _enodeId, uint256 _nodeStatus) {
|
|
|
|
uint256 nodeIndex = _getNodeIndex(enodeId);
|
2019-07-19 01:16:50 -07:00
|
|
|
return (nodeList[nodeIndex].orgId, nodeList[nodeIndex].enodeId,
|
|
|
|
nodeList[nodeIndex].status);
|
|
|
|
}
|
|
|
|
|
2019-07-30 01:56:44 -07:00
|
|
|
/** @notice fetches the node details given the index of the enode
|
|
|
|
* @param _nodeIndex node index
|
|
|
|
* @return org id
|
|
|
|
* @return enode id
|
|
|
|
* @return status of the node
|
|
|
|
*/
|
2019-07-21 20:25:14 -07:00
|
|
|
function getNodeDetailsFromIndex(uint256 _nodeIndex) external view
|
|
|
|
returns (string memory _orgId, string memory _enodeId, uint256 _nodeStatus) {
|
2019-07-19 01:16:50 -07:00
|
|
|
return (nodeList[_nodeIndex].orgId, nodeList[_nodeIndex].enodeId,
|
|
|
|
nodeList[_nodeIndex].status);
|
|
|
|
}
|
|
|
|
|
2019-07-30 01:56:44 -07:00
|
|
|
/** @notice returns the total number of enodes in the network
|
|
|
|
* @return number of nodes
|
|
|
|
*/
|
2019-07-21 20:25:14 -07:00
|
|
|
function getNumberOfNodes() external view returns (uint256) {
|
2019-03-14 23:41:04 -07:00
|
|
|
return numberOfNodes;
|
|
|
|
}
|
|
|
|
|
2019-07-30 01:56:44 -07:00
|
|
|
/** @notice called at the time of network initialization for adding
|
|
|
|
admin nodes
|
|
|
|
* @param _enodeId enode id
|
|
|
|
* @param _orgId org id to which the enode belongs
|
|
|
|
*/
|
2019-03-28 02:53:11 -07:00
|
|
|
function addAdminNode(string calldata _enodeId, string calldata _orgId) external
|
2019-07-19 01:16:50 -07:00
|
|
|
onlyImplementation
|
|
|
|
enodeDoesNotExists(_enodeId) {
|
2019-04-02 00:30:51 -07:00
|
|
|
numberOfNodes++;
|
2019-07-19 01:16:50 -07:00
|
|
|
nodeIdToIndex[keccak256(abi.encode(_enodeId))] = numberOfNodes;
|
2019-04-02 00:30:51 -07:00
|
|
|
nodeList.push(NodeDetails(_enodeId, _orgId, 2));
|
2019-07-19 01:16:50 -07:00
|
|
|
emit NodeApproved(_enodeId, _orgId);
|
2019-03-28 02:53:11 -07:00
|
|
|
}
|
2019-05-10 00:17:01 -07:00
|
|
|
|
2019-07-30 01:56:44 -07:00
|
|
|
/** @notice called at the time of new org creation to add node to org
|
|
|
|
* @param _enodeId enode id
|
|
|
|
* @param _orgId org id to which the enode belongs
|
|
|
|
*/
|
2019-07-19 01:16:50 -07:00
|
|
|
function addNode(string calldata _enodeId, string calldata _orgId) external
|
|
|
|
onlyImplementation
|
|
|
|
enodeDoesNotExists(_enodeId) {
|
2019-03-14 23:41:04 -07:00
|
|
|
numberOfNodes++;
|
2019-07-19 01:16:50 -07:00
|
|
|
nodeIdToIndex[keccak256(abi.encode(_enodeId))] = numberOfNodes;
|
2019-05-08 20:07:54 -07:00
|
|
|
nodeList.push(NodeDetails(_enodeId, _orgId, 1));
|
2019-03-28 19:51:16 -07:00
|
|
|
emit NodeProposed(_enodeId, _orgId);
|
2019-03-14 23:41:04 -07:00
|
|
|
}
|
|
|
|
|
2019-07-30 01:56:44 -07:00
|
|
|
/** @notice called org admins to add new enodes to the org or sub orgs
|
|
|
|
* @param _enodeId enode id
|
|
|
|
* @param _orgId org or sub org id to which the enode belongs
|
|
|
|
*/
|
2019-03-15 02:26:57 -07:00
|
|
|
function addOrgNode(string calldata _enodeId, string calldata _orgId) external
|
2019-07-19 01:16:50 -07:00
|
|
|
onlyImplementation
|
|
|
|
enodeDoesNotExists(_enodeId) {
|
2019-03-14 23:41:04 -07:00
|
|
|
numberOfNodes++;
|
2019-07-19 01:16:50 -07:00
|
|
|
nodeIdToIndex[keccak256(abi.encode(_enodeId))] = numberOfNodes;
|
2019-05-08 20:07:54 -07:00
|
|
|
nodeList.push(NodeDetails(_enodeId, _orgId, 2));
|
2019-03-28 19:51:16 -07:00
|
|
|
emit NodeApproved(_enodeId, _orgId);
|
2019-03-14 23:41:04 -07:00
|
|
|
}
|
|
|
|
|
2019-07-30 01:56:44 -07:00
|
|
|
/** @notice function to approve the node addition. only called at the time
|
|
|
|
master org creation by network admin
|
|
|
|
* @param _enodeId enode id
|
|
|
|
* @param _orgId org or sub org id to which the enode belongs
|
|
|
|
*/
|
2019-07-19 01:16:50 -07:00
|
|
|
function approveNode(string calldata _enodeId, string calldata _orgId) external
|
|
|
|
onlyImplementation
|
|
|
|
enodeExists(_enodeId) {
|
2019-03-28 02:53:11 -07:00
|
|
|
// node should belong to the passed org
|
2019-07-19 01:16:50 -07:00
|
|
|
require(_checkOrg(_enodeId, _orgId), "enode id does not belong to the passed org id");
|
|
|
|
require(_getNodeStatus(_enodeId) == 1, "nothing pending for approval");
|
2019-07-21 20:25:14 -07:00
|
|
|
uint256 nodeIndex = _getNodeIndex(_enodeId);
|
2019-03-14 23:41:04 -07:00
|
|
|
nodeList[nodeIndex].status = 2;
|
2019-03-28 19:51:16 -07:00
|
|
|
emit NodeApproved(nodeList[nodeIndex].enodeId, nodeList[nodeIndex].orgId);
|
2019-03-14 23:41:04 -07:00
|
|
|
}
|
|
|
|
|
2019-07-30 01:56:44 -07:00
|
|
|
/** @notice updates the node status. can be called for deactivating/
|
|
|
|
blacklisting and reactivating a deactivated node
|
|
|
|
* @param _enodeId enode id
|
|
|
|
* @param _orgId org or sub org id to which the enode belong
|
|
|
|
* @param _action action being performed
|
|
|
|
* @dev action can have any of the following values
|
|
|
|
1 - Suspend the node
|
|
|
|
2 - Revoke suspension of a suspended node
|
|
|
|
3 - blacklist a node
|
2019-07-31 20:10:50 -07:00
|
|
|
4 - initiate the recovery of a blacklisted node
|
|
|
|
5 - blacklisted node recovery fully approved. mark to active
|
2019-07-30 01:56:44 -07:00
|
|
|
*/
|
2019-07-21 20:25:14 -07:00
|
|
|
function updateNodeStatus(string calldata _enodeId, string calldata _orgId, uint256 _action) external
|
2019-07-19 01:16:50 -07:00
|
|
|
onlyImplementation
|
|
|
|
enodeExists(_enodeId) {
|
2019-03-28 02:53:11 -07:00
|
|
|
// node should belong to the org
|
2019-07-19 01:16:50 -07:00
|
|
|
require(_checkOrg(_enodeId, _orgId), "enode id does not belong to the passed org");
|
2019-08-01 00:19:40 -07:00
|
|
|
require((_action == 1 || _action == 2 || _action == 3 || _action == 4 || _action == 5),
|
2019-07-19 01:16:50 -07:00
|
|
|
"invalid operation. wrong action passed");
|
2019-03-28 02:53:11 -07:00
|
|
|
|
2019-05-12 23:15:09 -07:00
|
|
|
if (_action == 1) {
|
2019-07-19 01:16:50 -07:00
|
|
|
require(_getNodeStatus(_enodeId) == 2, "operation cannot be performed");
|
|
|
|
nodeList[_getNodeIndex(_enodeId)].status = 3;
|
2019-03-28 19:51:16 -07:00
|
|
|
emit NodeDeactivated(_enodeId, _orgId);
|
2019-03-28 02:53:11 -07:00
|
|
|
}
|
2019-05-12 23:15:09 -07:00
|
|
|
else if (_action == 2) {
|
2019-07-19 01:16:50 -07:00
|
|
|
require(_getNodeStatus(_enodeId) == 3, "operation cannot be performed");
|
|
|
|
nodeList[_getNodeIndex(_enodeId)].status = 2;
|
2019-03-28 19:51:16 -07:00
|
|
|
emit NodeActivated(_enodeId, _orgId);
|
2019-03-28 02:53:11 -07:00
|
|
|
}
|
2019-07-31 20:10:50 -07:00
|
|
|
else if (_action == 3) {
|
2019-07-30 01:56:44 -07:00
|
|
|
nodeList[_getNodeIndex(_enodeId)].status = 4;
|
2019-03-28 19:51:16 -07:00
|
|
|
emit NodeBlacklisted(_enodeId, _orgId);
|
2019-07-31 20:10:50 -07:00
|
|
|
} else if (_action == 4) {
|
|
|
|
// node should be in blacklisted state
|
|
|
|
require(_getNodeStatus(_enodeId) == 4, "operation cannot be performed");
|
|
|
|
nodeList[_getNodeIndex(_enodeId)].status = 5;
|
|
|
|
emit NodeRecoveryInitiated(_enodeId, _orgId);
|
2019-08-01 00:19:40 -07:00
|
|
|
} else {
|
|
|
|
// node should be in initiated recovery state
|
|
|
|
require(_getNodeStatus(_enodeId) == 5, "operation cannot be performed");
|
|
|
|
nodeList[_getNodeIndex(_enodeId)].status = 2;
|
|
|
|
emit NodeRecoveryCompleted(_enodeId, _orgId);
|
2019-03-28 02:53:11 -07:00
|
|
|
}
|
|
|
|
}
|
2019-03-14 23:41:04 -07:00
|
|
|
|
2019-07-30 01:56:44 -07:00
|
|
|
// private functions
|
|
|
|
/** @notice returns the node index for given enode id
|
|
|
|
* @param _enodeId enode id
|
|
|
|
* @return trur or false
|
|
|
|
*/
|
2019-07-19 01:16:50 -07:00
|
|
|
function _getNodeIndex(string memory _enodeId) internal view
|
2019-07-21 20:25:14 -07:00
|
|
|
returns (uint256) {
|
2019-07-19 01:16:50 -07:00
|
|
|
return nodeIdToIndex[keccak256(abi.encode(_enodeId))] - 1;
|
|
|
|
}
|
|
|
|
|
2019-07-30 01:56:44 -07:00
|
|
|
/** @notice checks if enode id is linked to the org id passed
|
|
|
|
* @param _enodeId enode id
|
|
|
|
* @param _orgId org or sub org id to which the enode belongs
|
|
|
|
* @return true or false
|
|
|
|
*/
|
2019-07-19 01:16:50 -07:00
|
|
|
function _checkOrg(string memory _enodeId, string memory _orgId) internal view
|
|
|
|
returns (bool) {
|
|
|
|
return (keccak256(abi.encode(nodeList[_getNodeIndex(_enodeId)].orgId)) == keccak256(abi.encode(_orgId)));
|
|
|
|
}
|
|
|
|
|
2019-07-30 01:56:44 -07:00
|
|
|
/** @notice returns the node status for a given enode id
|
|
|
|
* @param _enodeId enode id
|
|
|
|
* @return node status
|
|
|
|
*/
|
2019-07-21 20:25:14 -07:00
|
|
|
function _getNodeStatus(string memory _enodeId) internal view returns (uint256) {
|
2019-07-19 01:16:50 -07:00
|
|
|
if (nodeIdToIndex[keccak256(abi.encode(_enodeId))] == 0) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return nodeList[_getNodeIndex(_enodeId)].status;
|
2019-03-28 02:53:11 -07:00
|
|
|
}
|
2019-03-14 23:41:04 -07:00
|
|
|
}
|