quorum/controls/permission/NodeManager.sol

170 lines
6.3 KiB
Solidity

pragma solidity ^0.5.3;
import "./PermissionsUpgradable.sol";
contract NodeManager {
PermissionsUpgradable private permUpgradable;
// enum and struct declaration
// changing node status to integer (0-NotInList, 1- PendingApproval, 2-Approved, 3-Deactivated, 4-Blacklisted)
// PendingDeactivation, Deactivated, PendingActivation, PendingBlacklisting, Blacklisted)
// enum NodeStatus {NotInList, PendingApproval, Approved, PendingDeactivation, Deactivated, PendingActivation, PendingBlacklisting, Blacklisted}
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
event NodeProposed(string _enodeId, string _orgId);
event NodeApproved(string _enodeId, string _orgId);
// node permission events for node deactivation
event NodeDeactivated(string _enodeId, string _orgId);
// node permission events for node activation
event NodeActivated(string _enodeId, string _orgId);
// node permission events for node blacklist
event NodeBlacklisted(string _enodeId, string _orgId);
modifier onlyImpl
{
require(msg.sender == permUpgradable.getPermImpl());
_;
}
// 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");
_;
}
constructor (address _permUpgradable) public {
permUpgradable = PermissionsUpgradable(_permUpgradable);
}
// Get node details given enode Id
function getNodeDetails(string memory enodeId) public view returns (string memory _orgId, string memory _enodeId, uint _nodeStatus)
{
uint nodeIndex = getNodeIndex(enodeId);
return (nodeList[nodeIndex].orgId, nodeList[nodeIndex].enodeId, nodeList[nodeIndex].status);
}
// Get node details given index
function getNodeDetailsFromIndex(uint nodeIndex) public view returns (string memory _orgId, string memory _enodeId, uint _nodeStatus)
{
return (nodeList[nodeIndex].orgId, nodeList[nodeIndex].enodeId, nodeList[nodeIndex].status);
}
// 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)
{
if (nodeIdToIndex[keccak256(abi.encodePacked(_enodeId))] == 0){
return 0;
}
return nodeList[getNodeIndex(_enodeId)].status;
}
function addAdminNode(string calldata _enodeId, string calldata _orgId) external
onlyImpl
enodeNotInList(_enodeId)
{
numberOfNodes++;
nodeIdToIndex[keccak256(abi.encodePacked(_enodeId))] = numberOfNodes;
nodeList.push(NodeDetails(_enodeId, _orgId, 2));
}
function addNode(string memory _enodeId, string memory _orgId) public
onlyImpl
enodeNotInList(_enodeId)
{
numberOfNodes++;
nodeIdToIndex[keccak256(abi.encodePacked(_enodeId))] = numberOfNodes;
nodeList.push(NodeDetails(_enodeId, _orgId, 1));
emit NodeProposed(_enodeId, _orgId);
}
function addOrgNode(string calldata _enodeId, string calldata _orgId) external
onlyImpl
enodeNotInList(_enodeId)
{
numberOfNodes++;
nodeIdToIndex[keccak256(abi.encodePacked(_enodeId))] = numberOfNodes;
nodeList.push(NodeDetails(_enodeId, _orgId, 2));
emit NodeApproved(_enodeId, _orgId);
}
// Adds a node to the nodeList mapping and emits node added event if successfully and node exists event of node is already present
function approveNode(string memory _enodeId, string memory _orgId) public
onlyImpl
enodeInList(_enodeId)
{
// node should belong to the passed org
require(checkOrg(_enodeId, _orgId), "Node does not belong to the org");
require(getNodeStatus(_enodeId) == 1, "Node need to be in PendingApproval status");
uint nodeIndex = getNodeIndex(_enodeId);
// vote node
nodeList[nodeIndex].status = 2;
emit NodeApproved(nodeList[nodeIndex].enodeId, nodeList[nodeIndex].orgId);
}
function updateNodeStatus(string calldata _enodeId, string calldata _orgId, uint _status) external
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
require((_status == 3 || _status == 4 || _status == 5), "invalid operation");
if (_status == 3){
require(getNodeStatus(_enodeId) == 2, "Op cannot be performed");
nodeList[getNodeIndex(_enodeId)].status = 3;
emit NodeDeactivated(_enodeId, _orgId);
}
else if (_status == 4){
require(getNodeStatus(_enodeId) == 3, "Op cannot be performed");
nodeList[getNodeIndex(_enodeId)].status = 2;
emit NodeActivated(_enodeId, _orgId);
}
else {
nodeList[getNodeIndex(_enodeId)].status = 5;
emit NodeBlacklisted(_enodeId, _orgId);
}
}
/* private functions */
function getNodeIndex(string memory _enodeId) internal view
returns (uint)
{
return nodeIdToIndex[keccak256(abi.encodePacked(_enodeId))] - 1;
}
function checkOrg(string memory _enodeId, string memory _orgId) internal view
returns(bool)
{
return (keccak256(abi.encodePacked(nodeList[getNodeIndex(_enodeId)].orgId)) == keccak256(abi.encodePacked(_orgId)));
}
}