Permissions new contracts as per latest spec

This commit is contained in:
vsmk98 2019-03-15 14:41:04 +08:00
parent d650d5522d
commit 50a55a2c09
8 changed files with 1355 additions and 0 deletions

View File

@ -0,0 +1,173 @@
pragma solidity ^0.5.3;
contract AccountManager {
// enum AccountStatus {0-NotInList, 1-PendingApproval, 2-Active, 3-Inactive}
struct AccountAccessDetails {
address acctId;
string orgId;
string role;
uint status;
bool orgAdmin;
}
AccountAccessDetails[] private acctAccessList;
mapping(address => uint) private accountIndex;
uint private numberOfAccts;
string private adminRole;
string private orgAdminRole;
mapping(bytes32 => bool) private orgAdminIndex;
// account permission events
event AccountAccessModified(address _address, string _roleId);
event AccountAccessRevoked(address _address, string _roleId);
// Get account details given index
function orgAdminExists(string memory _orgId) public view returns (bool)
{
return orgAdminIndex[keccak256(abi.encodePacked(_orgId))];
}
function getAccountStatus(address _acct) internal view returns (uint)
{
if (accountIndex[_acct] == 0) {
return 0;
}
uint aIndex = getAcctIndex(_acct);
return (acctAccessList[aIndex].status);
}
function getAccountDetails(address _acct) external view returns (address, string memory, string memory, uint, bool)
{
if (accountIndex[_acct] == 0) {
return (_acct, "NONE", "", 0, false);
}
uint aIndex = getAcctIndex(_acct);
return (acctAccessList[aIndex].acctId, acctAccessList[aIndex].orgId, acctAccessList[aIndex].role, acctAccessList[aIndex].status, acctAccessList[aIndex].orgAdmin);
}
// Get number of accounts
function getNumberOfAccounts() external view returns (uint)
{
return acctAccessList.length;
}
function setDefaults(string calldata _nwAdminRole, string calldata _oAdminRole) external
{
adminRole = _nwAdminRole;
orgAdminRole = _oAdminRole;
}
function setAccountRole(address _address, string memory _orgId, string memory _roleId, uint _status, bool _oAdmin) internal
{
// Check if account already exists
uint aIndex = getAcctIndex(_address);
if (accountIndex[_address] != 0) {
acctAccessList[aIndex].role = _roleId;
acctAccessList[aIndex].status = _status;
acctAccessList[aIndex].orgAdmin = _oAdmin;
}
else {
numberOfAccts ++;
accountIndex[_address] = numberOfAccts;
acctAccessList.push(AccountAccessDetails(_address, _orgId, _roleId, _status, _oAdmin));
}
if (_oAdmin) {
orgAdminIndex[keccak256(abi.encodePacked(_orgId))] = true;
}
emit AccountAccessModified(_address, _roleId);
}
function addNWAdminAccount(address _address, string calldata _orgId) external
{
setAccountRole(_address, _orgId, adminRole, 2, true);
}
function assignAccountRole(address _address, string calldata _orgId, string calldata _roleId) external
{
bool oAdminRole = false;
uint status = 2;
// if the role id is ORGADMIN then check if already an orgadmin exists
if ((keccak256(abi.encodePacked(_roleId)) == keccak256(abi.encodePacked(orgAdminRole))) ||
(keccak256(abi.encodePacked(_roleId)) == keccak256(abi.encodePacked(adminRole)))) {
if (orgAdminIndex[keccak256(abi.encodePacked(_orgId))]) {
return;
}
else {
oAdminRole = true;
status = 1;
}
}
setAccountRole(_address, _orgId, _roleId, status, oAdminRole);
}
function approveOrgAdminAccount(address _address) external
{
// check of the account role is ORGADMIN and status is pending approval
// if yes update the status to approved
string memory role = getAccountRole(_address);
uint status = getAccountStatus(_address);
if ((keccak256(abi.encodePacked(role)) == keccak256(abi.encodePacked(orgAdminRole))) &&
(status == 1)) {
uint aIndex = getAcctIndex(_address);
acctAccessList[aIndex].status = 2;
emit AccountAccessModified(_address, acctAccessList[aIndex].role);
}
}
function revokeAccountRole(address _address) external
{
// Check if account already exists
uint aIndex = getAcctIndex(_address);
if (accountIndex[_address] != 0) {
acctAccessList[aIndex].status = 3;
emit AccountAccessRevoked(_address, acctAccessList[aIndex].role);
}
}
function getAccountRole(address _acct) public view returns (string memory)
{
if (accountIndex[_acct] == 0) {
return "NONE";
}
uint acctIndex = getAcctIndex(_acct);
if (acctAccessList[acctIndex].status != 0) {
return acctAccessList[acctIndex].role;
}
else {
return "NONE";
}
}
function checkOrgAdmin(address _acct, string calldata _orgId) external view returns (bool)
{
if (accountIndex[_acct] == 0) {
return false;
}
uint acctIndex = getAcctIndex(_acct);
return ((acctAccessList[acctIndex].orgAdmin) &&
(keccak256(abi.encodePacked(acctAccessList[acctIndex].orgId)) == keccak256(abi.encodePacked(_orgId))));
}
// this function checks if account access can be modified. Account access can be modified for a new account
// or if the call is from the orgadmin of the same org.
function valAcctAccessChange(address _acct, string calldata _orgId) external view returns (bool)
{
if (accountIndex[_acct] == 0) {
return true;
}
uint acctIndex = getAcctIndex(_acct);
return ((keccak256(abi.encodePacked(acctAccessList[acctIndex].orgId)) == keccak256(abi.encodePacked(_orgId))));
}
// Returns the account index based on account id
function getAcctIndex(address _acct) internal view returns (uint)
{
return accountIndex[_acct] - 1;
}
}

View File

@ -0,0 +1,197 @@
pragma solidity ^0.5.3;
contract NodeManager {
address[] initialAcctList;
// enum and struct declaration
// changing node status to integer (0-NotInList, 1- PendingApproval, 2-Approved,
// PendingDeactivation, Deactivated, PendingActivation, PendingBlacklisting, Blacklisted)
// enum NodeStatus {NotInList, PendingApproval, Approved, PendingDeactivation, Deactivated, PendingActivation, PendingBlacklisting, Blacklisted}
struct NodeDetails {
string enodeId; //e.g. 127.0.0.1:20005
string orgId;
uint status;
}
// use an array to store node details
// if we want to list all node one day, mapping is not capable
NodeDetails[] private nodeList;
// use a mapping of enodeid to array index to track node
mapping(bytes32 => uint) private nodeIdToIndex;
// keep track of node number
uint private numberOfNodes;
// node permission events for new node propose
event NodeProposed(string _enodeId);
event NodeApproved(string _enodeId);
// node permission events for node decativation
event NodePendingDeactivation (string _enodeId);
event NodeDeactivated(string _enodeId);
// node permission events for node activation
event NodePendingActivation(string _enodeId);
event NodeActivated(string _enodeId);
// node permission events for node blacklist
event NodePendingBlacklist(string _enodeId);
event NodeBlacklisted(string);
// Checks if the given enode exists
modifier enodeInList(string memory _enodeId)
{
require(nodeIdToIndex[keccak256(abi.encodePacked(_enodeId))] != 0, "Enode is not in the list");
_;
}
// Checks if the given enode does not exists
modifier enodeNotInList(string memory _enodeId)
{
require(nodeIdToIndex[keccak256(abi.encodePacked(_enodeId))] == 0, "Enode is in the list");
_;
}
// Get node details given enode Id
function getNodeDetails(string memory enodeId) public view returns (string memory _enodeId, uint _nodeStatus)
{
uint nodeIndex = getNodeIndex(enodeId);
return (nodeList[nodeIndex].enodeId, nodeList[nodeIndex].status);
}
// Get node details given index
function getNodeDetailsFromIndex(uint nodeIndex) public view returns (string memory _enodeId, uint _nodeStatus)
{
return (nodeList[nodeIndex].enodeId, nodeList[nodeIndex].status);
}
// Get number of nodes
function getNumberOfNodes() public view returns (uint)
{
return numberOfNodes;
}
// Get node status by enode id
function getNodeStatus(string memory _enodeId) public view returns (uint)
{
if (nodeIdToIndex[keccak256(abi.encodePacked(_enodeId))] == 0){
return 0;
}
return nodeList[getNodeIndex(_enodeId)].status;
}
function addNode(string calldata _enodeId, string calldata _orgId) external enodeNotInList(_enodeId){
numberOfNodes++;
nodeIdToIndex[keccak256(abi.encodePacked(_enodeId))] = numberOfNodes;
nodeList.push(NodeDetails(_enodeId, _orgId, 1));
emit NodeProposed(_enodeId);
}
function addOrgNode(string calldata _enodeId, string calldata _orgId) external enodeNotInList(_enodeId){
numberOfNodes++;
nodeIdToIndex[keccak256(abi.encodePacked(_enodeId))] = numberOfNodes;
nodeList.push(NodeDetails(_enodeId, _orgId, 2));
emit NodeApproved(_enodeId);
}
// Adds a node to the nodeList mapping and emits node added event if successfully and node exists event of node is already present
function approveNode(string calldata _enodeId) external
{
require(getNodeStatus(_enodeId) == 1, "Node need to be in PendingApproval status");
uint nodeIndex = getNodeIndex(_enodeId);
// vote node
nodeList[nodeIndex].status = 2;
emit NodeApproved(nodeList[nodeIndex].enodeId);
}
// // Propose a node for deactivation from network
// function proposeDeactivation(string calldata _enodeId) external enodeInList(_enodeId)
// {
// require(getNodeStatus(_enodeId) == NodeStatus.Approved, "Node need to be in Approved status");
// uint nodeIndex = getNodeIndex(_enodeId);
// nodeList[nodeIndex].status = NodeStatus.PendingDeactivation;
// emit NodePendingDeactivation(_enodeId);
//
// }
//
// //deactivates a given Enode and emits the decativation event
// function deactivateNode(string calldata _enodeId) external
// {
// require(getNodeStatus(_enodeId) == NodeStatus.PendingDeactivation, "Node need to be in PendingDeactivation status");
// uint nodeIndex = getNodeIndex(_enodeId);
// nodeList[nodeIndex].status = NodeStatus.Deactivated;
// emit NodeDeactivated(nodeList[nodeIndex].enodeId);
//
// }
//
// // Propose node for blacklisting
// function proposeNodeActivation(string calldata _enodeId) external
// {
// require(getNodeStatus(_enodeId) == NodeStatus.Deactivated, "Node need to be in Deactivated status");
// uint nodeIndex = getNodeIndex(_enodeId);
// nodeList[nodeIndex].status = NodeStatus.PendingActivation;
// // emit event
// emit NodePendingActivation(_enodeId);
// }
// //deactivates a given Enode and emits the decativation event
// function activateNode(string calldata _enodeId) external
// {
// require(getNodeStatus(_enodeId) == NodeStatus.PendingActivation, "Node need to be in PendingActivation status");
// uint nodeIndex = getNodeIndex(_enodeId);
// require(voteStatus[nodeIndex][msg.sender] == false, "Node can not double vote");
// // vote node
// updateVoteStatus(nodeIndex);
// // emit event
// // check if node vote reach majority
// if (checkEnoughVotes(nodeIndex)) {
// nodeList[nodeIndex].status = NodeStatus.Approved;
// emit NodeActivated(nodeList[nodeIndex].enodeId, nodeList[nodeIndex].ipAddrPort, nodeList[nodeIndex].discPort, nodeList[nodeIndex].raftPort);
// }
// }
//
// // Propose node for blacklisting
// function proposeNodeBlacklisting(string calldata _enodeId, string calldata _ipAddrPort, string calldata _discPort, string calldata _raftPort) external
// {
// if (checkVotingAccountExist()) {
// uint nodeIndex = getNodeIndex(_enodeId);
// // check if node is in the nodeList
// if (nodeIdToIndex[keccak256(abi.encodePacked(_enodeId))] != 0) {
// // no matter what status the node is in, vote will reset and node status change to PendingBlacklisting
// nodeList[nodeIndex].status = NodeStatus.PendingBlacklisting;
// nodeIndex = getNodeIndex(_enodeId);
// } else {
// // increment node number, add node to the list
// numberOfNodes++;
// nodeIdToIndex[keccak256(abi.encodePacked(_enodeId))] = numberOfNodes;
// nodeList.push(NodeDetails(_enodeId, _ipAddrPort, _discPort, _raftPort, NodeStatus.PendingBlacklisting));
// nodeIndex = numberOfNodes;
// }
// // add voting status, numberOfNodes is the index of current proposed node
// initNodeVoteStatus(nodeIndex);
// // emit event
// emit NodePendingBlacklist(_enodeId);
// }
// }
//
// //Approve node blacklisting
// function blacklistNode(string calldata _enodeId) external
// {
// require(getNodeStatus(_enodeId) == NodeStatus.PendingBlacklisting, "Node need to be in PendingBlacklisting status");
// uint nodeIndex = getNodeIndex(_enodeId);
// require(voteStatus[nodeIndex][msg.sender] == false, "Node can not double vote");
// // vote node
// voteStatus[nodeIndex][msg.sender] = true;
// voteCount[nodeIndex]++;
// // emit event
// // check if node vote reach majority
// if (checkEnoughVotes(nodeIndex)) {
// nodeList[nodeIndex].status = NodeStatus.Blacklisted;
// emit NodeBlacklisted(nodeList[nodeIndex].enodeId, nodeList[nodeIndex].ipAddrPort, nodeList[nodeIndex].discPort, nodeList[nodeIndex].raftPort);
// }
// }
/* private functions */
function getNodeIndex(string memory _enodeId) internal view returns (uint)
{
return nodeIdToIndex[keccak256(abi.encodePacked(_enodeId))] - 1;
}
}

View File

@ -0,0 +1,168 @@
pragma solidity ^0.5.3;
import "./PermissionsUpgradable.sol";
contract OrgManager {
string private adminOrgId;
PermissionsImplUpgradeable private permUpgradable;
// checks if first time network boot up has happened or not
bool private networkBoot = false;
// enum OrgStatus {0- NotInList, 1- Proposed, 2- Approved, 3- PendingSuspension, 4- Suspended, 5- RevokeSuspension}
struct OrgDetails {
string orgId;
uint status;
}
OrgDetails [] private orgList;
mapping(bytes32 => uint) private OrgIndex;
uint private orgNum = 0;
// events related to Master Org add
event OrgApproved(string _orgId);
event OrgPendingApproval(string _orgId, uint _type);
event OrgSuspended(string _orgId);
event OrgSuspensionRevoked(string _orgId);
event Dummy(string _msg);
modifier onlyImpl
{
require(msg.sender == permUpgradable.getPermImpl());
_;
}
modifier orgNotExists(string memory _orgId) {
require(checkOrgExists(_orgId) == false, "Org already exists");
_;
}
modifier orgExists(string memory _orgId) {
require(checkOrgExists(_orgId) == true, "Org does not exists");
_;
}
function setUpgradable (address _permUpgradable) external {
permUpgradable = PermissionsImplUpgradeable(_permUpgradable);
}
function addAdminOrg(string calldata _orgId) external
onlyImpl
{
orgNum++;
OrgIndex[keccak256(abi.encodePacked(_orgId))] = orgNum;
uint id = orgList.length++;
orgList[id].orgId = _orgId;
orgList[id].status = 2;
emit OrgApproved(_orgId);
}
// Org related functions
// returns the org index for the org list
function getOrgIndex(string memory _orgId) public view returns (uint)
{
return OrgIndex[keccak256(abi.encodePacked(_orgId))] - 1;
}
function getOrgStatus(string memory _orgId) public view returns (uint)
{
return orgList[OrgIndex[keccak256(abi.encodePacked(_orgId))]].status;
}
// function for adding a new master org
function addOrg(string calldata _orgId) external
onlyImpl
orgNotExists(_orgId)
{
orgNum++;
OrgIndex[keccak256(abi.encodePacked(_orgId))] = orgNum;
uint id = orgList.length++;
orgList[id].orgId = _orgId;
orgList[id].status = 1;
emit OrgPendingApproval(_orgId, 1);
}
function updateOrg(string calldata _orgId, uint _status) external
onlyImpl
orgExists(_orgId)
{
if (_status == 3) {
suspendOrg(_orgId);
}
else {
revokeOrgSuspension(_orgId);
}
}
function approveOrgStatusUpdate(string calldata _orgId, uint _status) external
onlyImpl
orgExists(_orgId)
{
if (_status == 3) {
approveOrgSuspension(_orgId);
}
else {
approveOrgRevokeSuspension(_orgId);
}
}
// function for adding a new master org
function suspendOrg(string memory _orgId) internal
{
require(checkOrgStatus(_orgId, 2) == true, "Org not in approved state");
uint id = getOrgIndex(_orgId);
orgList[id].status = 3;
emit OrgPendingApproval(_orgId, 3);
}
function revokeOrgSuspension(string memory _orgId) internal
{
require(checkOrgStatus(_orgId, 4) == true, "Org not in suspended state");
uint id = getOrgIndex(_orgId);
orgList[id].status = 5;
emit OrgPendingApproval(_orgId, 5);
}
function approveOrg(string calldata _orgId) external
onlyImpl
{
require(checkOrgStatus(_orgId, 1) == true, "Nothing to approve");
uint id = getOrgIndex(_orgId);
orgList[id].status = 2;
emit OrgApproved(_orgId);
}
function approveOrgSuspension(string memory _orgId) internal
{
require(checkOrgStatus(_orgId, 3) == true, "Nothing to approve");
uint id = getOrgIndex(_orgId);
orgList[id].status = 4;
emit OrgSuspended(_orgId);
}
function approveOrgRevokeSuspension(string memory _orgId) internal
{
require(checkOrgStatus(_orgId, 5) == true, "Nothing to approve");
uint id = getOrgIndex(_orgId);
orgList[id].status = 2;
emit OrgSuspensionRevoked(_orgId);
}
function checkOrgStatus(string memory _orgId, uint _orgStatus) public view returns (bool){
uint id = getOrgIndex(_orgId);
return ((OrgIndex[keccak256(abi.encodePacked(_orgId))] != 0) && orgList[id].status == _orgStatus);
}
// function to check if morg exists
function checkOrgExists(string memory _orgId) public view returns (bool)
{
return (!(OrgIndex[keccak256(abi.encodePacked(_orgId))] == 0));
}
// returns org and master org details based on org index
function getOrgInfo(uint _orgIndex) external view returns (string memory, uint)
{
return (orgList[_orgIndex].orgId, orgList[_orgIndex].status);
}
}

View File

@ -0,0 +1,325 @@
pragma solidity ^0.5.3;
import "./RoleManager.sol";
import "./AccountManager.sol";
import "./VoterManager.sol";
import "./NodeManager.sol";
import "./OrgManager.sol";
contract PermissionsImplementation {
AccountManager private accounts;
RoleManager private roles;
VoterManager private voter;
NodeManager private nodes;
OrgManager private org;
string private adminOrg;
string private adminRole;
string private orgAdminRole;
uint private fullAccess = 3;
// checks if first time network boot up has happened or not
bool private networkBoot = false;
// Checks if the given network boot up is pending exists
modifier networkBootUpPending()
{
require(networkBoot == false, "Network boot up completed");
_;
}
// Checks if the given network boot up is pending exists
modifier networkBootUpDone()
{
require(networkBoot == true, "Network boot not complete");
_;
}
modifier networkAdmin(address _account) {
require(isNetworkAdmin(_account) == true, "Not an network admin");
_;
}
modifier orgAdmin(address _account, string memory _orgId) {
require(isOrgAdmin(_account, _orgId) == true, "Not an org admin");
_;
}
modifier orgNotExists(string memory _orgId) {
require(org.checkOrgExists(_orgId) == false, "Org already exists");
_;
}
modifier orgExists(string memory _orgId) {
require(org.checkOrgExists(_orgId) == true, "Org does not exists");
_;
}
modifier orgApproved(string memory _orgId) {
require(org.checkOrgStatus(_orgId, 2) == true, "Org not approved");
_;
}
function setPolicy(string calldata _nwAdminOrg, string calldata _nwAdminRole, string calldata _oAdminRole) external
networkBootUpPending()
{
adminOrg = _nwAdminOrg;
adminRole = _nwAdminRole;
orgAdminRole = _oAdminRole;
}
function init(address _orgManager, address _rolesManager, address _acctManager, address _voterManager, address _nodeManager) external
networkBootUpPending()
{
org = OrgManager(_orgManager);
roles = RoleManager(_rolesManager);
accounts = AccountManager(_acctManager);
voter = VoterManager(_voterManager);
nodes = NodeManager(_nodeManager);
org.addAdminOrg(adminOrg);
roles.addRole(adminRole, adminOrg, fullAccess, true);
accounts.setDefaults(adminRole, orgAdminRole);
}
function addAdminNodes(string calldata _enodeId) external
networkBootUpPending()
{
nodes.addNode(_enodeId, adminOrg);
nodes.approveNode(_enodeId);
}
function addAdminAccounts(address _acct) external
networkBootUpPending()
{
// add the account as a voter for the admin org
voter.addVoter(adminOrg, _acct);
// add the account as an account with full access into the admin org
accounts.addNWAdminAccount(_acct, adminOrg);
}
// update the network boot status as true
function updateNetworkBootStatus() external
networkBootUpPending()
returns (bool)
{
networkBoot = true;
return networkBoot;
}
// // Get network boot status
function getNetworkBootStatus() external view returns (bool)
{
return networkBoot;
}
// function for adding a new master org
function addOrg(string calldata _orgId, string calldata _enodeId) external
networkBootUpDone()
orgNotExists(_orgId)
networkAdmin(msg.sender)
{
org.addOrg(_orgId);
// add the node to permissioned node list
nodes.addNode(_enodeId, _orgId);
// org add has to be approved by network admin org. create an item for approval
voter.addVotingItem(adminOrg, _orgId, _enodeId, address(0), 1);
}
function approveOrg(string calldata _orgId, string calldata _enodeId) external
networkBootUpDone()
networkAdmin(msg.sender)
{
require(org.checkOrgStatus(_orgId, 1) == true, "Nothing to approve");
if ((voter.processVote(adminOrg, msg.sender, 1))) {
org.approveOrg(_orgId);
nodes.approveNode(_enodeId);
}
}
function updateOrgStatus(string calldata _orgId, uint _status) external
networkBootUpDone()
orgExists(_orgId)
networkAdmin(msg.sender)
{
require ((_status == 3 || _status == 5), "Operation not allowed");
uint reqStatus;
uint pendingOp;
if (_status == 3) {
reqStatus = 2;
pendingOp = 2;
}
else if (_status == 5) {
reqStatus = 4;
pendingOp = 3;
}
require(org.checkOrgStatus(_orgId, reqStatus) == true, "Operation not allowed");
org.updateOrg(_orgId, _status);
voter.addVotingItem(adminOrg, _orgId, "", address(0), pendingOp);
}
function approveOrgStatus(string calldata _orgId, uint _status) external
networkBootUpDone()
orgExists(_orgId)
networkAdmin(msg.sender)
{
require ((_status == 3 || _status == 5), "Operation not allowed");
uint pendingOp;
if (_status == 3) {
pendingOp = 2;
}
else if (_status == 5) {
pendingOp = 3;
}
require(org.checkOrgStatus(_orgId, _status) == true, "Operation not allowed");
if ((voter.processVote(adminOrg, msg.sender, pendingOp))) {
org.approveOrgStatusUpdate(_orgId, _status);
}
}
// returns org and master org details based on org index
function getOrgInfo(uint _orgIndex) external view returns (string memory, uint)
{
return org.getOrgInfo(_orgIndex);
}
// Role related functions
function addNewRole(string calldata _roleId, string calldata _orgId, uint _access, bool _voter) external
orgApproved(_orgId)
orgAdmin(msg.sender, _orgId)
{
//add new roles can be created by org admins only
roles.addRole(_roleId, _orgId, _access, _voter);
}
function removeRole(string calldata _roleId, string calldata _orgId) external
orgApproved(_orgId)
orgAdmin(msg.sender, _orgId)
{
roles.removeRole(_roleId, _orgId);
}
function getRoleDetails(string calldata _roleId, string calldata _orgId) external view returns (string memory, string memory, uint, bool, bool)
{
return roles.getRoleDetails(_roleId, _orgId);
}
// Org voter related functions
function getNumberOfVoters(string calldata _orgId) external view returns (uint){
return voter.getNumberOfValidVoters(_orgId);
}
function checkIfVoterExists(string calldata _orgId, address _acct) external view returns (bool)
{
return voter.checkIfVoterExists(_orgId, _acct);
}
function getVoteCount(string calldata _orgId) external view returns (uint, uint)
{
return voter.getVoteCount(_orgId);
}
function getPendingOp(string calldata _orgId) external view returns (string memory, string memory, address, uint)
{
return voter.getPendingOpDetails(_orgId);
}
function assignOrgAdminAccount(string calldata _orgId, address _account) external
networkBootUpDone()
networkAdmin(msg.sender)
orgExists(_orgId)
{
// check if orgAdmin already exists if yes then op cannot be performed
require(accounts.orgAdminExists(_orgId) != true, "org admin exists");
// assign the account org admin role and propose voting
accounts.assignAccountRole(_account, _orgId, orgAdminRole);
//add voting item
voter.addVotingItem(adminOrg, _orgId, "", _account, 4);
}
function approveOrgAdminAccount(address _account) external
networkBootUpDone()
networkAdmin(msg.sender)
{
require(isNetworkAdmin(msg.sender) == true, "can be called from network admin only");
if ((voter.processVote(adminOrg, msg.sender, 4))) {
accounts.approveOrgAdminAccount(_account);
}
}
function assignAccountRole(address _acct, string memory _orgId, string memory _roleId) public
networkBootUpDone()
orgApproved(_orgId)
orgAdmin(msg.sender, _orgId)
{
// check if the account is part of another org. If yes then op cannot be done
require(validateAccount(_acct, _orgId) == true, "Operation cannot be performed");
// check if role is existing for the org. if yes the op can be done
require(roles.roleExists(_roleId, _orgId) == true, "role does not exists");
bool newRoleVoter = roles.isVoterRole(_roleId, _orgId);
// check the role of the account. if the current role is voter and new role is also voter
// voterlist change is not required. else voter list needs to be changed
string memory acctRole = accounts.getAccountRole(_acct);
if (keccak256(abi.encodePacked(acctRole)) == keccak256(abi.encodePacked("NONE"))) {
//new account
if (newRoleVoter) {
// add to voter list
voter.addVoter(_orgId, _acct);
}
}
else {
bool currRoleVoter = roles.isVoterRole(acctRole, _orgId);
if (!(currRoleVoter && newRoleVoter)) {
if (newRoleVoter) {
// add to voter list
voter.addVoter(_orgId, _acct);
}
else {
// delete from voter list
voter.deleteVoter(_orgId, _acct);
}
}
}
accounts.assignAccountRole(_acct, _orgId, _roleId);
}
function addNode(string calldata _orgId, string calldata _enodeId) external
networkBootUpDone()
orgApproved(_orgId)
orgAdmin(msg.sender, _orgId)
{
// check that the node is not part of another org
require(getNodeStatus(_enodeId) == 0, "Node present already");
nodes.addOrgNode(_enodeId, _orgId);
}
function getNodeStatus(string memory _enodeId) public view returns (uint)
{
return (nodes.getNodeStatus(_enodeId));
}
function isNetworkAdmin(address _account) public view returns (bool)
{
return (keccak256(abi.encodePacked(accounts.getAccountRole(_account))) == keccak256(abi.encodePacked(adminRole)));
}
function isOrgAdmin(address _account, string memory _orgId) public view returns (bool)
{
return (accounts.checkOrgAdmin(_account, _orgId));
}
function validateAccount(address _account, string memory _orgId) public view returns (bool)
{
return (accounts.valAcctAccessChange(_account, _orgId));
}
function getAccountDetails(address _acct) external view returns (address, string memory, string memory, uint, bool)
{
return accounts.getAccountDetails(_acct);
}
}

View File

@ -0,0 +1,174 @@
pragma solidity ^0.5.3;
import "./PermissionsImplementation.sol";
contract PermissionsInterface {
PermissionsImplementation permImplementation;
address private permImplUpgradeable;
constructor(address _permImplUpgradeable) public {
permImplUpgradeable = _permImplUpgradeable;
}
modifier onlyUpgradeable {
require(msg.sender == permImplUpgradeable);
_;
}
function setPermImplementation(address _permImplementation) public
onlyUpgradeable
{
permImplementation = PermissionsImplementation(_permImplementation);
}
function getPermissionsImpl() public view returns(address)
{
return address(permImplementation);
}
function setPolicy(string calldata _nwAdminOrg, string calldata _nwAdminRole, string calldata _oAdminRole) external
{
permImplementation.setPolicy(_nwAdminOrg, _nwAdminRole, _oAdminRole);
}
function init(address _orgManager, address _rolesManager, address _acctManager, address _voterManager, address _nodeManager) external
{
permImplementation.init(_orgManager, _rolesManager, _acctManager, _voterManager, _nodeManager);
}
function addAdminNodes(string calldata _enodeId) external
{
permImplementation.addAdminNodes(_enodeId);
}
function addAdminAccounts(address _acct) external
{
permImplementation.addAdminAccounts(_acct);
}
// update the network boot status as true
function updateNetworkBootStatus() external
returns (bool)
{
permImplementation.updateNetworkBootStatus();
}
// // Get network boot status
function getNetworkBootStatus() external view returns (bool)
{
return permImplementation.getNetworkBootStatus();
}
// function for adding a new master org
function addOrg(string calldata _orgId, string calldata _enodeId) external
{
permImplementation.addOrg(_orgId, _enodeId);
}
function approveOrg(string calldata _orgId, string calldata _enodeId) external
{
permImplementation.approveOrg(_orgId, _enodeId);
}
function updateOrgStatus(string calldata _orgId, uint _status) external
{
permImplementation.updateOrgStatus(_orgId, _status);
}
function approveOrgStatus(string calldata _orgId, uint _status) external
{
permImplementation.approveOrgStatus(_orgId, _status);
}
// returns org and master org details based on org index
function getOrgInfo(uint _orgIndex) external view returns (string memory, uint)
{
return permImplementation.getOrgInfo(_orgIndex);
}
// Role related functions
function addNewRole(string calldata _roleId, string calldata _orgId, uint _access, bool _voter) external
{
permImplementation.addNewRole(_roleId, _orgId, _access, _voter);
}
function removeRole(string calldata _roleId, string calldata _orgId) external
{
permImplementation.removeRole(_roleId, _orgId);
}
function getRoleDetails(string calldata _roleId, string calldata _orgId) external view returns (string memory, string memory, uint, bool, bool)
{
return permImplementation.getRoleDetails(_roleId, _orgId);
}
// Org voter related functions
function getNumberOfVoters(string calldata _orgId) external view returns (uint)
{
return permImplementation.getNumberOfVoters(_orgId);
}
function checkIfVoterExists(string calldata _orgId, address _acct) external view returns (bool)
{
return permImplementation.checkIfVoterExists(_orgId, _acct);
}
function getVoteCount(string calldata _orgId) external view returns (uint, uint)
{
return permImplementation.getVoteCount(_orgId);
}
function getPendingOp(string calldata _orgId) external view returns (string memory, string memory, address, uint)
{
return permImplementation.getPendingOp(_orgId);
}
function assignOrgAdminAccount(string calldata _orgId, address _account) external
{
permImplementation.assignOrgAdminAccount(_orgId, _account);
}
function approveOrgAdminAccount(address _account) external
{
permImplementation.approveOrgAdminAccount(_account);
}
function assignAccountRole(address _acct, string memory _orgId, string memory _roleId) public
{
permImplementation.assignAccountRole(_acct, _orgId, _roleId);
}
function addNode(string calldata _orgId, string calldata _enodeId) external
{
permImplementation.addNode(_orgId, _enodeId);
}
function getNodeStatus(string memory _enodeId) public view returns (uint)
{
return permImplementation.getNodeStatus(_enodeId);
}
function isNetworkAdmin(address _account) public view returns (bool)
{
return permImplementation.isNetworkAdmin(_account);
}
function isOrgAdmin(address _account, string memory _orgId) public view returns (bool)
{
return permImplementation.isOrgAdmin(_account, _orgId);
}
function validateAccount(address _account, string memory _orgId) public view returns (bool)
{
return permImplementation.validateAccount(_account, _orgId);
}
function getAccountDetails(address _acct) external view returns (address, string memory, string memory, uint, bool)
{
return permImplementation.getAccountDetails(_acct);
}
}

View File

@ -0,0 +1,43 @@
pragma solidity ^0.5.3;
import "./PermissionsInterface.sol";
contract PermissionsImplUpgradeable {
address private custodian;
address private permImpl;
// store the instances in the contract because upgradeable will setCoinImpl for them
PermissionsInterface private permInterface;
constructor (address _custodian, address _permInterface, address _permImpl) public {
custodian = _custodian;
permImpl = _permImpl;
permInterface = PermissionsInterface(_permInterface);
setImpl(_permImpl);
}
modifier onlyCustodian {
require(msg.sender == custodian);
_;
}
// custodian can potentially become a contract
// implementation change and custodian change are sending from custodian
function confirmImplChange(address _proposedImpl) public onlyCustodian {
permImpl = _proposedImpl;
setImpl(permImpl);
}
function getCustodian() public view returns(address) {
return custodian;
}
function getPermImpl() public view returns(address) {
return permImpl;
}
function setImpl(address _permImpl) private {
permInterface.setPermImplementation(_permImpl);
}
}

View File

@ -0,0 +1,80 @@
pragma solidity ^0.5.3;
contract RoleManager {
struct RoleDetails {
string roleId;
string orgId;
uint baseAccess;
bool isVoter;
bool active;
}
RoleDetails[] private roleList;
mapping(bytes32 => uint) private roleIndex;
uint private numberOfRoles;
event RoleCreated(string _roleId, string _orgId);
event RoleRevoked(string _roleId, string _orgId);
function roleExists(string memory _roleId, string memory _orgId) public view returns(bool)
{
return (roleIndex[keccak256(abi.encodePacked(_roleId, _orgId))] != 0);
}
function getRoleDetails(string calldata _roleId, string calldata _orgId) external view returns (string memory roleId, string memory orgId, uint accessType, bool voter, bool active)
{
if (!(roleExists(_roleId, _orgId))){
return (_roleId, "", 0, false, false);
}
uint rIndex = getRoleIndex(_roleId, _orgId);
return (roleList[rIndex].roleId, roleList[rIndex].orgId, roleList[rIndex].baseAccess, roleList[rIndex].isVoter, roleList[rIndex].active);
}
// Get number of Role
function getNumberOfRoles() external view returns (uint)
{
return roleList.length;
}
function addRole(string memory _roleId, string memory _orgId, uint _baseAccess, bool _voter) public
{
// Check if account already exists
if (roleIndex[keccak256(abi.encodePacked(_roleId, _orgId))] == 0) {
numberOfRoles ++;
roleIndex[keccak256(abi.encodePacked(_roleId, _orgId))] = numberOfRoles;
roleList.push(RoleDetails(_roleId, _orgId, _baseAccess, _voter, true));
emit RoleCreated(_roleId, _orgId);
}
}
function removeRole(string calldata _roleId, string calldata _orgId) external{
if (roleIndex[keccak256(abi.encodePacked(_roleId, _orgId))] != 0) {
uint rIndex = getRoleIndex(_roleId, _orgId);
roleList[rIndex].active = false;
emit RoleRevoked(_roleId, _orgId);
}
}
// Returns the account index based on account id
function getRoleIndex(string memory _roleId, string memory _orgId) internal view returns (uint)
{
return roleIndex[keccak256(abi.encodePacked(_roleId, _orgId))] - 1;
}
function isFullAccessRole(string calldata _roleId, string calldata _orgId) external view returns (bool){
if (!(roleExists(_roleId, _orgId))){
return false;
}
uint rIndex = getRoleIndex(_roleId, _orgId);
return (roleList[rIndex].active && roleList[rIndex].baseAccess == 3);
}
function isVoterRole(string calldata _roleId, string calldata _orgId) external view returns (bool){
if (!(roleExists(_roleId, _orgId))){
return false;
}
uint rIndex = getRoleIndex(_roleId, _orgId);
return (roleList[rIndex].active && roleList[rIndex].isVoter);
}
}

View File

@ -0,0 +1,195 @@
pragma solidity ^0.5.3;
contract VoterManager {
// enum PendingOpType {0-None, 1-OrgAdd, 2-OrgSuspension, 3-OrgRevokeSuspension, 4-AddOrgAdmin}
struct PendingOpDetails {
string orgId;
string enodeId;
address account;
uint opType;
}
struct VoterDetails {
address vAccount;
bool active;
}
struct OrgVoterDetails {
string orgId;
uint voterCount;
uint validVoterCount;
uint voteCount;
PendingOpDetails pendingOp;
VoterDetails [] voterList;
mapping(address => uint) voterIndex;
mapping(uint => mapping(address => bool)) votingStatus;
}
OrgVoterDetails [] private orgVoterList;
mapping(bytes32 => uint) private VoterOrgIndex;
uint private orgNum = 0;
// events related to managing voting accounts for the org
event VoterAdded(string _orgId, address _address);
event VoterDeleted(string _orgId, address _address);
event VotingItemAdded(string _orgId);
event VoteProcessed(string _orgId);
event Dummy(string _msg);
modifier voterExists(string memory _orgId, address _address) {
require(checkIfVoterExists(_orgId, _address) == true, "must be a voter");
_;
}
// returns the voter index
function getVoterIndex(string memory _orgId, address _vAccount) internal view returns (uint)
{
uint orgIndex = getVoterOrgIndex(_orgId);
return orgVoterList[orgIndex].voterIndex[_vAccount] - 1;
}
// returns the master org index for the org from voter list
function getVoterOrgIndex(string memory _orgId) internal view returns (uint)
{
return VoterOrgIndex[keccak256(abi.encodePacked(_orgId))] - 1;
}
// checks if the org has any voter accounts set up or not
function checkIfVoterExists(string memory _orgId, address _address) public view returns (bool){
uint orgIndex = getVoterOrgIndex(_orgId);
if (orgVoterList[orgIndex].voterIndex[_address] == 0) {
return false;
}
uint voterIndex = getVoterIndex(_orgId, _address);
return orgVoterList[orgIndex].voterList[voterIndex].active;
}
// Get number of total voters
function getNumberOfVoters(string calldata _orgId) external view returns (uint)
{
return orgVoterList[getVoterOrgIndex(_orgId)].voterCount;
}
// Get number of valid voters
function getNumberOfValidVoters(string calldata _orgId) external view returns (uint)
{
return orgVoterList[getVoterOrgIndex(_orgId)].validVoterCount;
}
// checks if the voting accounts exists for the org
function checkVotingAccountExists(string calldata _orgId) external view returns (bool)
{
uint orgIndex = getVoterOrgIndex(_orgId);
return (orgVoterList[orgIndex].validVoterCount > 0);
}
// function for adding a voter account to a master org
function addVoter(string calldata _orgId, address _address) external
{
// check if the org exists
if (VoterOrgIndex[keccak256(abi.encodePacked(_orgId))] == 0) {
orgNum++;
VoterOrgIndex[keccak256(abi.encodePacked(_orgId))] = orgNum;
uint 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[_address] = orgVoterList[id].voterCount;
orgVoterList[id].voterList.push(VoterDetails(_address, true));
}
else {
uint id = getVoterOrgIndex(_orgId);
// check of the voter already present in the list
if (orgVoterList[id].voterIndex[_address] == 0) {
orgVoterList[id].voterCount++;
orgVoterList[id].voterIndex[_address] = orgVoterList[id].voterCount;
orgVoterList[id].voterList.push(VoterDetails(_address, true));
orgVoterList[id].validVoterCount++;
}
else {
uint vid = getVoterIndex(_orgId, _address);
require(orgVoterList[id].voterList[vid].active != true, "already a voter");
orgVoterList[id].voterList[vid].active = true;
orgVoterList[id].validVoterCount++;
}
}
emit VoterAdded(_orgId, _address);
}
// function for deleting a voter account to a master org
function deleteVoter(string calldata _orgId, address _address) external voterExists(_orgId, _address)
{
uint id = getVoterOrgIndex(_orgId);
uint vId = getVoterIndex(_orgId, _address);
orgVoterList[id].validVoterCount --;
orgVoterList[id].voterList[vId].active = false;
emit VoterDeleted(_orgId, _address);
}
// function for adding an item into voting queue of the org
function addVotingItem(string calldata _authOrg, string calldata _orgId, string calldata _enodeId, address _account, uint _pendingOp) external
{
// check if anything is pending approval for the org. If yes another item cannot be added
require((checkPendingOp(_authOrg, 0)), "Items pending approval. New item cannot be added");
uint id = getVoterOrgIndex(_authOrg);
orgVoterList[id].pendingOp.orgId = _orgId;
orgVoterList[id].pendingOp.enodeId = _enodeId;
orgVoterList[id].pendingOp.account = _account;
orgVoterList[id].pendingOp.opType = _pendingOp;
// init vote status
for (uint 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);
}
// process vote and update status
function processVote(string calldata _authOrg, address _vAccount, uint _pendingOp) external voterExists(_authOrg, _vAccount) returns (bool) {
// check something is pending approval
require(checkPendingOp(_authOrg, _pendingOp) == true, "nothing to approve");
uint id = getVoterOrgIndex(_authOrg);
// check if vote 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;
}
function checkPendingOp(string memory _orgId, uint _pendingOp) internal view returns (bool){
return (orgVoterList[getVoterOrgIndex(_orgId)].pendingOp.opType == _pendingOp);
}
function getVoteCount(string calldata _orgId) external view returns (uint, uint) {
uint orgIndex = getVoterOrgIndex(_orgId);
return (orgVoterList[orgIndex].voteCount, orgVoterList[orgIndex].validVoterCount);
}
function getPendingOpDetails(string calldata _orgId) external view returns (string memory, string memory, address, uint){
uint orgIndex = getVoterOrgIndex(_orgId);
return (orgVoterList[orgIndex].pendingOp.orgId, orgVoterList[orgIndex].pendingOp.enodeId, orgVoterList[orgIndex].pendingOp.account, orgVoterList[orgIndex].pendingOp.opType);
}
}