Created
November 19, 2022 11:32
-
-
Save p14041999/658f29dd346ef146f83591384523ab86 to your computer and use it in GitHub Desktop.
Created using remix-ide: Realtime Ethereum Contract Compiler and Runtime. Load this file by pasting this gists URL or ID at https://remix.ethereum.org/#version=soljson-v0.6.12+commit.27d51765.js&optimize=false&runs=200&gist=
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| pragma solidity ^0.5.3; | |
| import "./PermissionsUpgradable.sol"; | |
| /** @title Account manager contract | |
| * @notice This contract holds implementation logic for all account management | |
| functionality. This can be called only by the implementation contract only. | |
| 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 account status is denoted by a fixed integer value. The values are | |
| as below: | |
| 0 - Not in list | |
| 1 - Account pending approval | |
| 2 - Active | |
| 3 - Inactive | |
| 4 - Suspended | |
| 5 - Blacklisted | |
| 6 - Revoked | |
| 7 - Recovery Initiated for blacklisted accounts and pending approval | |
| from network admins | |
| Once the account is blacklisted no further activity on the account is | |
| possible. | |
| When adding a new org admin account to an existing org, the existing org | |
| admin account will be in revoked status and can be assigned a new role | |
| later | |
| */ | |
| contract AccountManager { | |
| PermissionsUpgradable private permUpgradable; | |
| struct AccountAccessDetails { | |
| address account; | |
| string orgId; | |
| string role; | |
| uint status; | |
| bool orgAdmin; | |
| } | |
| AccountAccessDetails[] private accountAccessList; | |
| mapping(address => uint) private accountIndex; | |
| uint private numAccounts; | |
| string private adminRole; | |
| string private orgAdminRole; | |
| mapping(bytes32 => address) private orgAdminIndex; | |
| // account permission events | |
| event AccountAccessModified(address _account, string _orgId, string _roleId, bool _orgAdmin, uint _status); | |
| event AccountAccessRevoked(address _account, string _orgId, string _roleId, bool _orgAdmin); | |
| event AccountStatusChanged(address _account, string _orgId, uint _status); | |
| /** @notice confirms that the caller is the address of implementation | |
| contract | |
| */ | |
| modifier onlyImplementation { | |
| require(msg.sender == permUpgradable.getPermImpl(), "invalid caller"); | |
| _; | |
| } | |
| /** @notice checks if the account is exists and belongs to the org id passed | |
| * @param _orgId - org id | |
| * @param _account - account id | |
| */ | |
| modifier accountExists(string memory _orgId, address _account) { | |
| require((accountIndex[_account]) != 0, "account does not exists"); | |
| require(keccak256(abi.encode(accountAccessList[_getAccountIndex(_account)].orgId)) == keccak256(abi.encode(_orgId)), "account in different org"); | |
| _; | |
| } | |
| /// @notice constructor. sets the permissions upgradable address | |
| constructor (address _permUpgradable) public { | |
| permUpgradable = PermissionsUpgradable(_permUpgradable); | |
| } | |
| /** @notice returns the account details for a given account | |
| * @param _account account id | |
| * @return account id | |
| * @return org id of the account | |
| * @return role linked to the account | |
| * @return status of the account | |
| * @return bool indicating if the account is an org admin | |
| */ | |
| function getAccountDetails(address _account) external view returns (address, | |
| string memory, string memory, uint, bool){ | |
| if (accountIndex[_account] == 0) { | |
| return (_account, "NONE", "", 0, false); | |
| } | |
| uint aIndex = _getAccountIndex(_account); | |
| return (accountAccessList[aIndex].account, accountAccessList[aIndex].orgId, | |
| accountAccessList[aIndex].role, accountAccessList[aIndex].status, | |
| accountAccessList[aIndex].orgAdmin); | |
| } | |
| /** @notice returns the account details for a given account if account is valid/active | |
| * @param _account account id | |
| * @return org id of the account | |
| * @return role linked to the account | |
| */ | |
| function getAccountOrgRole(address _account) external view | |
| returns (string memory, string memory){ | |
| if (accountIndex[_account] == 0) { | |
| return ("NONE", ""); | |
| } | |
| uint aIndex = _getAccountIndex(_account); | |
| return (accountAccessList[aIndex].orgId, accountAccessList[aIndex].role); | |
| } | |
| /** @notice returns the account details a given account index | |
| * @param _aIndex account index | |
| * @return account id | |
| * @return org id of the account | |
| * @return role linked to the account | |
| * @return status of the account | |
| * @return bool indicating if the account is an org admin | |
| */ | |
| function getAccountDetailsFromIndex(uint _aIndex) external view returns | |
| (address, string memory, string memory, uint, bool) { | |
| return (accountAccessList[_aIndex].account, | |
| accountAccessList[_aIndex].orgId, accountAccessList[_aIndex].role, | |
| accountAccessList[_aIndex].status, accountAccessList[_aIndex].orgAdmin); | |
| } | |
| /** @notice returns the total number of accounts | |
| * @return total number accounts | |
| */ | |
| function getNumberOfAccounts() external view returns (uint) { | |
| return accountAccessList.length; | |
| } | |
| /** @notice this is called at the time of network initialization to set | |
| the default values of network admin and org admin roles | |
| */ | |
| function setDefaults(string calldata _nwAdminRole, string calldata _oAdminRole) | |
| external onlyImplementation { | |
| adminRole = _nwAdminRole; | |
| orgAdminRole = _oAdminRole; | |
| } | |
| /** @notice this function is called to assign the org admin or network | |
| admin roles only to the passed account | |
| * @param _account - account id | |
| * @param _orgId - org to which it belongs | |
| * @param _roleId - role id to be assigned | |
| * @param _status - account status to be assigned | |
| */ | |
| function assignAdminRole(address _account, string calldata _orgId, | |
| string calldata _roleId, uint _status) external onlyImplementation { | |
| require(((keccak256(abi.encode(_roleId)) == keccak256(abi.encode(orgAdminRole))) || | |
| (keccak256(abi.encode(_roleId)) == keccak256(abi.encode(adminRole)))), | |
| "can be called to assign admin roles only"); | |
| _setAccountRole(_account, _orgId, _roleId, _status, true); | |
| } | |
| /** @notice this function is called to assign the any role to the passed | |
| account. | |
| * @param _account - account id | |
| * @param _orgId - org to which it belongs | |
| * @param _roleId - role id to be assigned | |
| * @param _adminRole - indicates of the role is an admin role | |
| */ | |
| function assignAccountRole(address _account, string calldata _orgId, | |
| string calldata _roleId, bool _adminRole) external onlyImplementation { | |
| require(((keccak256(abi.encode(_roleId)) != keccak256(abi.encode(adminRole))) | |
| && (keccak256(abi.encode(abi.encode(_roleId))) != keccak256(abi.encode(orgAdminRole)))), | |
| "cannot be called fro assigning org admin and network admin roles"); | |
| _setAccountRole(_account, _orgId, _roleId, 2, _adminRole); | |
| } | |
| /** @notice this function removes existing admin account. will be called at | |
| the time of adding a new account as org admin account. at org | |
| level there can be one org admin account only | |
| * @param _orgId - org id | |
| * @return bool to indicate if voter update is required or not | |
| * @return _adminRole - indicates of the role is an admin role | |
| */ | |
| function removeExistingAdmin(string calldata _orgId) external | |
| onlyImplementation | |
| returns (bool voterUpdate, address account) { | |
| // change the status of existing org admin to revoked | |
| if (orgAdminExists(_orgId)) { | |
| uint id = _getAccountIndex(orgAdminIndex[keccak256(abi.encode(_orgId))]); | |
| accountAccessList[id].status = 6; | |
| accountAccessList[id].orgAdmin = false; | |
| emit AccountAccessModified(accountAccessList[id].account, | |
| accountAccessList[id].orgId, accountAccessList[id].role, | |
| accountAccessList[id].orgAdmin, accountAccessList[id].status); | |
| return ((keccak256(abi.encode(accountAccessList[id].role)) == keccak256(abi.encode(adminRole))), | |
| accountAccessList[id].account); | |
| } | |
| return (false, address(0)); | |
| } | |
| /** @notice function to add an account as network admin or org admin. | |
| * @param _orgId - org id | |
| * @param _account - account id | |
| * @return bool to indicate if voter update is required or not | |
| */ | |
| function addNewAdmin(string calldata _orgId, address _account) external | |
| onlyImplementation | |
| returns (bool voterUpdate) { | |
| // check of the account role is org admin role and status is pending | |
| // approval. if yes update the status to approved | |
| string memory role = getAccountRole(_account); | |
| uint status = getAccountStatus(_account); | |
| uint id = _getAccountIndex(_account); | |
| if ((keccak256(abi.encode(role)) == keccak256(abi.encode(orgAdminRole))) && | |
| (status == 1)) { | |
| orgAdminIndex[keccak256(abi.encode(_orgId))] = _account; | |
| } | |
| accountAccessList[id].status = 2; | |
| accountAccessList[id].orgAdmin = true; | |
| emit AccountAccessModified(_account, accountAccessList[id].orgId, accountAccessList[id].role, | |
| accountAccessList[id].orgAdmin, accountAccessList[id].status); | |
| return (keccak256(abi.encode(accountAccessList[id].role)) == keccak256(abi.encode(adminRole))); | |
| } | |
| /** @notice updates the account status to the passed status value | |
| * @param _orgId - org id | |
| * @param _account - account id | |
| * @param _action - new status of the account | |
| * @dev the following actions are allowed | |
| 1 - Suspend the account | |
| 2 - Reactivate a suspended account | |
| 3 - Blacklist an account | |
| 4 - Initiate recovery for black listed account | |
| 5 - Complete recovery of black listed account and update status to active | |
| */ | |
| function updateAccountStatus(string calldata _orgId, address _account, uint _action) external | |
| onlyImplementation | |
| accountExists(_orgId, _account) { | |
| require((_action > 0 && _action < 6), "invalid status change request"); | |
| // check if the account is org admin. if yes then do not allow any status change | |
| require(checkOrgAdmin(_account, _orgId, "") != true, "status change not possible for org admin accounts"); | |
| uint newStatus; | |
| if (_action == 1) { | |
| // for suspending an account current status should be active | |
| require(accountAccessList[_getAccountIndex(_account)].status == 2, | |
| "account is not in active status. operation cannot be done"); | |
| newStatus = 4; | |
| } | |
| else if (_action == 2) { | |
| // for reactivating a suspended account, current status should be suspended | |
| require(accountAccessList[_getAccountIndex(_account)].status == 4, | |
| "account is not in suspended status. operation cannot be done"); | |
| newStatus = 2; | |
| } | |
| else if (_action == 3) { | |
| require(accountAccessList[_getAccountIndex(_account)].status != 5, | |
| "account is already blacklisted. operation cannot be done"); | |
| newStatus = 5; | |
| } | |
| else if (_action == 4) { | |
| require(accountAccessList[_getAccountIndex(_account)].status == 5, | |
| "account is not blacklisted. operation cannot be done"); | |
| newStatus = 7; | |
| } | |
| else if (_action == 5) { | |
| require(accountAccessList[_getAccountIndex(_account)].status == 7, "account recovery not initiated. operation cannot be done"); | |
| newStatus = 2; | |
| } | |
| accountAccessList[_getAccountIndex(_account)].status = newStatus; | |
| emit AccountStatusChanged(_account, _orgId, newStatus); | |
| } | |
| /** @notice checks if the passed account exists and if exists does it | |
| belong to the passed organization. | |
| * @param _account - account id | |
| * @param _orgId - org id | |
| * @return bool true if the account does not exists or exists and belongs | |
| * @return passed org | |
| */ | |
| function validateAccount(address _account, string calldata _orgId) external | |
| view returns (bool){ | |
| if (accountIndex[_account] == 0) { | |
| return true; | |
| } | |
| uint256 id = _getAccountIndex(_account); | |
| return (keccak256(abi.encode(accountAccessList[id].orgId)) == keccak256(abi.encode(_orgId))); | |
| } | |
| /** @notice checks if org admin account exists for the passed org id | |
| * @param _orgId - org id | |
| * @return true if the org admin account exists and is approved | |
| */ | |
| function orgAdminExists(string memory _orgId) public view returns (bool) { | |
| if (orgAdminIndex[keccak256(abi.encode(_orgId))] != address(0)) { | |
| address adminAcct = orgAdminIndex[keccak256(abi.encode(_orgId))]; | |
| return getAccountStatus(adminAcct) == 2; | |
| } | |
| return false; | |
| } | |
| /** @notice returns the role id linked to the passed account | |
| * @param _account account id | |
| * @return role id | |
| */ | |
| function getAccountRole(address _account) public view returns (string memory) { | |
| if (accountIndex[_account] == 0) { | |
| return "NONE"; | |
| } | |
| uint256 acctIndex = _getAccountIndex(_account); | |
| if (accountAccessList[acctIndex].status != 0) { | |
| return accountAccessList[acctIndex].role; | |
| } | |
| else { | |
| return "NONE"; | |
| } | |
| } | |
| /** @notice returns the account status for a given account | |
| * @param _account account id | |
| * @return account status | |
| */ | |
| function getAccountStatus(address _account) public view returns (uint256) { | |
| if (accountIndex[_account] == 0) { | |
| return 0; | |
| } | |
| uint256 aIndex = _getAccountIndex(_account); | |
| return (accountAccessList[aIndex].status); | |
| } | |
| /** @notice checks if the account is a org admin for the passed org or | |
| for the ultimate parent organization | |
| * @param _account account id | |
| * @param _orgId org id | |
| * @param _ultParent master org id or | |
| */ | |
| function checkOrgAdmin(address _account, string memory _orgId, | |
| string memory _ultParent) public view returns (bool) { | |
| // check if the account role is network admin. If yes return success | |
| if (keccak256(abi.encode(getAccountRole(_account))) == keccak256(abi.encode(adminRole))) { | |
| // check of the orgid is network admin org. then return true | |
| uint256 id = _getAccountIndex(_account); | |
| return ((keccak256(abi.encode(accountAccessList[id].orgId)) == keccak256(abi.encode(_orgId))) | |
| || (keccak256(abi.encode(accountAccessList[id].orgId)) == keccak256(abi.encode(_ultParent)))); | |
| } | |
| return ((orgAdminIndex[keccak256(abi.encode(_orgId))] == _account) || (orgAdminIndex[keccak256(abi.encode(_ultParent))] == _account)); | |
| } | |
| /** @notice returns the index for a given account id | |
| * @param _account account id | |
| * @return account index | |
| */ | |
| function _getAccountIndex(address _account) internal view returns (uint256) { | |
| return accountIndex[_account] - 1; | |
| } | |
| /** @notice sets the account role to the passed role id and sets the status | |
| * @param _account account id | |
| * @param _orgId org id | |
| * @param _status status to be set | |
| * @param _oAdmin bool to indicate if account is org admin | |
| */ | |
| function _setAccountRole(address _account, string memory _orgId, | |
| string memory _roleId, uint256 _status, bool _oAdmin) internal onlyImplementation { | |
| // Check if account already exists | |
| uint256 aIndex = _getAccountIndex(_account); | |
| if (accountIndex[_account] != 0) { | |
| accountAccessList[aIndex].role = _roleId; | |
| accountAccessList[aIndex].status = _status; | |
| accountAccessList[aIndex].orgAdmin = _oAdmin; | |
| } | |
| else { | |
| numAccounts ++; | |
| accountIndex[_account] = numAccounts; | |
| accountAccessList.push(AccountAccessDetails(_account, _orgId, | |
| _roleId, _status, _oAdmin)); | |
| } | |
| emit AccountAccessModified(_account, _orgId, _roleId, _oAdmin, _status); | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| pragma solidity ^0.5.3; | |
| import "./PermissionsUpgradable.sol"; | |
| /** @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 | |
| 5 - Blacklisted node recovery initiated. Once approved the node | |
| status will be updated to Active (2) | |
| Once the node is blacklisted no further activity on the node is | |
| possible. | |
| */ | |
| contract NodeManager { | |
| PermissionsUpgradable private permUpgradable; | |
| struct NodeDetails { | |
| string enodeId; | |
| string ip; | |
| uint16 port; | |
| uint16 raftPort; | |
| string orgId; | |
| uint256 status; | |
| } | |
| // use an array to store node details | |
| // if we want to list all node one day, mapping is not capable | |
| NodeDetails[] private nodeList; | |
| // mapping of enode id to array index to track node | |
| mapping(bytes32 => uint256) private nodeIdToIndex; | |
| // mapping of enodeId to array index to track node | |
| mapping(bytes32 => uint256) private enodeIdToIndex; | |
| // tracking total number of nodes in network | |
| uint256 private numberOfNodes; | |
| // node permission events for new node propose | |
| event NodeProposed(string _enodeId, string _ip, uint16 _port, uint16 _raftport, string _orgId); | |
| event NodeApproved(string _enodeId, string _ip, uint16 _port, uint16 _raftport, string _orgId); | |
| // node permission events for node deactivation | |
| event NodeDeactivated(string _enodeId, string _ip, uint16 _port, uint16 _raftport, string _orgId); | |
| // node permission events for node activation | |
| event NodeActivated(string _enodeId, string _ip, uint16 _port, uint16 _raftport, string _orgId); | |
| // node permission events for node blacklist | |
| event NodeBlacklisted(string _enodeId, string _ip, uint16 _port, uint16 _raftport, string _orgId); | |
| // node permission events for initiating the recovery of blacklisted | |
| // node | |
| event NodeRecoveryInitiated(string _enodeId, string _ip, uint16 _port, uint16 _raftport, string _orgId); | |
| // node permission events for completing the recovery of blacklisted | |
| // node | |
| event NodeRecoveryCompleted(string _enodeId, string _ip, uint16 _port, uint16 _raftport, string _orgId); | |
| /** @notice confirms that the caller is the address of implementation | |
| contract | |
| */ | |
| modifier onlyImplementation { | |
| require(msg.sender == permUpgradable.getPermImpl(), "invalid caller"); | |
| _; | |
| } | |
| /** @notice checks if the node exists in the network | |
| * @param _enodeId full enode id | |
| */ | |
| modifier enodeExists(string memory _enodeId) { | |
| require(enodeIdToIndex[keccak256(abi.encode(_enodeId))] != 0, | |
| "passed enode id does not exist"); | |
| _; | |
| } | |
| /** @notice checks if the node does not exist in the network | |
| * @param _enodeId full enode id | |
| */ | |
| modifier enodeDoesNotExists(string memory _enodeId) { | |
| require(enodeIdToIndex[keccak256(abi.encode(_enodeId))] == 0, | |
| "passed enode id exists"); | |
| _; | |
| } | |
| /** @notice constructor. sets the permissions upgradable address | |
| */ | |
| constructor (address _permUpgradable) public { | |
| permUpgradable = PermissionsUpgradable(_permUpgradable); | |
| } | |
| /** @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 | |
| */ | |
| function getNodeDetails(string calldata enodeId) external view | |
| returns (string memory _orgId, string memory _enodeId, string memory _ip, uint16 _port, uint16 _raftport, uint256 _nodeStatus) { | |
| if (nodeIdToIndex[keccak256(abi.encode(_enodeId))] == 0) { | |
| return ("", "", "", 0, 0, 0); | |
| } | |
| uint256 nodeIndex = _getNodeIndex(enodeId); | |
| return (nodeList[nodeIndex].orgId, nodeList[nodeIndex].enodeId, nodeList[nodeIndex].ip, | |
| nodeList[nodeIndex].port, nodeList[nodeIndex].raftPort, | |
| nodeList[nodeIndex].status); | |
| } | |
| /** @notice fetches the node details given the index of the enode | |
| * @param _nodeIndex node index | |
| * @return org id | |
| * @return enode id | |
| * @return ip of the node | |
| * @return port of the node | |
| * @return raftport of the node | |
| * @return status of the node | |
| */ | |
| function getNodeDetailsFromIndex(uint256 _nodeIndex) external view | |
| returns (string memory _orgId, string memory _enodeId, string memory _ip, uint16 _port, uint16 _raftport, uint256 _nodeStatus) { | |
| return (nodeList[_nodeIndex].orgId, nodeList[_nodeIndex].enodeId, nodeList[_nodeIndex].ip, | |
| nodeList[_nodeIndex].port, nodeList[_nodeIndex].raftPort, | |
| nodeList[_nodeIndex].status); | |
| } | |
| /** @notice returns the total number of enodes in the network | |
| * @return number of nodes | |
| */ | |
| function getNumberOfNodes() external view returns (uint256) { | |
| return numberOfNodes; | |
| } | |
| /** @notice called at the time of network initialization for adding | |
| admin nodes | |
| * @param _enodeId enode id | |
| * @param _ip IP of node | |
| * @param _port tcp port of node | |
| * @param _raftport raft port of node | |
| * @param _orgId org id to which the enode belongs | |
| */ | |
| function addAdminNode(string memory _enodeId, string memory _ip, uint16 _port, uint16 _raftport, string memory _orgId) public | |
| onlyImplementation | |
| enodeDoesNotExists(_enodeId) { | |
| numberOfNodes++; | |
| enodeIdToIndex[keccak256(abi.encode(_enodeId))] = numberOfNodes; | |
| nodeList.push(NodeDetails(_enodeId, _ip, _port, _raftport, _orgId, 2)); | |
| emit NodeApproved(_enodeId, _ip, _port, _raftport, _orgId); | |
| } | |
| /** @notice called at the time of new org creation to add node to org | |
| * @param _enodeId enode id | |
| * @param _ip IP of node | |
| * @param _port tcp port of node | |
| * @param _raftport raft port of node | |
| * @param _orgId org id to which the enode belongs | |
| */ | |
| function addNode(string memory _enodeId, string memory _ip, uint16 _port, uint16 _raftport, string memory _orgId) public | |
| onlyImplementation | |
| enodeDoesNotExists(_enodeId) { | |
| numberOfNodes++; | |
| enodeIdToIndex[keccak256(abi.encode(_enodeId))] = numberOfNodes; | |
| nodeList.push(NodeDetails(_enodeId, _ip, _port, _raftport, _orgId, 1)); | |
| emit NodeProposed(_enodeId, _ip, _port, _raftport, _orgId); | |
| } | |
| /** @notice called org admins to add new enodes to the org or sub orgs | |
| * @param _enodeId enode id | |
| * @param _ip IP of node | |
| * @param _port tcp port of node | |
| * @param _raftport raft port of node | |
| * @param _orgId org or sub org id to which the enode belongs | |
| */ | |
| function addOrgNode(string memory _enodeId, string memory _ip, uint16 _port, uint16 _raftport, string memory _orgId) public | |
| onlyImplementation | |
| enodeDoesNotExists(_enodeId) { | |
| numberOfNodes++; | |
| enodeIdToIndex[keccak256(abi.encode(_enodeId))] = numberOfNodes; | |
| nodeList.push(NodeDetails(_enodeId, _ip, _port, _raftport, _orgId, 2)); | |
| emit NodeApproved(_enodeId, _ip, _port, _raftport, _orgId); | |
| } | |
| /** @notice function to approve the node addition. only called at the time | |
| master org creation by network admin | |
| * @param _enodeId enode id | |
| * @param _ip IP of node | |
| * @param _port tcp port of node | |
| * @param _raftport raft port of node | |
| * @param _orgId org or sub org id to which the enode belongs | |
| */ | |
| function approveNode(string memory _enodeId, string memory _ip, uint16 _port, uint16 _raftport, string memory _orgId) public | |
| onlyImplementation | |
| enodeExists(_enodeId) { | |
| // node should belong to the passed org | |
| require(_checkOrg(_enodeId, _orgId), "enode id does not belong to the passed org id"); | |
| require(_getNodeStatus(_enodeId) == 1, "nothing pending for approval"); | |
| uint256 nodeIndex = _getNodeIndex(_enodeId); | |
| if (keccak256(abi.encode(nodeList[nodeIndex].ip)) != keccak256(abi.encode(_ip)) || nodeList[nodeIndex].port != _port || nodeList[nodeIndex].raftPort != _raftport) { | |
| return; | |
| } | |
| nodeList[nodeIndex].status = 2; | |
| emit NodeApproved(nodeList[nodeIndex].enodeId, _ip, _port, _raftport, nodeList[nodeIndex].orgId); | |
| } | |
| /** @notice updates the node status. can be called for deactivating/ | |
| blacklisting and reactivating a deactivated node | |
| * @param _enodeId enode id | |
| * @param _ip IP of node | |
| * @param _port tcp port of node | |
| * @param _raftport raft port of node | |
| * @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 | |
| 4 - initiate the recovery of a blacklisted node | |
| 5 - blacklisted node recovery fully approved. mark to active | |
| */ | |
| function updateNodeStatus(string memory _enodeId, string memory _ip, uint16 _port, uint16 _raftport, string memory _orgId, uint256 _action) public | |
| onlyImplementation | |
| enodeExists(_enodeId) { | |
| // node should belong to the org | |
| require(_checkOrg(_enodeId, _orgId), "enode id does not belong to the passed org"); | |
| require((_action == 1 || _action == 2 || _action == 3 || _action == 4 || _action == 5), | |
| "invalid operation. wrong action passed"); | |
| uint256 nodeIndex = _getNodeIndex(_enodeId); | |
| if (keccak256(abi.encode(nodeList[nodeIndex].ip)) != keccak256(abi.encode(_ip)) || nodeList[nodeIndex].port != _port || nodeList[nodeIndex].raftPort != _raftport) { | |
| return; | |
| } | |
| if (_action == 1) { | |
| require(_getNodeStatus(_enodeId) == 2, "operation cannot be performed"); | |
| nodeList[nodeIndex].status = 3; | |
| emit NodeDeactivated(_enodeId, _ip, _port, _raftport, _orgId); | |
| } | |
| else if (_action == 2) { | |
| require(_getNodeStatus(_enodeId) == 3, "operation cannot be performed"); | |
| nodeList[nodeIndex].status = 2; | |
| emit NodeActivated(_enodeId, _ip, _port, _raftport, _orgId); | |
| } | |
| else if (_action == 3) { | |
| nodeList[nodeIndex].status = 4; | |
| emit NodeBlacklisted(_enodeId, _ip, _port, _raftport, _orgId); | |
| } else if (_action == 4) { | |
| // node should be in blacklisted state | |
| require(_getNodeStatus(_enodeId) == 4, "operation cannot be performed"); | |
| nodeList[nodeIndex].status = 5; | |
| emit NodeRecoveryInitiated(_enodeId, _ip, _port, _raftport, _orgId); | |
| } else { | |
| // node should be in initiated recovery state | |
| require(_getNodeStatus(_enodeId) == 5, "operation cannot be performed"); | |
| nodeList[nodeIndex].status = 2; | |
| emit NodeRecoveryCompleted(_enodeId, _ip, _port, _raftport, _orgId); | |
| } | |
| } | |
| // private functions | |
| /** @notice returns the node index for given enode id | |
| * @param _enodeId enode id | |
| * @return trur or false | |
| */ | |
| function _getNodeIndex(string memory _enodeId) internal view | |
| returns (uint256) { | |
| return enodeIdToIndex[keccak256(abi.encode(_enodeId))] - 1; | |
| } | |
| /** @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 | |
| */ | |
| function _checkOrg(string memory _enodeId, string memory _orgId) internal view | |
| returns (bool) { | |
| return (keccak256(abi.encode(nodeList[_getNodeIndex(_enodeId)].orgId)) == keccak256(abi.encode(_orgId))); | |
| } | |
| /** @notice returns the node status for a given enode id | |
| * @param _enodeId enode id | |
| * @return node status | |
| */ | |
| function _getNodeStatus(string memory _enodeId) internal view returns (uint256) { | |
| if (enodeIdToIndex[keccak256(abi.encode(_enodeId))] == 0) { | |
| return 0; | |
| } | |
| return nodeList[_getNodeIndex(_enodeId)].status; | |
| } | |
| /** @notice checks if the node is allowed to connect or not | |
| * @param _enodeId enode id | |
| * @param _ip IP of node | |
| * @param _port tcp port of node | |
| * @return bool indicating if the node is allowed to connect or not | |
| */ | |
| function connectionAllowed(string memory _enodeId, string memory _ip, uint16 _port) public view onlyImplementation | |
| returns (bool){ | |
| if (enodeIdToIndex[keccak256(abi.encode(_enodeId))] == 0) { | |
| return false; | |
| } | |
| uint256 nodeIndex = _getNodeIndex(_enodeId); | |
| if (nodeList[nodeIndex].status == 2 && keccak256(abi.encode(nodeList[nodeIndex].ip)) == keccak256(abi.encode(_ip))) { | |
| return true; | |
| } | |
| return false; | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| pragma solidity ^0.5.3; | |
| import "./PermissionsUpgradable.sol"; | |
| /** @title Organization manager contract | |
| * @notice This contract holds implementation logic for all org management | |
| functionality. This can be called only by the implementation | |
| contract only. 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 the status of the organization is denoted by a set of integer | |
| values. These are as below: | |
| 0 - Not in list, | |
| 1 - Org proposed for approval by network admins | |
| 2 - Org in Approved status | |
| 3 - Org proposed for suspension and pending approval by network admins | |
| 4 - Org in Suspended, | |
| Once the node is blacklisted no further activity on the node is | |
| possible. | |
| */ | |
| contract OrgManager { | |
| string private adminOrgId; | |
| PermissionsUpgradable private permUpgradable; | |
| // checks if first time network boot up has happened or not | |
| bool private networkBoot = false; | |
| // variables which control the breadth and depth of the sub org tree | |
| uint private DEPTH_LIMIT = 4; | |
| uint private BREADTH_LIMIT = 4; | |
| struct OrgDetails { | |
| string orgId; | |
| uint status; | |
| string parentId; | |
| string fullOrgId; | |
| string ultParent; | |
| uint pindex; | |
| uint level; | |
| uint [] subOrgIndexList; | |
| } | |
| OrgDetails [] private orgList; | |
| mapping(bytes32 => uint) private OrgIndex; | |
| uint private orgNum = 0; | |
| // events related to Master Org add | |
| event OrgApproved(string _orgId, string _porgId, string _ultParent, | |
| uint _level, uint _status); | |
| event OrgPendingApproval(string _orgId, string _porgId, string _ultParent, | |
| uint _level, uint _status); | |
| event OrgSuspended(string _orgId, string _porgId, string _ultParent, | |
| uint _level); | |
| event OrgSuspensionRevoked(string _orgId, string _porgId, string _ultParent, | |
| uint _level); | |
| /** @notice confirms that the caller is the address of implementation | |
| contract | |
| */ | |
| modifier onlyImplementation{ | |
| require(msg.sender == permUpgradable.getPermImpl(), "invalid caller"); | |
| _; | |
| } | |
| /** @notice checks if the org id does not exists | |
| * @param _orgId - org id | |
| * @return true if org does not exist | |
| */ | |
| modifier orgDoesNotExist(string memory _orgId) { | |
| require(checkOrgExists(_orgId) == false, "org exists"); | |
| _; | |
| } | |
| /** @notice checks if the org id does exists | |
| * @param _orgId - org id | |
| * @return true if org exists | |
| */ | |
| modifier orgExists(string memory _orgId) { | |
| require(checkOrgExists(_orgId) == true, "org does not exist"); | |
| _; | |
| } | |
| /** @notice constructor. sets the permissions upgradable address | |
| */ | |
| constructor (address _permUpgradable) public { | |
| permUpgradable = PermissionsUpgradable(_permUpgradable); | |
| } | |
| /** @notice called at the time of network initialization. sets the depth | |
| breadth for sub orgs creation. and creates the default network | |
| admin org as per config file | |
| */ | |
| function setUpOrg(string calldata _orgId, uint256 _breadth, uint256 _depth) external | |
| onlyImplementation { | |
| _addNewOrg("", _orgId, 1, 2); | |
| DEPTH_LIMIT = _depth; | |
| BREADTH_LIMIT = _breadth; | |
| } | |
| /** @notice function for adding a new master org to the network | |
| * @param _orgId unique org id to be added | |
| * @dev org will be added if it does exist | |
| */ | |
| function addOrg(string calldata _orgId) external | |
| onlyImplementation | |
| orgDoesNotExist(_orgId) { | |
| _addNewOrg("", _orgId, 1, 1); | |
| } | |
| /** @notice function for adding a new sub org under a parent org | |
| * @param _pOrgId unique org id to be added | |
| * @dev org will be added if it does exist | |
| */ | |
| function addSubOrg(string calldata _pOrgId, string calldata _orgId) external | |
| onlyImplementation | |
| orgDoesNotExist(string(abi.encodePacked(_pOrgId, ".", _orgId))) { | |
| _addNewOrg(_pOrgId, _orgId, 2, 2); | |
| } | |
| /** @notice updates the status of a master org. | |
| * @param _orgId unique org id to be added | |
| * @param _action action being performed | |
| * @dev status cannot be updated for sub orgs. | |
| This function can be called for the following actions: | |
| 1 - to suspend an org | |
| 2 - to activate the org back | |
| */ | |
| function updateOrg(string calldata _orgId, uint256 _action) external | |
| onlyImplementation | |
| orgExists(_orgId) | |
| returns (uint256){ | |
| require((_action == 1 || _action == 2), "invalid action. operation not allowed"); | |
| uint256 id = _getOrgIndex(_orgId); | |
| require(orgList[id].level == 1, "not a master org. operation not allowed"); | |
| uint256 reqStatus; | |
| uint256 pendingOp; | |
| if (_action == 1) { | |
| reqStatus = 2; | |
| pendingOp = 2; | |
| } | |
| else if (_action == 2) { | |
| reqStatus = 4; | |
| pendingOp = 3; | |
| } | |
| require(checkOrgStatus(_orgId, reqStatus) == true, | |
| "org status does not allow the operation"); | |
| if (_action == 1) { | |
| _suspendOrg(_orgId); | |
| } | |
| else { | |
| _revokeOrgSuspension(_orgId); | |
| } | |
| return pendingOp; | |
| } | |
| /** @notice function to approve org status change for master orgs | |
| * @param _orgId unique org id to be added | |
| * @param _action approval for action | |
| * @dev status cannot be updated for sub orgs. | |
| This function can be called for the following actions: | |
| 1 - to suspend an org | |
| 2 - to activate the org back | |
| */ | |
| function approveOrgStatusUpdate(string calldata _orgId, uint256 _action) external | |
| onlyImplementation | |
| orgExists(_orgId) { | |
| if (_action == 1) { | |
| _approveOrgSuspension(_orgId); | |
| } | |
| else { | |
| _approveOrgRevokeSuspension(_orgId); | |
| } | |
| } | |
| /** @notice function to approve org status change for master orgs | |
| * @param _orgId unique org id to be added | |
| */ | |
| function approveOrg(string calldata _orgId) external | |
| onlyImplementation { | |
| require(checkOrgStatus(_orgId, 1) == true, "nothing to approve"); | |
| uint256 id = _getOrgIndex(_orgId); | |
| orgList[id].status = 2; | |
| emit OrgApproved(orgList[id].orgId, orgList[id].parentId, | |
| orgList[id].ultParent, orgList[id].level, 2); | |
| } | |
| /** @notice returns org info for a given org index | |
| * @param _orgIndex org index | |
| * @return org id | |
| * @return parent org id | |
| * @return ultimate parent id | |
| * @return level in the org tree | |
| * @return status | |
| */ | |
| function getOrgInfo(uint256 _orgIndex) external view returns (string memory, | |
| string memory, string memory, uint256, uint256) { | |
| return (orgList[_orgIndex].orgId, orgList[_orgIndex].parentId, | |
| orgList[_orgIndex].ultParent, orgList[_orgIndex].level, orgList[_orgIndex].status); | |
| } | |
| /** @notice returns org info for a given org id | |
| * @param _orgId org id | |
| * @return org id | |
| * @return parent org id | |
| * @return ultimate parent id | |
| * @return level in the org tree | |
| * @return status | |
| */ | |
| function getOrgDetails(string calldata _orgId) external view returns (string memory, | |
| string memory, string memory, uint256, uint256) { | |
| if (!checkOrgExists(_orgId)) { | |
| return (_orgId, "", "", 0, 0); | |
| } | |
| uint256 _orgIndex = _getOrgIndex(_orgId); | |
| return (orgList[_orgIndex].orgId, orgList[_orgIndex].parentId, | |
| orgList[_orgIndex].ultParent, orgList[_orgIndex].level, orgList[_orgIndex].status); | |
| } | |
| /** @notice returns the array of sub org indexes for the given org | |
| * @param _orgId org id | |
| * @return array of sub org indexes | |
| */ | |
| function getSubOrgIndexes(string calldata _orgId) external view returns (uint[] memory) { | |
| require(checkOrgExists(_orgId) == true, "org does not exist"); | |
| uint256 _orgIndex = _getOrgIndex(_orgId); | |
| return (orgList[_orgIndex].subOrgIndexList); | |
| } | |
| /** @notice returns the master org id for the given org or sub org | |
| * @param _orgId org id | |
| * @return master org id | |
| */ | |
| function getUltimateParent(string calldata _orgId) external view | |
| onlyImplementation | |
| returns (string memory) { | |
| return orgList[_getOrgIndex(_orgId)].ultParent; | |
| } | |
| /** @notice returns the total number of orgs in the network | |
| * @return master org id | |
| */ | |
| function getNumberOfOrgs() public view returns (uint256) { | |
| return orgList.length; | |
| } | |
| /** @notice confirms that org status is same as passed status | |
| * @param _orgId org id | |
| * @param _orgStatus org status | |
| * @return true or false | |
| */ | |
| function checkOrgStatus(string memory _orgId, uint256 _orgStatus) | |
| public view returns (bool){ | |
| if (OrgIndex[keccak256(abi.encodePacked(_orgId))] == 0) { | |
| return false; | |
| } | |
| uint256 id = _getOrgIndex(_orgId); | |
| return ((OrgIndex[keccak256(abi.encodePacked(_orgId))] != 0) | |
| && orgList[id].status == _orgStatus); | |
| } | |
| /** @notice confirms that org status either active or pending suspension | |
| * @param _orgId org id | |
| * @return true or false | |
| */ | |
| function checkOrgActive(string memory _orgId) | |
| public view returns (bool){ | |
| if (OrgIndex[keccak256(abi.encodePacked(_orgId))] != 0) { | |
| uint256 id = _getOrgIndex(_orgId); | |
| if (orgList[id].status == 2 || orgList[id].status == 3) { | |
| uint256 uid = _getOrgIndex(orgList[id].ultParent); | |
| if (orgList[uid].status == 2 || orgList[uid].status == 3) { | |
| return true; | |
| } | |
| } | |
| } | |
| return false; | |
| } | |
| /** @notice confirms if the org exists in the network | |
| * @param _orgId org id | |
| * @return true or false | |
| */ | |
| function checkOrgExists(string memory _orgId) public view returns (bool) { | |
| return (!(OrgIndex[keccak256(abi.encodePacked(_orgId))] == 0)); | |
| } | |
| /** @notice updates the org status to suspended | |
| * @param _orgId org id | |
| */ | |
| function _suspendOrg(string memory _orgId) internal { | |
| require(checkOrgStatus(_orgId, 2) == true, | |
| "org not in approved status. operation cannot be done"); | |
| uint256 id = _getOrgIndex(_orgId); | |
| orgList[id].status = 3; | |
| emit OrgPendingApproval(orgList[id].orgId, orgList[id].parentId, | |
| orgList[id].ultParent, orgList[id].level, 3); | |
| } | |
| /** @notice revokes the suspension of an org | |
| * @param _orgId org id | |
| */ | |
| function _revokeOrgSuspension(string memory _orgId) internal { | |
| require(checkOrgStatus(_orgId, 4) == true, "org not in suspended state"); | |
| uint256 id = _getOrgIndex(_orgId); | |
| orgList[id].status = 5; | |
| emit OrgPendingApproval(orgList[id].orgId, orgList[id].parentId, | |
| orgList[id].ultParent, orgList[id].level, 5); | |
| } | |
| /** @notice approval function for org suspension activity | |
| * @param _orgId org id | |
| */ | |
| function _approveOrgSuspension(string memory _orgId) internal { | |
| require(checkOrgStatus(_orgId, 3) == true, "nothing to approve"); | |
| uint256 id = _getOrgIndex(_orgId); | |
| orgList[id].status = 4; | |
| emit OrgSuspended(orgList[id].orgId, orgList[id].parentId, | |
| orgList[id].ultParent, orgList[id].level); | |
| } | |
| /** @notice approval function for revoking org suspension | |
| * @param _orgId org id | |
| */ | |
| function _approveOrgRevokeSuspension(string memory _orgId) internal { | |
| require(checkOrgStatus(_orgId, 5) == true, "nothing to approve"); | |
| uint256 id = _getOrgIndex(_orgId); | |
| orgList[id].status = 2; | |
| emit OrgSuspensionRevoked(orgList[id].orgId, orgList[id].parentId, | |
| orgList[id].ultParent, orgList[id].level); | |
| } | |
| /** @notice function to add a new organization | |
| * @param _pOrgId parent org id | |
| * @param _orgId org id | |
| * @param _level level in org hierarchy | |
| * @param _status status of the org | |
| */ | |
| function _addNewOrg(string memory _pOrgId, string memory _orgId, | |
| uint256 _level, uint _status) internal { | |
| bytes32 pid = ""; | |
| bytes32 oid = ""; | |
| uint256 parentIndex = 0; | |
| if (_level == 1) {//root | |
| oid = keccak256(abi.encodePacked(_orgId)); | |
| } else { | |
| pid = keccak256(abi.encodePacked(_pOrgId)); | |
| oid = keccak256(abi.encodePacked(_pOrgId, ".", _orgId)); | |
| } | |
| orgNum++; | |
| OrgIndex[oid] = orgNum; | |
| uint256 id = orgList.length++; | |
| if (_level == 1) { | |
| orgList[id].level = _level; | |
| orgList[id].pindex = 0; | |
| orgList[id].fullOrgId = _orgId; | |
| orgList[id].ultParent = _orgId; | |
| } else { | |
| parentIndex = OrgIndex[pid] - 1; | |
| require(orgList[parentIndex].subOrgIndexList.length < BREADTH_LIMIT, | |
| "breadth level exceeded"); | |
| require(orgList[parentIndex].level < DEPTH_LIMIT, | |
| "depth level exceeded"); | |
| orgList[id].level = orgList[parentIndex].level + 1; | |
| orgList[id].pindex = parentIndex; | |
| orgList[id].ultParent = orgList[parentIndex].ultParent; | |
| uint256 subOrgId = orgList[parentIndex].subOrgIndexList.length++; | |
| orgList[parentIndex].subOrgIndexList[subOrgId] = id; | |
| orgList[id].fullOrgId = string(abi.encodePacked(_pOrgId, ".", _orgId)); | |
| } | |
| orgList[id].orgId = _orgId; | |
| orgList[id].parentId = _pOrgId; | |
| orgList[id].status = _status; | |
| if (_status == 1) { | |
| emit OrgPendingApproval(orgList[id].orgId, orgList[id].parentId, | |
| orgList[id].ultParent, orgList[id].level, 1); | |
| } | |
| else { | |
| emit OrgApproved(orgList[id].orgId, orgList[id].parentId, | |
| orgList[id].ultParent, orgList[id].level, 2); | |
| } | |
| } | |
| /** @notice returns the org index from the org list for the given org | |
| * @return org index | |
| */ | |
| function _getOrgIndex(string memory _orgId) private view returns (uint){ | |
| return OrgIndex[keccak256(abi.encodePacked(_orgId))] - 1; | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| pragma solidity ^0.5.3; | |
| import "./RoleManager.sol"; | |
| import "./AccountManager.sol"; | |
| import "./VoterManager.sol"; | |
| import "./NodeManager.sol"; | |
| import "./OrgManager.sol"; | |
| import "./PermissionsUpgradable.sol"; | |
| /** @title Permissions Implementation Contract | |
| * @notice This contract holds implementation logic for all permissions | |
| related functionality. This can be called only by the interface | |
| contract. | |
| */ | |
| contract PermissionsImplementation { | |
| AccountManager private accountManager; | |
| RoleManager private roleManager; | |
| VoterManager private voterManager; | |
| NodeManager private nodeManager; | |
| OrgManager private orgManager; | |
| PermissionsUpgradable private permUpgradable; | |
| string private adminOrg; | |
| string private adminRole; | |
| string private orgAdminRole; | |
| uint256 private fullAccess = 3; | |
| /** @dev this variable is meant for tracking the initial network boot up | |
| once the network boot up is done the value is set to true | |
| */ | |
| bool private networkBoot = false; | |
| event PermissionsInitialized(bool _networkBootStatus); | |
| /** @notice modifier to confirm that caller is the interface contract | |
| */ | |
| modifier onlyInterface{ | |
| require(msg.sender == permUpgradable.getPermInterface(), | |
| "can be called by interface contract only"); | |
| _; | |
| } | |
| /** @notice modifier to confirm that caller is the upgradable contract | |
| */ | |
| modifier onlyUpgradeable { | |
| require(msg.sender == address(permUpgradable), "invalid caller"); | |
| _; | |
| } | |
| /** @notice confirms if the network boot status is equal to passed value | |
| * @param _status true/false | |
| */ | |
| modifier networkBootStatus(bool _status){ | |
| require(networkBoot == _status, "Incorrect network boot status"); | |
| _; | |
| } | |
| /** @notice confirms that the account passed is network admin account | |
| * @param _account account id | |
| */ | |
| modifier networkAdmin(address _account) { | |
| require(isNetworkAdmin(_account) == true, "account is not a network admin account"); | |
| _; | |
| } | |
| /** @notice confirms that the account passed is org admin account | |
| * @param _account account id | |
| * @param _orgId org id to which the account belongs | |
| */ | |
| modifier orgAdmin(address _account, string memory _orgId) { | |
| require(isOrgAdmin(_account, _orgId) == true, "account is not a org admin account"); | |
| _; | |
| } | |
| /** @notice confirms that org does not exist | |
| * @param _orgId org id | |
| */ | |
| modifier orgNotExists(string memory _orgId) { | |
| require(_checkOrgExists(_orgId) != true, "org exists"); | |
| _; | |
| } | |
| /** @notice confirms that org exists | |
| * @param _orgId org id | |
| */ | |
| modifier orgExists(string memory _orgId) { | |
| require(_checkOrgExists(_orgId) == true, "org does not exist"); | |
| _; | |
| } | |
| /** @notice checks of the passed org id is in approved status | |
| * @param _orgId org id | |
| */ | |
| modifier orgApproved(string memory _orgId) { | |
| require(checkOrgApproved(_orgId) == true, "org not in approved status"); | |
| _; | |
| } | |
| /** @notice constructor accepts the contracts addresses of other deployed | |
| contracts of the permissions model | |
| * @param _permUpgradable - address of permissions upgradable contract | |
| * @param _orgManager - address of org manager contract | |
| * @param _rolesManager - address of role manager contract | |
| * @param _accountManager - address of account manager contract | |
| * @param _voterManager - address of voter manager contract | |
| * @param _nodeManager - address of node manager contract | |
| */ | |
| constructor (address _permUpgradable, address _orgManager, address _rolesManager, | |
| address _accountManager, address _voterManager, address _nodeManager) public { | |
| permUpgradable = PermissionsUpgradable(_permUpgradable); | |
| orgManager = OrgManager(_orgManager); | |
| roleManager = RoleManager(_rolesManager); | |
| accountManager = AccountManager(_accountManager); | |
| voterManager = VoterManager(_voterManager); | |
| nodeManager = NodeManager(_nodeManager); | |
| } | |
| // initial set up related functions | |
| /** @notice for permissions its necessary to define the initial admin org | |
| id, network admin role id and default org admin role id. this | |
| sets these values at the time of network boot up | |
| * @param _nwAdminOrg - address of permissions upgradable contract | |
| * @param _nwAdminRole - address of org manager contract | |
| * @param _oAdminRole - address of role manager contract | |
| * @dev this function will be executed only once as part of the boot up | |
| */ | |
| function setPolicy(string calldata _nwAdminOrg, string calldata _nwAdminRole, | |
| string calldata _oAdminRole) external onlyInterface | |
| networkBootStatus(false) { | |
| adminOrg = _nwAdminOrg; | |
| adminRole = _nwAdminRole; | |
| orgAdminRole = _oAdminRole; | |
| } | |
| /** @notice when migrating implementation contract, the values of these | |
| key values need to be set from the previous implementation | |
| contract. this function allows these values to be set | |
| * @param _nwAdminOrg - address of permissions upgradable contract | |
| * @param _nwAdminRole - address of org manager contract | |
| * @param _oAdminRole - address of role manager contract | |
| * @param _networkBootStatus - network boot status true/false | |
| */ | |
| function setMigrationPolicy(string calldata _nwAdminOrg, string calldata _nwAdminRole, | |
| string calldata _oAdminRole, bool _networkBootStatus) external onlyUpgradeable | |
| networkBootStatus(false) { | |
| adminOrg = _nwAdminOrg; | |
| adminRole = _nwAdminRole; | |
| orgAdminRole = _oAdminRole; | |
| networkBoot = _networkBootStatus; | |
| } | |
| /** @notice called at the time of network initialization. sets up | |
| network admin org with allowed sub org depth and breadth | |
| creates the network admin for the network admin org | |
| sets the default values required by account manager contract | |
| * @param _breadth - number of sub orgs allowed at parent level | |
| * @param _depth - levels of sub org nesting allowed at parent level | |
| */ | |
| function init(uint256 _breadth, uint256 _depth) external | |
| onlyInterface | |
| networkBootStatus(false) { | |
| orgManager.setUpOrg(adminOrg, _breadth, _depth); | |
| roleManager.addRole(adminRole, adminOrg, fullAccess, true, true); | |
| accountManager.setDefaults(adminRole, orgAdminRole); | |
| } | |
| /** @notice as a part of network initialization add all nodes which | |
| are part of static-nodes.json as nodes belonging to | |
| network admin org | |
| * @param _enodeId - enode id | |
| * @param _ip IP of node | |
| * @param _port tcp port of node | |
| * @param _raftport raft port of node | |
| */ | |
| function addAdminNode(string calldata _enodeId, string calldata _ip, uint16 _port, uint16 _raftport) external | |
| onlyInterface | |
| networkBootStatus(false) { | |
| nodeManager.addAdminNode(_enodeId, _ip, _port, _raftport, adminOrg); | |
| } | |
| /** @notice as a part of network initialization add all accounts which are | |
| passed via permission-config.json as network administrator | |
| accounts | |
| * @param _account - account id | |
| */ | |
| function addAdminAccount(address _account) external | |
| onlyInterface | |
| networkBootStatus(false) { | |
| updateVoterList(adminOrg, _account, true); | |
| accountManager.assignAdminRole(_account, adminOrg, adminRole, 2); | |
| } | |
| /** @notice once the network initialization is complete, sets the network | |
| boot status to true | |
| * @return network boot status | |
| * @dev this will be called only once from geth as a part of | |
| * @dev network initialization | |
| */ | |
| function updateNetworkBootStatus() external | |
| onlyInterface | |
| networkBootStatus(false) | |
| returns (bool){ | |
| networkBoot = true; | |
| emit PermissionsInitialized(networkBoot); | |
| return networkBoot; | |
| } | |
| /** @notice function to add a new organization to the network. creates org | |
| record and marks it as pending approval. adds the passed node | |
| node manager contract. adds the account with org admin role to | |
| account manager contracts. creates voting record for approval | |
| by other network admin accounts | |
| * @param _orgId unique organization id | |
| * @param _enodeId enode id linked to the organization | |
| * @param _ip IP of node | |
| * @param _port tcp port of node | |
| * @param _raftport raft port of node | |
| * @param _account account id. this will have the org admin privileges | |
| */ | |
| function addOrg(string memory _orgId, string memory _enodeId, | |
| string memory _ip, uint16 _port, uint16 _raftport, address _account, address _caller) public | |
| onlyInterface | |
| { | |
| require(networkBoot == true, "Incorrect network boot status"); | |
| require(isNetworkAdmin(_caller) == true, "account is not a network admin account"); | |
| voterManager.addVotingItem(adminOrg, _orgId, _enodeId, _account, 1); | |
| orgManager.addOrg(_orgId); | |
| nodeManager.addNode(_enodeId, _ip, _port, _raftport, _orgId); | |
| require(validateAccount(_account, _orgId) == true, | |
| "Operation cannot be performed"); | |
| accountManager.assignAdminRole(_account, _orgId, orgAdminRole, 1); | |
| } | |
| /** @notice functions to approve a pending approval org record by networ | |
| admin account. once majority votes are received the org is | |
| marked as approved | |
| * @param _orgId unique organization id | |
| * @param _enodeId enode id linked to the organization | |
| * @param _ip IP of node | |
| * @param _port tcp port of node | |
| * @param _raftport raft port of node | |
| * @param _account account id this will have the org admin privileges | |
| */ | |
| function approveOrg(string memory _orgId, string memory _enodeId, string memory _ip, uint16 _port, uint16 _raftport, | |
| address _account, address _caller) public | |
| onlyInterface | |
| { | |
| require(isNetworkAdmin(_caller) == true, "account is not a network admin account"); | |
| require(_checkOrgStatus(_orgId, 1) == true, "Nothing to approve"); | |
| if ((processVote(adminOrg, _caller, 1))) { | |
| orgManager.approveOrg(_orgId); | |
| roleManager.addRole(orgAdminRole, _orgId, fullAccess, true, true); | |
| nodeManager.approveNode(_enodeId, _ip, _port, _raftport, _orgId); | |
| accountManager.addNewAdmin(_orgId, _account); | |
| } | |
| } | |
| /** @notice function to create a sub org under a given parent org. | |
| * @param _pOrgId parent org id under which the sub org is being added | |
| * @param _orgId unique id for the sub organization | |
| * @param _enodeId enode id linked to the sjb organization | |
| * @param _ip IP of node | |
| * @param _port tcp port of node | |
| * @param _raftport raft port of node | |
| * @dev _enodeId is optional. parent org id should contain the complete | |
| org hierarchy from master org id to the immediate parent. The org | |
| hierarchy is separated by. For example, if master org ABC has a | |
| sub organization SUB1, then while creating the sub organization at | |
| SUB1 level, the parent org should be given as ABC.SUB1 | |
| */ | |
| function addSubOrg(string calldata _pOrgId, string calldata _orgId, | |
| string calldata _enodeId, string calldata _ip, uint16 _port, uint16 _raftport, address _caller) external onlyInterface | |
| orgExists(_pOrgId) orgAdmin(_caller, _pOrgId) { | |
| orgManager.addSubOrg(_pOrgId, _orgId); | |
| string memory pOrgId = string(abi.encodePacked(_pOrgId, ".", _orgId)); | |
| if (bytes(_enodeId).length > 0) { | |
| nodeManager.addOrgNode(_enodeId, _ip, _port, _raftport, pOrgId); | |
| } | |
| } | |
| /** @notice function to update the org status. it updates the org status | |
| and adds a voting item for network admins to approve | |
| * @param _orgId unique id of the organization | |
| * @param _action 1 for suspending an org and 2 for revoke of suspension | |
| */ | |
| function updateOrgStatus(string calldata _orgId, uint256 _action, address _caller) | |
| external onlyInterface networkAdmin(_caller) { | |
| uint256 pendingOp; | |
| pendingOp = orgManager.updateOrg(_orgId, _action); | |
| voterManager.addVotingItem(adminOrg, _orgId, "", address(0), pendingOp); | |
| } | |
| /** @notice function to approve org status change. the org status is | |
| changed once the majority votes are received from network | |
| admin accounts. | |
| * @param _orgId unique id for the sub organization | |
| * @param _action 1 for suspending an org and 2 for revoke of suspension | |
| */ | |
| function approveOrgStatus(string calldata _orgId, uint256 _action, address _caller) | |
| external onlyInterface networkAdmin(_caller) { | |
| require((_action == 1 || _action == 2), "Operation not allowed"); | |
| uint256 pendingOp; | |
| uint256 orgStatus; | |
| if (_action == 1) { | |
| pendingOp = 2; | |
| orgStatus = 3; | |
| } | |
| else if (_action == 2) { | |
| pendingOp = 3; | |
| orgStatus = 5; | |
| } | |
| require(_checkOrgStatus(_orgId, orgStatus) == true, "operation not allowed"); | |
| if ((processVote(adminOrg, _caller, pendingOp))) { | |
| orgManager.approveOrgStatusUpdate(_orgId, _action); | |
| } | |
| } | |
| // Role related functions | |
| /** @notice function to add new role definition to an organization | |
| can be executed by the org admin account only | |
| * @param _roleId unique id for the role | |
| * @param _orgId unique id of the organization to which the role belongs | |
| * @param _access account access type allowed for the role | |
| * @param _voter bool indicates if the role is voter role or not | |
| * @param _admin bool indicates if the role is an admin role | |
| * @dev account access type can have of the following four values: | |
| 0 - Read only | |
| 1 - value transfer | |
| 2 - contract deploy | |
| 3 - full access | |
| 4 - contract call | |
| 5 - value transfer and contract call | |
| 6 - value transfer and contract deploy | |
| 7 - contract call and deploy | |
| */ | |
| function addNewRole(string calldata _roleId, string calldata _orgId, | |
| uint256 _access, bool _voter, bool _admin, address _caller) external | |
| onlyInterface orgApproved(_orgId) orgAdmin(_caller, _orgId) { | |
| //add new roles can be created by org admins only | |
| roleManager.addRole(_roleId, _orgId, _access, _voter, _admin); | |
| } | |
| /** @notice function to remove a role definition from an organization | |
| can be executed by the org admin account only | |
| * @param _roleId unique id for the role | |
| * @param _orgId unique id of the organization to which the role belongs | |
| */ | |
| function removeRole(string calldata _roleId, string calldata _orgId, | |
| address _caller) external onlyInterface orgApproved(_orgId) | |
| orgAdmin(_caller, _orgId) { | |
| require(((keccak256(abi.encode(_roleId)) != keccak256(abi.encode(adminRole))) && | |
| (keccak256(abi.encode(_roleId)) != keccak256(abi.encode(orgAdminRole)))), | |
| "admin roles cannot be removed"); | |
| roleManager.removeRole(_roleId, _orgId); | |
| } | |
| // Account related functions | |
| /** @notice function to assign network admin/org admin role to an account | |
| this can be executed by network admin accounts only. it assigns | |
| the role to the accounts and creates voting record for network | |
| admin accounts | |
| * @param _orgId unique id of the organization to which the account belongs | |
| * @param _account account id | |
| * @param _roleId role id to be assigned to the account | |
| */ | |
| function assignAdminRole(string calldata _orgId, address _account, | |
| string calldata _roleId, address _caller) external | |
| onlyInterface orgExists(_orgId) networkAdmin(_caller) { | |
| accountManager.assignAdminRole(_account, _orgId, _roleId, 1); | |
| //add voting item | |
| voterManager.addVotingItem(adminOrg, _orgId, "", _account, 4); | |
| } | |
| /** @notice function to approve network admin/org admin role assigment | |
| this can be executed by network admin accounts only. | |
| * @param _orgId unique id of the organization to which the account belongs | |
| * @param _account account id | |
| */ | |
| function approveAdminRole(string calldata _orgId, address _account, | |
| address _caller) external onlyInterface networkAdmin(_caller) { | |
| if ((processVote(adminOrg, _caller, 4))) { | |
| (bool ret, address account) = accountManager.removeExistingAdmin(_orgId); | |
| if (ret) { | |
| updateVoterList(adminOrg, account, false); | |
| } | |
| bool ret1 = accountManager.addNewAdmin(_orgId, _account); | |
| if (ret1) { | |
| updateVoterList(adminOrg, _account, true); | |
| } | |
| } | |
| } | |
| /** @notice function to update account status. can be executed by org admin | |
| account only. | |
| * @param _orgId unique id of the organization to which the account belongs | |
| * @param _account account id | |
| * @param _action 1-suspend 2-activate back 3-blacklist | |
| */ | |
| function updateAccountStatus(string calldata _orgId, address _account, | |
| uint256 _action, address _caller) external onlyInterface | |
| orgAdmin(_caller, _orgId) { | |
| // ensure that the action passed to this call is proper and is not | |
| // called with action 4 and 5 which are actions for blacklisted account | |
| // recovery | |
| require((_action == 1 || _action == 2 || _action == 3), | |
| "invalid action. operation not allowed"); | |
| accountManager.updateAccountStatus(_orgId, _account, _action); | |
| } | |
| // Node related functions | |
| /** @notice function to add a new node to the organization. can be invoked | |
| org admin account only | |
| * @param _orgId unique id of the organization to which the account belongs | |
| * @param _enodeId enode id being dded to the org | |
| * @param _ip IP of node | |
| * @param _port tcp port of node | |
| * @param _raftport raft port of node | |
| */ | |
| function addNode(string memory _orgId, string memory _enodeId, string memory _ip, uint16 _port, uint16 _raftport, address _caller) | |
| public | |
| onlyInterface | |
| orgApproved(_orgId) | |
| { | |
| // check that the node is not part of another org | |
| require(isOrgAdmin(_caller, _orgId) == true, "account is not a org admin account"); | |
| nodeManager.addOrgNode(_enodeId, _ip, _port, _raftport, _orgId); | |
| } | |
| /** @notice function to update node status. can be invoked by org admin | |
| account only | |
| * @param _orgId unique id of the organization to which the account belongs | |
| * @param _enodeId enode id being dded to the org | |
| * @param _ip IP of node | |
| * @param _port tcp port of node | |
| * @param _raftport raft port of node | |
| * @param _action 1-deactivate, 2-activate back, 3-blacklist the node | |
| */ | |
| function updateNodeStatus(string memory _orgId, string memory _enodeId, string memory _ip, uint16 _port, uint16 _raftport, | |
| uint256 _action, address _caller) public | |
| onlyInterface | |
| { | |
| require(isOrgAdmin(_caller, _orgId) == true, "account is not a org admin account"); | |
| // ensure that the action passed to this call is proper and is not | |
| // called with action 4 and 5 which are actions for blacklisted node | |
| // recovery | |
| require((_action == 1 || _action == 2 || _action == 3), | |
| "invalid action. operation not allowed"); | |
| nodeManager.updateNodeStatus(_enodeId, _ip, _port, _raftport, _orgId, _action); | |
| } | |
| /** @notice function to initiate blacklisted nodes recovery. this can be | |
| invoked by an network admin account only | |
| * @param _orgId unique id of the organization to which the account belongs | |
| * @param _enodeId enode id being dded to the org | |
| * @param _ip IP of node | |
| * @param _port tcp port of node | |
| * @param _raftport raft port of node | |
| * @dev this function creates a voting record for other network admins to | |
| approve the operation. The recovery is complete only after majority voting | |
| */ | |
| function startBlacklistedNodeRecovery(string memory _orgId, string memory _enodeId, string memory _ip, uint16 _port, uint16 _raftport, | |
| address _caller) public | |
| onlyInterface | |
| networkAdmin(_caller) | |
| { | |
| // update the node status as recovery initiated. action for this is 4 | |
| nodeManager.updateNodeStatus(_enodeId, _ip, _port, _raftport, _orgId, 4); | |
| // add a voting record with pending op of 5 which corresponds to blacklisted node | |
| // recovery | |
| voterManager.addVotingItem(adminOrg, _orgId, _enodeId, address(0), 5); | |
| } | |
| /** @notice function to initiate blacklisted nodes recovery. this can be | |
| invoked by an network admin account only | |
| * @param _orgId unique id of the organization to which the account belongs | |
| * @param _enodeId enode id being dded to the org | |
| * @param _ip IP of node | |
| * @param _port tcp port of node | |
| * @param _raftport raft port of node | |
| * @dev this function creates a voting record for other network admins to | |
| approve the operation. The recovery is complete only after majority voting | |
| */ | |
| function approveBlacklistedNodeRecovery(string memory _orgId, string memory _enodeId, string memory _ip, uint16 _port, uint16 _raftport, | |
| address _caller) public | |
| onlyInterface | |
| networkAdmin(_caller) | |
| { | |
| // check if majority votes are received. pending op type is passed as 5 | |
| // which stands for black listed node recovery | |
| if ((processVote(adminOrg, _caller, 5))) { | |
| // update the node back to active | |
| nodeManager.updateNodeStatus(_enodeId, _ip, _port, _raftport, _orgId, 5); | |
| } | |
| } | |
| /** @notice function to initaite blacklisted nodes recovery. this can be | |
| invoked by an network admin account only | |
| * @param _orgId unique id of the organization to which the account belongs | |
| * @param _account account id being dded to the org | |
| * @dev this function creates a voting record for other network admins to | |
| approve the operation. The recovery is complete only after majority voting | |
| */ | |
| function startBlacklistedAccountRecovery(string calldata _orgId, address _account, | |
| address _caller) external | |
| onlyInterface | |
| networkAdmin(_caller) | |
| { | |
| // update the account status as recovery initiated. action for this is 4 | |
| accountManager.updateAccountStatus(_orgId, _account, 4); | |
| // add a voting record with pending op of 5 which corresponds to blacklisted node | |
| // recovery | |
| voterManager.addVotingItem(adminOrg, _orgId, "", _account, 6); | |
| } | |
| /** @notice function to initaite blacklisted nodes recovery. this can be | |
| invoked by an network admin account only | |
| * @param _orgId unique id of the organization to which the account belongs | |
| * @param _account account id being dded to the org | |
| * @dev this function creates a voting record for other network admins to | |
| approve the operation. The recovery is complete only after majority voting | |
| */ | |
| function approveBlacklistedAccountRecovery(string calldata _orgId, address _account, | |
| address _caller) external | |
| onlyInterface | |
| networkAdmin(_caller) { | |
| // check if majority votes are received. pending op type is passed as 6 | |
| // which stands for black listed account recovery | |
| if ((processVote(adminOrg, _caller, 6))) { | |
| // update the node back to active | |
| accountManager.updateAccountStatus(_orgId, _account, 5); | |
| } | |
| } | |
| /** @notice function to fetch network boot status | |
| * @return bool network boot status | |
| */ | |
| function getNetworkBootStatus() external view | |
| returns (bool){ | |
| return networkBoot; | |
| } | |
| /** @notice function to fetch detail of any pending approval activities | |
| for network admin organization | |
| * @param _orgId unique id of the organization to which the account belongs | |
| */ | |
| function getPendingOp(string calldata _orgId) external view | |
| returns (string memory, string memory, address, uint256){ | |
| return voterManager.getPendingOpDetails(_orgId); | |
| } | |
| /** @notice function to assigns a role id to the account given account | |
| can be executed by org admin account only | |
| * @param _account account id | |
| * @param _orgId organization id to which the account belongs | |
| * @param _roleId role id to be assigned to the account | |
| */ | |
| function assignAccountRole(address _account, string memory _orgId, | |
| string memory _roleId, address _caller) public | |
| onlyInterface | |
| orgAdmin(_caller, _orgId) | |
| orgApproved(_orgId) { | |
| require(validateAccount(_account, _orgId) == true, "operation cannot be performed"); | |
| require(_roleExists(_roleId, _orgId) == true, "role does not exists"); | |
| bool admin = roleManager.isAdminRole(_roleId, _orgId, _getUltimateParent(_orgId)); | |
| accountManager.assignAccountRole(_account, _orgId, _roleId, admin); | |
| } | |
| /** @notice function to check if passed account is an network admin account | |
| * @param _account account id | |
| * @return true/false | |
| */ | |
| function isNetworkAdmin(address _account) public view | |
| returns (bool){ | |
| return (keccak256(abi.encode(accountManager.getAccountRole(_account))) == keccak256(abi.encode(adminRole))); | |
| } | |
| /** @notice function to check if passed account is an org admin account | |
| * @param _account account id | |
| * @param _orgId organization id | |
| * @return true/false | |
| */ | |
| function isOrgAdmin(address _account, string memory _orgId) public view | |
| returns (bool){ | |
| if (accountManager.checkOrgAdmin(_account, _orgId, _getUltimateParent(_orgId))) { | |
| return true; | |
| } | |
| return roleManager.isAdminRole(accountManager.getAccountRole(_account), _orgId, | |
| _getUltimateParent(_orgId)); | |
| } | |
| /** @notice function to validate the account for access change operation | |
| * @param _account account id | |
| * @param _orgId organization id | |
| * @return true/false | |
| */ | |
| function validateAccount(address _account, string memory _orgId) public view | |
| returns (bool){ | |
| return (accountManager.validateAccount(_account, _orgId)); | |
| } | |
| /** @notice function to update the voter list at network level. this will | |
| be called whenever an account is assigned a network admin role | |
| or an account having network admin role is being assigned | |
| different role | |
| * @param _orgId org id to which the account belongs | |
| * @param _account account which needs to be added/removed as voter | |
| * @param _add bool indicating if its an add or delete operation | |
| */ | |
| function updateVoterList(string memory _orgId, address _account, bool _add) internal { | |
| if (_add) { | |
| voterManager.addVoter(_orgId, _account); | |
| } | |
| else { | |
| voterManager.deleteVoter(_orgId, _account); | |
| } | |
| } | |
| /** @notice whenever a network admin account votes on a pending item, this | |
| function processes the vote. | |
| * @param _orgId org id of the caller | |
| * @param _caller account which approving the operation | |
| * @param _pendingOp operation for which the approval is being done | |
| * @dev the list of pending ops are managed in voter manager contract | |
| */ | |
| function processVote(string memory _orgId, address _caller, uint256 _pendingOp) internal | |
| returns (bool){ | |
| return voterManager.processVote(_orgId, _caller, _pendingOp); | |
| } | |
| /** @notice returns various permissions policy related parameters | |
| * @return adminOrg admin org id | |
| * @return adminRole default network admin role | |
| * @return orgAdminRole default org admin role | |
| * @return networkBoot network boot status | |
| */ | |
| function getPolicyDetails() external view | |
| returns (string memory, string memory, string memory, bool){ | |
| return (adminOrg, adminRole, orgAdminRole, networkBoot); | |
| } | |
| /** @notice checks if the passed org exists or not | |
| * @param _orgId org id | |
| * @return true/false | |
| */ | |
| function _checkOrgExists(string memory _orgId) internal view | |
| returns (bool){ | |
| return orgManager.checkOrgExists(_orgId); | |
| } | |
| /** @notice checks if the passed org is in approved status | |
| * @param _orgId org id | |
| * @return true/false | |
| */ | |
| function checkOrgApproved(string memory _orgId) internal view | |
| returns (bool){ | |
| return orgManager.checkOrgStatus(_orgId, 2); | |
| } | |
| /** @notice checks if the passed org is in the status passed | |
| * @param _orgId org id | |
| * @param _status status to be checked for | |
| * @return true/false | |
| */ | |
| function _checkOrgStatus(string memory _orgId, uint256 _status) internal view | |
| returns (bool){ | |
| return orgManager.checkOrgStatus(_orgId, _status); | |
| } | |
| /** @notice checks if org admin account exists for the passed org id | |
| * @param _orgId org id | |
| * @return true/false | |
| */ | |
| function _checkOrgAdminExists(string memory _orgId) internal view | |
| returns (bool){ | |
| return accountManager.orgAdminExists(_orgId); | |
| } | |
| /** @notice checks if role id exists for the passed org_id | |
| * @param _roleId role id | |
| * @param _orgId org id | |
| * @return true/false | |
| */ | |
| function _roleExists(string memory _roleId, string memory _orgId) internal view | |
| returns (bool){ | |
| return roleManager.roleExists(_roleId, _orgId, _getUltimateParent(_orgId)); | |
| } | |
| /** @notice checks if the role id for the org is a voter role | |
| * @param _roleId role id | |
| * @param _orgId org id | |
| * @return true/false | |
| */ | |
| function _isVoterRole(string memory _roleId, string memory _orgId) internal view | |
| returns (bool){ | |
| return roleManager.isVoterRole(_roleId, _orgId, _getUltimateParent(_orgId)); | |
| } | |
| /** @notice returns the ultimate parent for a given org id | |
| * @param _orgId org id | |
| * @return ultimate parent org id | |
| */ | |
| function _getUltimateParent(string memory _orgId) internal view | |
| returns (string memory){ | |
| return orgManager.getUltimateParent(_orgId); | |
| } | |
| /** @notice checks if the node is allowed to connect or not | |
| * @param _enodeId enode id | |
| * @param _ip IP of node | |
| * @param _port tcp port of node | |
| * @return bool indicating if the node is allowed to connect or not | |
| */ | |
| function connectionAllowed(string calldata _enodeId, string calldata _ip, uint16 _port) external view returns (bool) { | |
| if (!networkBoot){ | |
| return true; | |
| } | |
| return nodeManager.connectionAllowed(_enodeId, _ip, _port); | |
| } | |
| /** @notice checks if the account is allowed to transact or not | |
| * @param _sender source account | |
| * @param _target target account | |
| * @param _value value being transferred | |
| * @param _gasPrice gas price | |
| * @param _gasLimit gas limit | |
| * @param _payload payload for transactions on contracts | |
| * @return bool indicating if the account is allowed to transact or not | |
| */ | |
| function transactionAllowed(address _sender, address _target, uint256 _value, uint256 _gasPrice, uint256 _gasLimit, bytes calldata _payload) | |
| external view returns (bool) { | |
| if (!networkBoot){ | |
| return true; | |
| } | |
| if (accountManager.getAccountStatus(_sender) == 2) { | |
| (string memory act_org, string memory act_role) = accountManager.getAccountOrgRole(_sender); | |
| string memory act_uOrg = _getUltimateParent(act_org); | |
| if (orgManager.checkOrgActive(act_org)) { | |
| if (isNetworkAdmin(_sender) || isOrgAdmin(_sender, act_org)) { | |
| return true; | |
| } | |
| uint256 typeOfxn = 1; | |
| if (_target == address(0)) { | |
| typeOfxn = 2; | |
| } | |
| else if (_payload.length > 0) { | |
| typeOfxn = 3; | |
| } | |
| return roleManager.transactionAllowed(act_role, act_org, act_uOrg, typeOfxn); | |
| } | |
| } | |
| return false; | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| pragma solidity ^0.5.3; | |
| import "./PermissionsImplementation.sol"; | |
| import "./PermissionsUpgradable.sol"; | |
| /** @title Permissions Interface Contract | |
| * @notice This contract is the interface for permissions implementation | |
| contract. for any call, it forwards the call to the implementation | |
| contract | |
| */ | |
| contract PermissionsInterface { | |
| PermissionsImplementation private permImplementation; | |
| PermissionsUpgradable private permUpgradable; | |
| address private permImplUpgradeable; | |
| /** @notice constructor | |
| * @param _permImplUpgradeable permissions upgradable contract address | |
| */ | |
| constructor(address _permImplUpgradeable) public { | |
| permImplUpgradeable = _permImplUpgradeable; | |
| } | |
| /** @notice confirms that the caller is the address of upgradable | |
| contract | |
| */ | |
| modifier onlyUpgradeable { | |
| require(msg.sender == permImplUpgradeable, "invalid caller"); | |
| _; | |
| } | |
| /** @notice interface for setting the permissions policy in implementation | |
| * @param _nwAdminOrg network admin organization id | |
| * @param _nwAdminRole default network admin role id | |
| * @param _oAdminRole default organization admin role id | |
| */ | |
| function setPolicy(string calldata _nwAdminOrg, string calldata _nwAdminRole, | |
| string calldata _oAdminRole) external { | |
| permImplementation.setPolicy(_nwAdminOrg, _nwAdminRole, _oAdminRole); | |
| } | |
| /** @notice interface to initializes the breadth and depth values for | |
| sub organization management | |
| * @param _breadth controls the number of sub org a parent org can have | |
| * @param _depth controls the depth of nesting allowed for sub orgs | |
| */ | |
| function init(uint256 _breadth, uint256 _depth) external { | |
| permImplementation.init(_breadth, _depth); | |
| } | |
| /** @notice interface to add new node to an admin organization | |
| * @param _enodeId enode id of the node to be added | |
| * @param _ip IP of node | |
| * @param _port tcp port of node | |
| * @param _raftport raft port of node | |
| */ | |
| function addAdminNode(string memory _enodeId, string memory _ip, uint16 _port, uint16 _raftport) public { | |
| permImplementation.addAdminNode(_enodeId, _ip, _port, _raftport); | |
| } | |
| /** @notice interface to add accounts to an admin organization | |
| * @param _acct account address to be added | |
| */ | |
| function addAdminAccount(address _acct) external { | |
| permImplementation.addAdminAccount(_acct); | |
| } | |
| /** @notice interface to update network boot up status | |
| * @return bool true or false | |
| */ | |
| function updateNetworkBootStatus() external | |
| returns (bool) | |
| { | |
| return permImplementation.updateNetworkBootStatus(); | |
| } | |
| /** @notice interface to fetch network boot status | |
| * @return bool network boot status | |
| */ | |
| function getNetworkBootStatus() external view returns (bool){ | |
| return permImplementation.getNetworkBootStatus(); | |
| } | |
| /** @notice interface to add a new organization to the network | |
| * @param _orgId unique organization id | |
| * @param _enodeId enode id linked to the organization | |
| * @param _ip IP of node | |
| * @param _port tcp port of node | |
| * @param _raftport raft port of node | |
| * @param _account account id. this will have the org admin privileges | |
| */ | |
| function addOrg(string memory _orgId, string memory _enodeId, string memory _ip, uint16 _port, uint16 _raftport, | |
| address _account) public { | |
| permImplementation.addOrg(_orgId, _enodeId, _ip, _port, _raftport, _account, msg.sender); | |
| } | |
| /** @notice interface to approve a newly added organization | |
| * @param _orgId unique organization id | |
| * @param _enodeId enode id linked to the organization | |
| * @param _ip IP of node | |
| * @param _port tcp port of node | |
| * @param _raftport raft port of node | |
| * @param _account account id this will have the org admin privileges | |
| */ | |
| function approveOrg(string memory _orgId, string memory _enodeId, string memory _ip, uint16 _port, uint16 _raftport, | |
| address _account) public { | |
| permImplementation.approveOrg(_orgId, _enodeId, _ip, _port, _raftport, _account, msg.sender); | |
| } | |
| /** @notice interface to add sub org under an org | |
| * @param _pOrgId parent org id under which the sub org is being added | |
| * @param _orgId unique id for the sub organization | |
| * @param _enodeId enode id linked to the sjb organization | |
| * @param _ip IP of node | |
| * @param _port tcp port of node | |
| * @param _raftport raft port of node | |
| */ | |
| function addSubOrg(string memory _pOrgId, string memory _orgId, | |
| string memory _enodeId, string memory _ip, uint16 _port, uint16 _raftport) public { | |
| permImplementation.addSubOrg(_pOrgId, _orgId, _enodeId, _ip, _port, _raftport, msg.sender); | |
| } | |
| /** @notice interface to update the org status | |
| * @param _orgId unique id of the organization | |
| * @param _action 1 for suspending an org and 2 for revoke of suspension | |
| */ | |
| function updateOrgStatus(string calldata _orgId, uint256 _action) external { | |
| permImplementation.updateOrgStatus(_orgId, _action, msg.sender); | |
| } | |
| /** @notice interface to approve org status change | |
| * @param _orgId unique id for the sub organization | |
| * @param _action 1 for suspending an org and 2 for revoke of suspension | |
| */ | |
| function approveOrgStatus(string calldata _orgId, uint256 _action) external { | |
| permImplementation.approveOrgStatus(_orgId, _action, msg.sender); | |
| } | |
| /** @notice interface to add a new role definition to an organization | |
| * @param _roleId unique id for the role | |
| * @param _orgId unique id of the organization to which the role belongs | |
| * @param _access account access type for the role | |
| * @param _voter bool indicates if the role is voter role or not | |
| * @param _admin bool indicates if the role is an admin role | |
| * @dev account access type can have of the following four values: | |
| 0 - Read only | |
| 1 - Transact access | |
| 2 - Contract deployment access. Can transact as well | |
| 3 - Full access | |
| */ | |
| function addNewRole(string calldata _roleId, string calldata _orgId, | |
| uint256 _access, bool _voter, bool _admin) external { | |
| permImplementation.addNewRole(_roleId, _orgId, _access, _voter, _admin, msg.sender); | |
| } | |
| /** @notice interface to remove a role definition from an organization | |
| * @param _roleId unique id for the role | |
| * @param _orgId unique id of the organization to which the role belongs | |
| */ | |
| function removeRole(string calldata _roleId, string calldata _orgId) external { | |
| permImplementation.removeRole(_roleId, _orgId, msg.sender); | |
| } | |
| /** @notice interface to assign network admin/org admin role to an account | |
| this can be executed by network admin accounts only | |
| * @param _orgId unique id of the organization to which the account belongs | |
| * @param _account account id | |
| * @param _roleId role id to be assigned to the account | |
| */ | |
| function assignAdminRole(string calldata _orgId, address _account, | |
| string calldata _roleId) external { | |
| permImplementation.assignAdminRole(_orgId, _account, _roleId, msg.sender); | |
| } | |
| /** @notice interface to approve network admin/org admin role assigment | |
| this can be executed by network admin accounts only | |
| * @param _orgId unique id of the organization to which the account belongs | |
| * @param _account account id | |
| */ | |
| function approveAdminRole(string calldata _orgId, address _account) external { | |
| permImplementation.approveAdminRole(_orgId, _account, msg.sender); | |
| } | |
| /** @notice interface to update account status | |
| this can be executed by org admin accounts only | |
| * @param _orgId unique id of the organization to which the account belongs | |
| * @param _account account id | |
| * @param _action 1-suspending 2-activating back 3-blacklisting | |
| */ | |
| function updateAccountStatus(string calldata _orgId, address _account, | |
| uint256 _action) external { | |
| permImplementation.updateAccountStatus(_orgId, _account, _action, msg.sender); | |
| } | |
| /** @notice interface to add a new node to the organization | |
| * @param _orgId unique id of the organization to which the account belongs | |
| * @param _enodeId enode id being dded to the org | |
| * @param _ip IP of node | |
| * @param _port tcp port of node | |
| * @param _raftport raft port of node | |
| */ | |
| function addNode(string memory _orgId, string memory _enodeId, string memory _ip, uint16 _port, uint16 _raftport) public { | |
| permImplementation.addNode(_orgId, _enodeId, _ip, _port, _raftport, msg.sender); | |
| } | |
| /** @notice interface to update node status | |
| * @param _orgId unique id of the organization to which the account belongs | |
| * @param _enodeId enode id being dded to the org | |
| * @param _ip IP of node | |
| * @param _port tcp port of node | |
| * @param _raftport raft port of node | |
| * @param _action 1-deactivate, 2-activate back, 3-blacklist the node | |
| */ | |
| function updateNodeStatus(string memory _orgId, string memory _enodeId, string memory _ip, uint16 _port, uint16 _raftport, | |
| uint256 _action) public { | |
| permImplementation.updateNodeStatus(_orgId, _enodeId, _ip, _port, _raftport, _action, msg.sender); | |
| } | |
| /** @notice interface to initiate blacklisted node recovery | |
| * @param _orgId unique id of the organization to which the account belongs | |
| * @param _enodeId enode id being recovered | |
| * @param _ip IP of node | |
| * @param _port tcp port of node | |
| * @param _raftport raft port of node | |
| */ | |
| function startBlacklistedNodeRecovery(string memory _orgId, string memory _enodeId, string memory _ip, uint16 _port, uint16 _raftport) | |
| public { | |
| permImplementation.startBlacklistedNodeRecovery(_orgId, _enodeId, _ip, _port, _raftport, msg.sender); | |
| } | |
| /** @notice interface to approve blacklisted node recoevry | |
| * @param _orgId unique id of the organization to which the account belongs | |
| * @param _enodeId enode id being recovered | |
| * @param _ip IP of node | |
| * @param _port tcp port of node | |
| * @param _raftport raft port of node | |
| */ | |
| function approveBlacklistedNodeRecovery(string memory _orgId, string memory _enodeId, string memory _ip, uint16 _port, uint16 _raftport) | |
| public { | |
| permImplementation.approveBlacklistedNodeRecovery(_orgId, _enodeId, _ip, _port, _raftport, msg.sender); | |
| } | |
| /** @notice interface to initiate blacklisted account recovery | |
| * @param _orgId unique id of the organization to which the account belongs | |
| * @param _account account id being recovered | |
| */ | |
| function startBlacklistedAccountRecovery(string calldata _orgId, address _account) | |
| external { | |
| permImplementation.startBlacklistedAccountRecovery(_orgId, _account, msg.sender); | |
| } | |
| /** @notice interface to approve blacklisted node recovery | |
| * @param _orgId unique id of the organization to which the account belongs | |
| * @param _account account id being recovered | |
| */ | |
| function approveBlacklistedAccountRecovery(string calldata _orgId, address _account) | |
| external { | |
| permImplementation.approveBlacklistedAccountRecovery(_orgId, _account, msg.sender); | |
| } | |
| /** @notice interface to fetch detail of any pending approval activities | |
| for network admin organization | |
| * @param _orgId unique id of the organization to which the account belongs | |
| */ | |
| function getPendingOp(string calldata _orgId) external view | |
| returns (string memory, string memory, address, uint256) { | |
| return permImplementation.getPendingOp(_orgId); | |
| } | |
| /** @notice sets the permissions implementation contract address | |
| can be called from upgradable contract only | |
| * @param _permImplementation permissions implementation contract address | |
| */ | |
| function setPermImplementation(address _permImplementation) external | |
| onlyUpgradeable { | |
| permImplementation = PermissionsImplementation(_permImplementation); | |
| } | |
| /** @notice returns the address of permissions implementation contract | |
| * @return permissions implementation contract address | |
| */ | |
| function getPermissionsImpl() external view returns (address) { | |
| return address(permImplementation); | |
| } | |
| /** @notice interface to assigns a role id to the account give | |
| * @param _account account id | |
| * @param _orgId organization id to which the account belongs | |
| * @param _roleId role id to be assigned to the account | |
| */ | |
| function assignAccountRole(address _account, string calldata _orgId, | |
| string calldata _roleId) external { | |
| permImplementation.assignAccountRole(_account, _orgId, _roleId, msg.sender); | |
| } | |
| /** @notice interface to check if passed account is an network admin account | |
| * @param _account account id | |
| * @return true/false | |
| */ | |
| function isNetworkAdmin(address _account) external view returns (bool) { | |
| return permImplementation.isNetworkAdmin(_account); | |
| } | |
| /** @notice interface to check if passed account is an org admin account | |
| * @param _account account id | |
| * @param _orgId organization id | |
| * @return true/false | |
| */ | |
| function isOrgAdmin(address _account, string calldata _orgId) | |
| external view returns (bool) { | |
| return permImplementation.isOrgAdmin(_account, _orgId); | |
| } | |
| /** @notice interface to validate the account for access change operation | |
| * @param _account account id | |
| * @param _orgId organization id | |
| * @return true/false | |
| */ | |
| function validateAccount(address _account, string calldata _orgId) | |
| external view returns (bool) { | |
| return permImplementation.validateAccount(_account, _orgId); | |
| } | |
| /** @notice checks if the node is allowed to connect or not | |
| * @param _enodeId enode id | |
| * @param _ip IP of node | |
| * @param _port tcp port of node | |
| * @return bool indicating if the node is allowed to connect or not | |
| */ | |
| function connectionAllowed(string calldata _enodeId, string calldata _ip, uint16 _port) external view returns (bool) { | |
| return permImplementation.connectionAllowed(_enodeId, _ip, _port); | |
| } | |
| /** @notice checks if the account is allowed to transact or not | |
| * @param _sender source account | |
| * @param _target target account | |
| * @param _value value being transferred | |
| * @param _gasPrice gas price | |
| * @param _gasLimit gas limit | |
| * @param _payload payload for transactions on contracts | |
| * @return bool indicating if the account is allowed to transact or not | |
| */ | |
| function transactionAllowed(address _sender, address _target, uint256 _value, uint256 _gasPrice, uint256 _gasLimit, bytes calldata _payload) | |
| external view returns (bool) { | |
| return permImplementation.transactionAllowed(_sender, _target, _value, _gasPrice, _gasLimit, _payload); | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| pragma solidity ^0.5.3; | |
| import "./PermissionsInterface.sol"; | |
| /** @title Permissions Upgradable Contract | |
| * @notice This contract holds the address of current permissions implementation | |
| contract. The contract is owned by a guardian account. Only the | |
| guardian account can change the implementation contract address as | |
| business needs. | |
| */ | |
| contract PermissionsUpgradable { | |
| address private guardian; | |
| address private permImpl; | |
| address private permInterface; | |
| // initDone ensures that init can be called only once | |
| bool private initDone; | |
| /** @notice constructor | |
| * @param _guardian account address | |
| */ | |
| constructor (address _guardian) public{ | |
| guardian = _guardian; | |
| initDone = false; | |
| } | |
| /** @notice confirms that the caller is the guardian account | |
| */ | |
| modifier onlyGuardian { | |
| require(msg.sender == guardian, "invalid caller"); | |
| _; | |
| } | |
| /** @notice executed by guardian. Links interface and implementation contract | |
| addresses. Can be executed by guardian account only | |
| * @param _permInterface permissions interface contract address | |
| * @param _permImpl implementation contract address | |
| */ | |
| function init(address _permInterface, address _permImpl) external | |
| onlyGuardian { | |
| require(!initDone, "can be executed only once"); | |
| permImpl = _permImpl; | |
| permInterface = _permInterface; | |
| _setImpl(permImpl); | |
| initDone = true; | |
| } | |
| /** @notice changes the implementation contract address to the new address | |
| address passed. Can be executed by guardian account only | |
| * @param _proposedImpl address of the new permissions implementation contract | |
| */ | |
| function confirmImplChange(address _proposedImpl) public | |
| onlyGuardian { | |
| // The policy details needs to be carried forward from existing | |
| // implementation to new. So first these are read from existing | |
| // implementation and then updated in new implementation | |
| (string memory adminOrg, string memory adminRole, string memory orgAdminRole, bool bootStatus) = PermissionsImplementation(permImpl).getPolicyDetails(); | |
| _setPolicy(_proposedImpl, adminOrg, adminRole, orgAdminRole, bootStatus); | |
| permImpl = _proposedImpl; | |
| _setImpl(permImpl); | |
| } | |
| /** @notice function to fetch the guardian account address | |
| * @return _guardian guardian account address | |
| */ | |
| function getGuardian() public view returns (address) { | |
| return guardian; | |
| } | |
| /** @notice function to fetch the current implementation address | |
| * @return permissions implementation contract address | |
| */ | |
| function getPermImpl() public view returns (address) { | |
| return permImpl; | |
| } | |
| /** @notice function to fetch the interface address | |
| * @return permissions interface contract address | |
| */ | |
| function getPermInterface() public view returns (address) { | |
| return permInterface; | |
| } | |
| /** @notice function to set the permissions policy details in the | |
| permissions implementation contract | |
| * @param _permImpl permissions implementation contract address | |
| * @param _adminOrg name of admin organization | |
| * @param _adminRole name of the admin role | |
| * @param _orgAdminRole name of default organization admin role | |
| * @param _bootStatus network boot status | |
| */ | |
| function _setPolicy(address _permImpl, string memory _adminOrg, string memory _adminRole, string memory _orgAdminRole, bool _bootStatus) private { | |
| PermissionsImplementation(_permImpl).setMigrationPolicy(_adminOrg, _adminRole, _orgAdminRole, _bootStatus); | |
| } | |
| /** @notice function to set the permissions implementation contract address | |
| in the permissions interface contract | |
| * @param _permImpl permissions implementation contract address | |
| */ | |
| function _setImpl(address _permImpl) private { | |
| PermissionsInterface(permInterface).setPermImplementation(_permImpl); | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| pragma solidity ^0.5.3; | |
| import "./PermissionsUpgradable.sol"; | |
| /** @title Role manager contract | |
| * @notice This contract holds implementation logic for all role management | |
| functionality. This can be called only by the implementation | |
| contract only. there are few view functions exposed as public and | |
| can be called directly. these are invoked by quorum for populating | |
| permissions data in cache | |
| */ | |
| contract RoleManager { | |
| PermissionsUpgradable private permUpgradable; | |
| struct RoleDetails { | |
| string roleId; | |
| string orgId; | |
| uint256 baseAccess; | |
| bool isVoter; | |
| bool isAdmin; | |
| bool active; | |
| } | |
| RoleDetails[] private roleList; | |
| mapping(bytes32 => uint256) private roleIndex; | |
| uint256 private numberOfRoles; | |
| event RoleCreated(string _roleId, string _orgId, uint256 _baseAccess, | |
| bool _isVoter, bool _isAdmin); | |
| event RoleRevoked(string _roleId, string _orgId); | |
| /** @notice confirms that the caller is the address of implementation | |
| contract | |
| */ | |
| modifier onlyImplementation { | |
| require(msg.sender == permUpgradable.getPermImpl(), "invalid caller"); | |
| _; | |
| } | |
| /** @notice constructor. sets the permissions upgradable address | |
| */ | |
| constructor (address _permUpgradable) public { | |
| permUpgradable = PermissionsUpgradable(_permUpgradable); | |
| } | |
| /** @notice function to add a new role definition to an organization | |
| * @param _roleId - unique identifier for the role being added | |
| * @param _orgId - org id to which the role belongs | |
| * @param _baseAccess - can be from 0 to 7 | |
| * @param _isVoter - bool to indicate if voter role or not | |
| * @param _isAdmin - bool to indicate if admin role or not | |
| * @dev base access can have any of the following values: | |
| 0 - Read only | |
| 1 - value transfer | |
| 2 - contract deploy | |
| 3 - full access | |
| 4 - contract call | |
| 5 - value transfer and contract call | |
| 6 - value transfer and contract deploy | |
| 7 - contract call and deploy | |
| */ | |
| function addRole(string memory _roleId, string memory _orgId, uint256 _baseAccess, | |
| bool _isVoter, bool _isAdmin) public onlyImplementation { | |
| require(_baseAccess < 8, "invalid access value"); | |
| // Check if account already exists | |
| require(roleIndex[keccak256(abi.encode(_roleId, _orgId))] == 0, "role exists for the org"); | |
| numberOfRoles ++; | |
| roleIndex[keccak256(abi.encode(_roleId, _orgId))] = numberOfRoles; | |
| roleList.push(RoleDetails(_roleId, _orgId, _baseAccess, _isVoter, _isAdmin, true)); | |
| emit RoleCreated(_roleId, _orgId, _baseAccess, _isVoter, _isAdmin); | |
| } | |
| /** @notice function to remove an existing role definition from an organization | |
| * @param _roleId - unique identifier for the role being added | |
| * @param _orgId - org id to which the role belongs | |
| */ | |
| function removeRole(string calldata _roleId, string calldata _orgId) external | |
| onlyImplementation { | |
| require(roleIndex[keccak256(abi.encode(_roleId, _orgId))] != 0, "role does not exist"); | |
| uint256 rIndex = _getRoleIndex(_roleId, _orgId); | |
| roleList[rIndex].active = false; | |
| emit RoleRevoked(_roleId, _orgId); | |
| } | |
| /** @notice checks if the role is a voter role or not | |
| * @param _roleId - unique identifier for the role being added | |
| * @param _orgId - org id to which the role belongs | |
| * @param _ultParent - master org id | |
| * @return true or false | |
| * @dev checks for the role existence in the passed org and master org | |
| */ | |
| function isVoterRole(string calldata _roleId, string calldata _orgId, | |
| string calldata _ultParent) external view onlyImplementation returns (bool){ | |
| if (!(roleExists(_roleId, _orgId, _ultParent))) { | |
| return false; | |
| } | |
| uint256 rIndex; | |
| if (roleIndex[keccak256(abi.encode(_roleId, _orgId))] != 0) { | |
| rIndex = _getRoleIndex(_roleId, _orgId); | |
| } | |
| else { | |
| rIndex = _getRoleIndex(_roleId, _ultParent); | |
| } | |
| return (roleList[rIndex].active && roleList[rIndex].isVoter); | |
| } | |
| /** @notice checks if the role is an admin role or not | |
| * @param _roleId - unique identifier for the role being added | |
| * @param _orgId - org id to which the role belongs | |
| * @param _ultParent - master org id | |
| * @return true or false | |
| * @dev checks for the role existence in the passed org and master org | |
| */ | |
| function isAdminRole(string calldata _roleId, string calldata _orgId, | |
| string calldata _ultParent) external view onlyImplementation returns (bool){ | |
| if (!(roleExists(_roleId, _orgId, _ultParent))) { | |
| return false; | |
| } | |
| uint256 rIndex; | |
| if (roleIndex[keccak256(abi.encode(_roleId, _orgId))] != 0) { | |
| rIndex = _getRoleIndex(_roleId, _orgId); | |
| } | |
| else { | |
| rIndex = _getRoleIndex(_roleId, _ultParent); | |
| } | |
| return (roleList[rIndex].active && roleList[rIndex].isAdmin); | |
| } | |
| /** @notice returns the role details for a passed role id and org | |
| * @param _roleId - unique identifier for the role being added | |
| * @param _orgId - org id to which the role belongs | |
| * @return role id | |
| * @return org id | |
| * @return access type | |
| * @return bool to indicate if the role is a voter role | |
| * @return bool to indicate if the role is active | |
| */ | |
| function getRoleDetails(string calldata _roleId, string calldata _orgId) | |
| external view returns (string memory roleId, string memory orgId, | |
| uint256 accessType, bool voter, bool admin, bool active) { | |
| if (!(roleExists(_roleId, _orgId, ""))) { | |
| return (_roleId, "", 0, false, false, false); | |
| } | |
| uint256 rIndex = _getRoleIndex(_roleId, _orgId); | |
| return (roleList[rIndex].roleId, roleList[rIndex].orgId, | |
| roleList[rIndex].baseAccess, roleList[rIndex].isVoter, | |
| roleList[rIndex].isAdmin, roleList[rIndex].active); | |
| } | |
| /** @notice returns the role details for a passed role index | |
| * @param _rIndex - unique identifier for the role being added | |
| * @return role id | |
| * @return org id | |
| * @return access type | |
| * @return bool to indicate if the role is a voter role | |
| * @return bool to indicate if the role is active | |
| */ | |
| function getRoleDetailsFromIndex(uint256 _rIndex) external view returns | |
| (string memory roleId, string memory orgId, uint256 accessType, | |
| bool voter, bool admin, bool active) { | |
| return (roleList[_rIndex].roleId, roleList[_rIndex].orgId, | |
| roleList[_rIndex].baseAccess, roleList[_rIndex].isVoter, | |
| roleList[_rIndex].isAdmin, roleList[_rIndex].active); | |
| } | |
| /** @notice returns the total number of roles in the network | |
| * @return total number of roles | |
| */ | |
| function getNumberOfRoles() external view returns (uint256) { | |
| return roleList.length; | |
| } | |
| /** @notice checks if the role exists for the given org or master org | |
| * @param _roleId - unique identifier for the role being added | |
| * @param _orgId - org id to which the role belongs | |
| * @param _ultParent - master org id | |
| * @return true or false | |
| */ | |
| function roleExists(string memory _roleId, string memory _orgId, | |
| string memory _ultParent) public view returns (bool) { | |
| uint256 id; | |
| if (roleIndex[keccak256(abi.encode(_roleId, _orgId))] != 0) { | |
| id = _getRoleIndex(_roleId, _orgId); | |
| return roleList[id].active; | |
| } | |
| else if (roleIndex[keccak256(abi.encode(_roleId, _ultParent))] != 0) { | |
| id = _getRoleIndex(_roleId, _ultParent); | |
| return roleList[id].active; | |
| } | |
| return false; | |
| } | |
| function roleAccess(string memory _roleId, string memory _orgId, | |
| string memory _ultParent) public view returns (uint256) { | |
| uint256 id; | |
| if (roleIndex[keccak256(abi.encode(_roleId, _orgId))] != 0) { | |
| id = _getRoleIndex(_roleId, _orgId); | |
| return roleList[id].baseAccess; | |
| } | |
| else if (roleIndex[keccak256(abi.encode(_roleId, _ultParent))] != 0) { | |
| id = _getRoleIndex(_roleId, _ultParent); | |
| return roleList[id].baseAccess; | |
| } | |
| return 0; | |
| } | |
| function transactionAllowed(string calldata _roleId, string calldata _orgId, | |
| string calldata _ultParent, uint256 _typeOfTxn) external view returns (bool) { | |
| uint256 access = roleAccess(_roleId, _orgId, _ultParent); | |
| if (access == 3) { | |
| return true; | |
| } | |
| if (_typeOfTxn == 1 && (access == 1 || access == 5 || access == 6)){ | |
| return true; | |
| } | |
| if (_typeOfTxn == 2 && (access == 2 || access == 6 || access == 7)){ | |
| return true; | |
| } | |
| if (_typeOfTxn == 3 && (access == 4 || access == 5 || access == 7)){ | |
| return true; | |
| } | |
| return false; | |
| } | |
| /** @notice returns the role index based on role id and org id | |
| * @param _roleId - role id | |
| * @param _orgId - org id | |
| * @return role index | |
| */ | |
| function _getRoleIndex(string memory _roleId, string memory _orgId) | |
| internal view returns (uint256) { | |
| return roleIndex[keccak256(abi.encode(_roleId, _orgId))] - 1; | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| pragma solidity ^0.5.3; | |
| import "./PermissionsUpgradable.sol"; | |
| /** @title Voter manager contract | |
| * @notice This contract holds implementation logic for all account voter and | |
| voting functionality. This can be called only by the implementation | |
| contract only. 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 each voting record has an attribute operation type (opType) | |
| which denotes the activity type which is pending approval. This can | |
| have the following values: | |
| 0 - None - indicates no pending records for the org | |
| 1 - New org add activity | |
| 2 - Org suspension activity | |
| 3 - Revoke of org suspension | |
| 4 - Assigning admin role for a new account | |
| 5 - Blacklisted node recovery | |
| 6 - Blacklisted account recovery | |
| */ | |
| contract VoterManager { | |
| PermissionsUpgradable private permUpgradable; | |
| struct PendingOpDetails { | |
| string orgId; | |
| string enodeId; | |
| address account; | |
| uint256 opType; | |
| } | |
| struct Voter { | |
| address vAccount; | |
| bool active; | |
| } | |
| struct OrgVoterDetails { | |
| string orgId; | |
| uint256 voterCount; | |
| uint256 validVoterCount; | |
| uint256 voteCount; | |
| PendingOpDetails pendingOp; | |
| Voter [] voterList; | |
| mapping(address => uint256) voterIndex; | |
| mapping(uint256 => mapping(address => bool)) votingStatus; | |
| } | |
| OrgVoterDetails [] private orgVoterList; | |
| mapping(bytes32 => uint256) private VoterOrgIndex; | |
| uint256 private orgNum = 0; | |
| // events related to managing voting accounts for the org | |
| event VoterAdded(string _orgId, address _vAccount); | |
| event VoterDeleted(string _orgId, address _vAccount); | |
| event VotingItemAdded(string _orgId); | |
| event VoteProcessed(string _orgId); | |
| /** @notice confirms that the caller is the address of implementation | |
| contract | |
| */ | |
| modifier onlyImplementation { | |
| require(msg.sender == permUpgradable.getPermImpl(), "invalid caller"); | |
| _; | |
| } | |
| /** @notice checks if account is a valid voter record and belongs to the org | |
| passed | |
| * @param _orgId - org id | |
| * @param _vAccount - voter account passed | |
| */ | |
| modifier voterExists(string memory _orgId, address _vAccount) { | |
| require(_checkVoterExists(_orgId, _vAccount) == true, "must be a voter"); | |
| _; | |
| } | |
| /** @notice constructor. sets the permissions upgradable address | |
| */ | |
| constructor (address _permUpgradable) public { | |
| permUpgradable = PermissionsUpgradable(_permUpgradable); | |
| } | |
| /** @notice function to add a new voter account to the organization | |
| * @param _orgId org id | |
| * @param _vAccount - voter account | |
| * @dev voter capability is currently enabled for network level activities | |
| only. voting is not available for org related activities | |
| */ | |
| function addVoter(string calldata _orgId, address _vAccount) external | |
| onlyImplementation { | |
| // check if the org exists | |
| if (VoterOrgIndex[keccak256(abi.encode(_orgId))] == 0) { | |
| orgNum++; | |
| VoterOrgIndex[keccak256(abi.encode(_orgId))] = orgNum; | |
| uint256 id = orgVoterList.length++; | |
| orgVoterList[id].orgId = _orgId; | |
| orgVoterList[id].voterCount = 1; | |
| orgVoterList[id].validVoterCount = 1; | |
| orgVoterList[id].voteCount = 0; | |
| orgVoterList[id].pendingOp.orgId = ""; | |
| orgVoterList[id].pendingOp.enodeId = ""; | |
| orgVoterList[id].pendingOp.account = address(0); | |
| orgVoterList[id].pendingOp.opType = 0; | |
| orgVoterList[id].voterIndex[_vAccount] = orgVoterList[id].voterCount; | |
| orgVoterList[id].voterList.push(Voter(_vAccount, true)); | |
| } | |
| else { | |
| uint256 id = _getVoterOrgIndex(_orgId); | |
| // check if the voter is already present in the list | |
| if (orgVoterList[id].voterIndex[_vAccount] == 0) { | |
| orgVoterList[id].voterCount++; | |
| orgVoterList[id].voterIndex[_vAccount] = orgVoterList[id].voterCount; | |
| orgVoterList[id].voterList.push(Voter(_vAccount, true)); | |
| orgVoterList[id].validVoterCount++; | |
| } | |
| else { | |
| uint256 vid = _getVoterIndex(_orgId, _vAccount); | |
| require(orgVoterList[id].voterList[vid].active != true, "already a voter"); | |
| orgVoterList[id].voterList[vid].active = true; | |
| orgVoterList[id].validVoterCount++; | |
| } | |
| } | |
| emit VoterAdded(_orgId, _vAccount); | |
| } | |
| /** @notice function to delete a voter account from the organization | |
| * @param _orgId org id | |
| * @param _vAccount - voter account | |
| * @dev voter capability is currently enabled for network level activities | |
| only. voting is not available for org related activities | |
| */ | |
| function deleteVoter(string calldata _orgId, address _vAccount) external | |
| onlyImplementation | |
| voterExists(_orgId, _vAccount) { | |
| uint256 id = _getVoterOrgIndex(_orgId); | |
| uint256 vId = _getVoterIndex(_orgId, _vAccount); | |
| orgVoterList[id].validVoterCount --; | |
| orgVoterList[id].voterList[vId].active = false; | |
| emit VoterDeleted(_orgId, _vAccount); | |
| } | |
| /** @notice function to a voting item for network admin accounts to vote | |
| * @param _authOrg org id of the authorizing org. it will be network admin org | |
| * @param _orgId - org id for which the voting record is being created | |
| * @param _enodeId - enode id for which the voting record is being created | |
| * @param _account - account id for which the voting record is being created | |
| * @param _pendingOp - operation for which voting is being done | |
| */ | |
| function addVotingItem(string calldata _authOrg, string calldata _orgId, | |
| string calldata _enodeId, address _account, uint256 _pendingOp) | |
| external onlyImplementation { | |
| // check if anything is pending approval for the org. | |
| // If yes another item cannot be added | |
| require((_checkPendingOp(_authOrg, 0)), | |
| "items pending for approval. new item cannot be added"); | |
| uint256 id = _getVoterOrgIndex(_authOrg); | |
| orgVoterList[id].pendingOp.orgId = _orgId; | |
| orgVoterList[id].pendingOp.enodeId = _enodeId; | |
| orgVoterList[id].pendingOp.account = _account; | |
| orgVoterList[id].pendingOp.opType = _pendingOp; | |
| // initialize vote status for voter accounts | |
| for (uint256 i = 0; i < orgVoterList[id].voterList.length; i++) { | |
| if (orgVoterList[id].voterList[i].active) { | |
| orgVoterList[id].votingStatus[id][orgVoterList[id].voterList[i].vAccount] = false; | |
| } | |
| } | |
| // set vote count to zero | |
| orgVoterList[id].voteCount = 0; | |
| emit VotingItemAdded(_authOrg); | |
| } | |
| /** @notice function processing vote of a voter account | |
| * @param _authOrg org id of the authorizing org. it will be network admin org | |
| * @param _vAccount - account id of the voter | |
| * @param _pendingOp - operation which is being approved | |
| * @return success of the voter process. either true or false | |
| */ | |
| function processVote(string calldata _authOrg, address _vAccount, uint256 _pendingOp) | |
| external onlyImplementation voterExists(_authOrg, _vAccount) returns (bool) { | |
| // check something if anything is pending approval | |
| require(_checkPendingOp(_authOrg, _pendingOp) == true, "nothing to approve"); | |
| uint256 id = _getVoterOrgIndex(_authOrg); | |
| // check if vote is already processed | |
| require(orgVoterList[id].votingStatus[id][_vAccount] != true, "cannot double vote"); | |
| orgVoterList[id].voteCount++; | |
| orgVoterList[id].votingStatus[id][_vAccount] = true; | |
| emit VoteProcessed(_authOrg); | |
| if (orgVoterList[id].voteCount > orgVoterList[id].validVoterCount / 2) { | |
| // majority achieved, clean up pending op | |
| orgVoterList[id].pendingOp.orgId = ""; | |
| orgVoterList[id].pendingOp.enodeId = ""; | |
| orgVoterList[id].pendingOp.account = address(0); | |
| orgVoterList[id].pendingOp.opType = 0; | |
| return true; | |
| } | |
| return false; | |
| } | |
| /** @notice returns the details of any pending operation to be approved | |
| * @param _orgId org id. this will be the org id of network admin org | |
| */ | |
| function getPendingOpDetails(string calldata _orgId) external view | |
| onlyImplementation returns (string memory, string memory, address, uint256){ | |
| uint256 orgIndex = _getVoterOrgIndex(_orgId); | |
| return (orgVoterList[orgIndex].pendingOp.orgId, orgVoterList[orgIndex].pendingOp.enodeId, | |
| orgVoterList[orgIndex].pendingOp.account, orgVoterList[orgIndex].pendingOp.opType); | |
| } | |
| /** @notice checks if the voter account exists and is linked to the org | |
| * @param _orgId org id | |
| * @param _vAccount voter account id | |
| * @return true or false | |
| */ | |
| function _checkVoterExists(string memory _orgId, address _vAccount) | |
| internal view returns (bool){ | |
| uint256 orgIndex = _getVoterOrgIndex(_orgId); | |
| if (orgVoterList[orgIndex].voterIndex[_vAccount] == 0) { | |
| return false; | |
| } | |
| uint256 voterIndex = _getVoterIndex(_orgId, _vAccount); | |
| return orgVoterList[orgIndex].voterList[voterIndex].active; | |
| } | |
| /** @notice checks if the pending operation exists or not | |
| * @param _orgId org id | |
| * @param _pendingOp type of operation | |
| * @return true or false | |
| */ | |
| function _checkPendingOp(string memory _orgId, uint256 _pendingOp) | |
| internal view returns (bool){ | |
| return (orgVoterList[_getVoterOrgIndex(_orgId)].pendingOp.opType == _pendingOp); | |
| } | |
| /** @notice returns the voter account index | |
| */ | |
| function _getVoterIndex(string memory _orgId, address _vAccount) | |
| internal view returns (uint256) { | |
| uint256 orgIndex = _getVoterOrgIndex(_orgId); | |
| return orgVoterList[orgIndex].voterIndex[_vAccount] - 1; | |
| } | |
| /** @notice returns the org index for the org from voter list | |
| */ | |
| function _getVoterOrgIndex(string memory _orgId) | |
| internal view returns (uint256) { | |
| return VoterOrgIndex[keccak256(abi.encode(_orgId))] - 1; | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment