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-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
|
|
|
// enum and struct declaration
|
2019-03-28 02:53:11 -07:00
|
|
|
// changing node status to integer (0-NotInList, 1- PendingApproval, 2-Approved, 3-Deactivated, 4-Blacklisted)
|
2019-03-14 23:41:04 -07:00
|
|
|
// PendingDeactivation, Deactivated, PendingActivation, PendingBlacklisting, Blacklisted)
|
2019-05-08 20:07:54 -07:00
|
|
|
// enum NodeStatus {NotInList, PendingApproval, Approved, PendingDeactivation, Deactivated, PendingActivation, PendingBlacklisting, Blacklisted}
|
2019-03-14 23:41:04 -07:00
|
|
|
struct NodeDetails {
|
|
|
|
string enodeId; //e.g. 127.0.0.1:20005
|
|
|
|
string orgId;
|
|
|
|
uint status;
|
|
|
|
}
|
|
|
|
// use an array to store node details
|
|
|
|
// if we want to list all node one day, mapping is not capable
|
|
|
|
NodeDetails[] private nodeList;
|
|
|
|
// use a mapping of enodeid to array index to track node
|
|
|
|
mapping(bytes32 => uint) private nodeIdToIndex;
|
|
|
|
// keep track of node number
|
|
|
|
uint private numberOfNodes;
|
|
|
|
|
|
|
|
|
|
|
|
// 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-05-10 00:17:01 -07:00
|
|
|
// checks if the caller is implementation contracts
|
2019-03-15 02:26:57 -07:00
|
|
|
modifier onlyImpl
|
|
|
|
{
|
|
|
|
require(msg.sender == permUpgradable.getPermImpl());
|
|
|
|
_;
|
|
|
|
}
|
|
|
|
|
2019-03-14 23:41:04 -07:00
|
|
|
// Checks if the given enode exists
|
|
|
|
modifier enodeInList(string memory _enodeId)
|
|
|
|
{
|
|
|
|
require(nodeIdToIndex[keccak256(abi.encodePacked(_enodeId))] != 0, "Enode is not in the list");
|
|
|
|
_;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Checks if the given enode does not exists
|
|
|
|
modifier enodeNotInList(string memory _enodeId)
|
|
|
|
{
|
|
|
|
require(nodeIdToIndex[keccak256(abi.encodePacked(_enodeId))] == 0, "Enode is in the list");
|
|
|
|
_;
|
|
|
|
}
|
|
|
|
|
2019-05-10 00:17:01 -07:00
|
|
|
// constructor. sets the 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-03-14 23:41:04 -07:00
|
|
|
// Get node details given enode Id
|
2019-03-27 21:44:47 -07:00
|
|
|
function getNodeDetails(string memory enodeId) public view returns (string memory _orgId, string memory _enodeId, uint _nodeStatus)
|
2019-03-14 23:41:04 -07:00
|
|
|
{
|
|
|
|
uint nodeIndex = getNodeIndex(enodeId);
|
2019-03-27 21:44:47 -07:00
|
|
|
return (nodeList[nodeIndex].orgId, nodeList[nodeIndex].enodeId, nodeList[nodeIndex].status);
|
2019-03-14 23:41:04 -07:00
|
|
|
}
|
2019-05-10 00:17:01 -07:00
|
|
|
|
2019-03-14 23:41:04 -07:00
|
|
|
// Get node details given index
|
2019-03-27 04:07:01 -07:00
|
|
|
function getNodeDetailsFromIndex(uint nodeIndex) public view returns (string memory _orgId, string memory _enodeId, uint _nodeStatus)
|
2019-03-14 23:41:04 -07:00
|
|
|
{
|
2019-03-27 04:07:01 -07:00
|
|
|
return (nodeList[nodeIndex].orgId, nodeList[nodeIndex].enodeId, nodeList[nodeIndex].status);
|
2019-03-14 23:41:04 -07:00
|
|
|
}
|
2019-05-10 00:17:01 -07:00
|
|
|
|
2019-03-14 23:41:04 -07:00
|
|
|
// Get number of nodes
|
|
|
|
function getNumberOfNodes() public view returns (uint)
|
|
|
|
{
|
|
|
|
return numberOfNodes;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get node status by enode id
|
|
|
|
function getNodeStatus(string memory _enodeId) public view returns (uint)
|
|
|
|
{
|
2019-05-08 20:07:54 -07:00
|
|
|
if (nodeIdToIndex[keccak256(abi.encodePacked(_enodeId))] == 0) {
|
2019-03-14 23:41:04 -07:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return nodeList[getNodeIndex(_enodeId)].status;
|
|
|
|
}
|
2019-05-10 00:17:01 -07:00
|
|
|
|
|
|
|
// called at the time of initialization for adding admin nodes
|
2019-03-28 02:53:11 -07:00
|
|
|
function addAdminNode(string calldata _enodeId, string calldata _orgId) external
|
|
|
|
onlyImpl
|
|
|
|
enodeNotInList(_enodeId)
|
|
|
|
{
|
2019-04-02 00:30:51 -07:00
|
|
|
numberOfNodes++;
|
|
|
|
nodeIdToIndex[keccak256(abi.encodePacked(_enodeId))] = numberOfNodes;
|
|
|
|
nodeList.push(NodeDetails(_enodeId, _orgId, 2));
|
2019-03-28 02:53:11 -07:00
|
|
|
}
|
2019-05-10 00:17:01 -07:00
|
|
|
|
|
|
|
// called at the time of new org creation. will need approval for the node to be
|
|
|
|
// part of the network
|
2019-03-28 02:53:11 -07:00
|
|
|
function addNode(string memory _enodeId, string memory _orgId) public
|
2019-03-15 02:26:57 -07:00
|
|
|
onlyImpl
|
|
|
|
enodeNotInList(_enodeId)
|
|
|
|
{
|
2019-03-14 23:41:04 -07:00
|
|
|
numberOfNodes++;
|
|
|
|
nodeIdToIndex[keccak256(abi.encodePacked(_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-05-10 00:17:01 -07:00
|
|
|
// can be called by org admins to add new nodes to the org or sub orgs
|
2019-03-15 02:26:57 -07:00
|
|
|
function addOrgNode(string calldata _enodeId, string calldata _orgId) external
|
|
|
|
onlyImpl
|
|
|
|
enodeNotInList(_enodeId)
|
|
|
|
{
|
2019-03-14 23:41:04 -07:00
|
|
|
numberOfNodes++;
|
|
|
|
nodeIdToIndex[keccak256(abi.encodePacked(_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-05-10 00:17:01 -07:00
|
|
|
// updates the node status to approved and emits the event
|
2019-03-28 02:53:11 -07:00
|
|
|
function approveNode(string memory _enodeId, string memory _orgId) public
|
2019-03-15 02:26:57 -07:00
|
|
|
onlyImpl
|
2019-03-28 02:53:11 -07:00
|
|
|
enodeInList(_enodeId)
|
2019-03-14 23:41:04 -07:00
|
|
|
{
|
2019-03-28 02:53:11 -07:00
|
|
|
// node should belong to the passed org
|
|
|
|
require(checkOrg(_enodeId, _orgId), "Node does not belong to the org");
|
2019-03-14 23:41:04 -07:00
|
|
|
require(getNodeStatus(_enodeId) == 1, "Node need to be in PendingApproval status");
|
|
|
|
uint nodeIndex = getNodeIndex(_enodeId);
|
|
|
|
// vote node
|
|
|
|
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-05-10 00:17:01 -07:00
|
|
|
// updates the node status. Used for deactivating or blacklisting a node and reactivating
|
|
|
|
// a deactivated node
|
2019-05-12 23:15:09 -07:00
|
|
|
function updateNodeStatus(string calldata _enodeId, string calldata _orgId, uint _action) external
|
2019-03-28 02:53:11 -07:00
|
|
|
onlyImpl
|
|
|
|
enodeInList(_enodeId)
|
|
|
|
{
|
|
|
|
// node should belong to the org
|
|
|
|
require(checkOrg(_enodeId, _orgId), "Node does not belong to the org");
|
|
|
|
// changing node status to integer (0-NotInList, 1- PendingApproval, 2-Approved, 3-Deactivated, 4-Blacklisted)
|
|
|
|
// operations that can be done 3-Deactivate Node, 4-ActivateNode, 5-Blacklist nodeList
|
2019-05-12 23:15:09 -07:00
|
|
|
require((_action == 1 || _action == 2 || _action == 3), "invalid operation");
|
2019-03-28 02:53:11 -07:00
|
|
|
|
2019-05-12 23:15:09 -07:00
|
|
|
if (_action == 1) {
|
2019-03-28 02:53:11 -07:00
|
|
|
require(getNodeStatus(_enodeId) == 2, "Op 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-03-28 02:53:11 -07:00
|
|
|
require(getNodeStatus(_enodeId) == 3, "Op 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
|
|
|
}
|
|
|
|
else {
|
|
|
|
nodeList[getNodeIndex(_enodeId)].status = 5;
|
2019-03-28 19:51:16 -07:00
|
|
|
emit NodeBlacklisted(_enodeId, _orgId);
|
2019-03-28 02:53:11 -07:00
|
|
|
}
|
|
|
|
}
|
2019-03-14 23:41:04 -07:00
|
|
|
|
|
|
|
/* private functions */
|
2019-05-10 00:17:01 -07:00
|
|
|
// returs the node index for given node id
|
2019-03-28 02:53:11 -07:00
|
|
|
function getNodeIndex(string memory _enodeId) internal view
|
|
|
|
returns (uint)
|
2019-03-14 23:41:04 -07:00
|
|
|
{
|
|
|
|
return nodeIdToIndex[keccak256(abi.encodePacked(_enodeId))] - 1;
|
|
|
|
}
|
|
|
|
|
2019-05-10 00:17:01 -07:00
|
|
|
// checks if the node is linked to the passed org
|
2019-03-28 02:53:11 -07:00
|
|
|
function checkOrg(string memory _enodeId, string memory _orgId) internal view
|
2019-05-08 20:07:54 -07:00
|
|
|
returns (bool)
|
2019-03-28 02:53:11 -07:00
|
|
|
{
|
|
|
|
return (keccak256(abi.encodePacked(nodeList[getNodeIndex(_enodeId)].orgId)) == keccak256(abi.encodePacked(_orgId)));
|
|
|
|
}
|
2019-03-14 23:41:04 -07:00
|
|
|
|
|
|
|
}
|