mirror of https://github.com/poanetwork/quorum.git
Permissions new contracts as per latest spec
This commit is contained in:
parent
d650d5522d
commit
50a55a2c09
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue