quorum/controls/permission/Permission.sol

404 lines
14 KiB
Solidity
Raw Normal View History

2018-07-11 00:25:45 -07:00
pragma solidity ^0.4.23;
contract Permissions {
address[] initialAcctList;
2018-09-05 19:40:21 -07:00
// enum and struct declaration
2018-11-02 03:42:14 -07:00
enum NodeStatus {NotInList, PendingApproval, Approved, PendingDeactivation, Deactivated, PendingActivation, PendingBlacklisting, Blacklisted }
2018-09-05 19:40:21 -07:00
struct NodeDetails {
string enodeId; //e.g. 127.0.0.1:20005
string ipAddrPort;
string discPort;
string raftPort;
2018-07-11 00:25:45 -07:00
NodeStatus status;
}
2018-11-02 03:42:14 -07:00
enum AccountAccess { FullAccess, ReadOnly, Transact, ContractDeploy }
struct AccountAccessDetails {
address acctId;
AccountAccess acctAccess;
}
2018-09-05 19:40:21 -07:00
// use an array to store node details
// if we want to list all node one day, mapping is not capable
NodeDetails[] private nodeList;
2018-11-02 03:42:14 -07:00
2018-09-05 19:40:21 -07:00
// use a mapping of enodeid to array index to track node
mapping (bytes32 => uint) private nodeIdToIndex;
// keep track of node number
uint private numberOfNodes;
2018-08-05 22:26:29 -07:00
2018-11-02 03:42:14 -07:00
AccountAccessDetails[] private acctAccessList;
2018-11-02 03:42:14 -07:00
mapping (address => uint) private acctToIndex;
uint private numberOfAccts;
2018-09-05 19:40:21 -07:00
// use an array to store account details
// if we want to list all account one day, mapping is not capable
2018-11-02 03:42:14 -07:00
address[] private voterAcctList;
2018-09-05 19:40:21 -07:00
// store node approval, deactivation and blacklisting vote status (prevent double vote)
mapping (uint => mapping (address => bool)) private voteStatus;
// valid vote count
mapping (uint => uint) private voteCount;
// checks if first time network boot up has happened or not
bool private networkBoot = false;
2018-09-19 20:18:39 -07:00
// node permission events for new node propose
event NodeProposed(string _enodeId);
event NodeApproved(string _enodeId, string _ipAddrPort, string _discPort, string _raftPort);
2018-09-19 20:18:39 -07:00
// node permission events for node decativation
2018-07-11 00:25:45 -07:00
event NodePendingDeactivation (string _enodeId);
event NodeDeactivated(string _enodeId, string _ipAddrPort, string _discPort, string _raftPort);
2018-09-19 20:18:39 -07:00
2018-11-02 03:42:14 -07:00
// node permission events for node activation
event NodePendingActivation(string _enodeId);
event NodeActivated(string _enodeId, string _ipAddrPort, string _discPort, string _raftPort);
2018-09-19 20:18:39 -07:00
// node permission events for node blacklist
event NodePendingBlacklist(string _enodeId);
2018-08-31 04:35:35 -07:00
event NodeBlacklisted(string _enodeId, string _ipAddrPort, string _discPort, string _raftPort);
2018-09-19 20:18:39 -07:00
2018-09-05 19:40:21 -07:00
// account permission events
event AccountAccessModified(address _address, AccountAccess _access);
2018-09-19 20:18:39 -07:00
// Checks if the given enode exists
2018-09-05 19:40:21 -07:00
modifier enodeInList(string _enodeId)
{
require(nodeIdToIndex[keccak256(abi.encodePacked(_enodeId))] != 0, "Enode is not in the list");
_;
}
2018-09-19 20:18:39 -07:00
// Checks if the given enode does not exists
2018-09-05 19:40:21 -07:00
modifier enodeNotInList(string _enodeId)
{
require(nodeIdToIndex[keccak256(abi.encodePacked(_enodeId))] == 0, "Enode is in the list");
_;
}
2018-09-19 20:18:39 -07:00
// Checks if the account can vote
2018-09-05 19:40:21 -07:00
modifier canVote()
{
bool flag = false;
2018-11-02 03:42:14 -07:00
for (uint i=0; i<voterAcctList.length; i++){
if (voterAcctList[i] == msg.sender){
2018-09-05 19:40:21 -07:00
flag = true;
break;
}
}
require(flag, "Account can not vote");
_;
2018-08-31 04:35:35 -07:00
}
2018-09-05 19:40:21 -07:00
/* public and external functions */
// view functions
// Get number of voters
2018-11-02 03:42:14 -07:00
function getNumberOfVoters() public view returns (uint)
2018-10-31 00:15:34 -07:00
{
return voterAcctList.length;
2018-10-31 00:15:34 -07:00
}
2018-11-15 21:40:36 -08:00
// Get voter
function getVoter(uint i) public view returns (address _addr)
{
return voterAcctList[i];
}
// Get number of nodes
function getNetworkBootStatus() public view returns (bool)
{
return networkBoot;
}
// Get node details given enode Id
function getNodeDetails(string enodeId) public view returns (string _enodeId, string _ipAddrPort, string _discPort, string _raftPort, NodeStatus _nodeStatus)
{
uint nodeIndex = getNodeIndex(enodeId);
return (nodeList[nodeIndex].enodeId, nodeList[nodeIndex].ipAddrPort, nodeList[nodeIndex].discPort, nodeList[nodeIndex].raftPort, nodeList[nodeIndex].status);
}
2018-11-14 01:58:57 -08:00
// Get node details given index
function getNodeDetailsFromIndex(uint nodeIndex) public view returns (string _enodeId, string _ipAddrPort, string _discPort, string _raftPort, NodeStatus _nodeStatus)
2018-11-14 01:58:57 -08:00
{
return (nodeList[nodeIndex].enodeId, nodeList[nodeIndex].ipAddrPort, nodeList[nodeIndex].discPort, nodeList[nodeIndex].raftPort, nodeList[nodeIndex].status);
}
2018-09-05 19:40:21 -07:00
// Get number of nodes
function getNumberOfNodes() public view returns (uint)
2018-09-05 19:40:21 -07:00
{
return numberOfNodes;
}
2018-11-15 20:21:50 -08:00
// Get account details given index
function getAccountDetails(uint acctIndex) public view returns (address _acct, AccountAccess _acctAccess)
{
return (acctAccessList[acctIndex].acctId, acctAccessList[acctIndex].acctAccess);
}
2018-11-15 20:21:50 -08:00
2018-09-05 19:40:21 -07:00
// Get number of accounts and voting accounts
function getNumberOfAccounts() public view returns (uint)
2018-09-05 19:40:21 -07:00
{
2018-11-02 03:42:14 -07:00
return acctAccessList.length;
2018-09-05 19:40:21 -07:00
}
// Get node status by enode id
function getNodeStatus(string _enodeId) public view enodeInList(_enodeId) returns (NodeStatus)
2018-09-05 19:40:21 -07:00
{
return nodeList[getNodeIndex(_enodeId)].status;
}
2018-11-13 00:15:28 -08:00
function isVoter(address _acctid) external view returns (bool)
{
bool flag = false;
for (uint i=0; i<voterAcctList.length; i++){
if (voterAcctList[i] == _acctid){
flag = true;
break;
}
}
return flag;
}
2018-09-05 19:40:21 -07:00
// update the networ boot status as true
function updateNetworkBootStatus() external returns (bool)
{
require (networkBoot == false, "Invalid call: Network boot up completed");
networkBoot = true;
return networkBoot;
}
2018-09-05 19:40:21 -07:00
2018-11-02 03:42:14 -07:00
function initNodeVoteStatus(uint nodeIndex) internal {
voteCount[nodeIndex] = 0;
for (uint i = 0; i < voterAcctList.length; i++){
voteStatus[nodeIndex][voterAcctList[i]] = false;
}
}
function updateVoteStatus(uint nodeIndex) internal {
voteCount[nodeIndex]++;
voteStatus[nodeIndex][msg.sender] = true;
}
function checkEnoughVotes(uint nodeIndex) internal view returns (bool) {
bool approvalStatus = false;
if (voteCount[nodeIndex] > voterAcctList.length / 2){
approvalStatus = true;
}
return approvalStatus;
}
2018-08-31 04:35:35 -07:00
// propose a new node to the network
2018-09-19 20:18:39 -07:00
function proposeNode(string _enodeId, string _ipAddrPort, string _discPort, string _raftPort) external enodeNotInList(_enodeId)
2018-09-05 19:40:21 -07:00
{
if (!(networkBoot)){
2018-09-05 19:40:21 -07:00
numberOfNodes++;
nodeIdToIndex[keccak256(abi.encodePacked(_enodeId))] = numberOfNodes;
nodeList.push(NodeDetails(_enodeId, _ipAddrPort,_discPort, _raftPort, NodeStatus.Approved));
}
else {
if (checkVotingAccountExist()){
// increment node number, add node to the list
numberOfNodes++;
nodeIdToIndex[keccak256(abi.encodePacked(_enodeId))] = numberOfNodes;
nodeList.push(NodeDetails(_enodeId, _ipAddrPort,_discPort, _raftPort, NodeStatus.PendingApproval));
2018-11-02 03:42:14 -07:00
// add voting status, numberOfNodes is the index of current proposed node
2018-11-02 03:42:14 -07:00
initNodeVoteStatus(numberOfNodes);
// emit event
emit NodeProposed(_enodeId);
2018-09-05 19:40:21 -07:00
}
}
2018-07-11 00:25:45 -07:00
}
// 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 _enodeId) external canVote
2018-09-05 19:40:21 -07:00
{
require(getNodeStatus(_enodeId) == NodeStatus.PendingApproval, "Node need to be in PendingApproval status");
uint nodeIndex = getNodeIndex(_enodeId);
require(voteStatus[nodeIndex][msg.sender] == false, "Node can not double vote");
// vote node
2018-11-02 03:42:14 -07:00
updateVoteStatus(nodeIndex);
2018-09-05 19:40:21 -07:00
// emit event
// check if node vote reach majority
2018-11-02 03:42:14 -07:00
if (checkEnoughVotes(nodeIndex)) {
nodeList[nodeIndex].status = NodeStatus.Approved;
emit NodeApproved(nodeList[nodeIndex].enodeId, nodeList[nodeIndex].ipAddrPort, nodeList[nodeIndex].discPort, nodeList[nodeIndex].raftPort);
}
2018-07-11 00:25:45 -07:00
}
2018-08-31 04:35:35 -07:00
// Propose a node for deactivation from network
2018-09-19 20:18:39 -07:00
function proposeDeactivation(string _enodeId) external enodeInList(_enodeId)
2018-09-05 19:40:21 -07:00
{
if (checkVotingAccountExist()){
require(getNodeStatus(_enodeId) == NodeStatus.Approved, "Node need to be in Approved status");
uint nodeIndex = getNodeIndex(_enodeId);
nodeList[nodeIndex].status = NodeStatus.PendingDeactivation;
// add voting status, numberOfNodes is the index of current proposed node
2018-11-02 03:42:14 -07:00
initNodeVoteStatus(nodeIndex);
2018-09-05 19:40:21 -07:00
// emit event
emit NodePendingDeactivation(_enodeId);
}
2018-07-11 00:25:45 -07:00
}
//deactivates a given Enode and emits the decativation event
2018-09-19 20:18:39 -07:00
function deactivateNode(string _enodeId) external canVote
2018-09-05 19:40:21 -07:00
{
2018-07-11 00:25:45 -07:00
require(getNodeStatus(_enodeId) == NodeStatus.PendingDeactivation, "Node need to be in PendingDeactivation status");
2018-09-05 19:40:21 -07:00
uint nodeIndex = getNodeIndex(_enodeId);
require(voteStatus[nodeIndex][msg.sender] == false, "Node can not double vote");
// vote node
2018-11-02 03:42:14 -07:00
updateVoteStatus(nodeIndex);
2018-09-05 19:40:21 -07:00
// emit event
// check if node vote reach majority
2018-11-02 03:42:14 -07:00
if (checkEnoughVotes(nodeIndex)) {
nodeList[nodeIndex].status = NodeStatus.Deactivated;
emit NodeDeactivated(nodeList[nodeIndex].enodeId, nodeList[nodeIndex].ipAddrPort, nodeList[nodeIndex].discPort, nodeList[nodeIndex].raftPort);
}
}
// Propose node for blacklisting
function proposeNodeActivation(string _enodeId) external
{
if (checkVotingAccountExist()){
require(getNodeStatus(_enodeId) == NodeStatus.Deactivated, "Node need to be in Deactivated status");
uint nodeIndex = getNodeIndex(_enodeId);
nodeList[nodeIndex].status = NodeStatus.PendingActivation;
// add voting status, numberOfNodes is the index of current proposed node
initNodeVoteStatus(nodeIndex);
// emit event
emit NodePendingActivation(_enodeId);
}
}
//deactivates a given Enode and emits the decativation event
function activateNode(string _enodeId) external canVote
{
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);
}
2018-07-11 00:25:45 -07:00
}
2018-09-05 19:40:21 -07:00
// Propose node for blacklisting
2018-09-19 20:18:39 -07:00
function proposeNodeBlacklisting(string _enodeId, string _ipAddrPort, string _discPort, string _raftPort) external
2018-09-05 19:40:21 -07:00
{
if (checkVotingAccountExist()){
2018-11-02 03:42:14 -07:00
uint nodeIndex = getNodeIndex(_enodeId);
2018-09-05 19:40:21 -07:00
// 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;
2018-09-19 20:18:39 -07:00
nodeList.push(NodeDetails(_enodeId, _ipAddrPort,_discPort, _raftPort, NodeStatus.PendingBlacklisting));
2018-09-05 19:40:21 -07:00
nodeIndex = numberOfNodes;
}
// add voting status, numberOfNodes is the index of current proposed node
2018-11-02 03:42:14 -07:00
initNodeVoteStatus(nodeIndex);
2018-09-05 19:40:21 -07:00
// emit event
2018-09-19 20:18:39 -07:00
emit NodePendingBlacklist(_enodeId);
2018-08-31 04:35:35 -07:00
}
}
//Approve node blacklisting
2018-09-19 20:18:39 -07:00
function blacklistNode(string _enodeId) external canVote
2018-09-05 19:40:21 -07:00
{
2018-08-31 04:35:35 -07:00
require(getNodeStatus(_enodeId) == NodeStatus.PendingBlacklisting, "Node need to be in PendingBlacklisting status");
2018-09-05 19:40:21 -07:00
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
2018-11-02 03:42:14 -07:00
if (checkEnoughVotes(nodeIndex)) {
nodeList[nodeIndex].status = NodeStatus.Blacklisted;
emit NodeBlacklisted(nodeList[nodeIndex].enodeId, nodeList[nodeIndex].ipAddrPort, nodeList[nodeIndex].discPort, nodeList[nodeIndex].raftPort);
}
2018-08-31 04:35:35 -07:00
}
function initAccounts() external
{
require(networkBoot == false, "network accounts already boot up");
for (uint i=0; i<initialAcctList.length; i++){
if (acctToIndex[initialAcctList[i]] == 0){
numberOfAccts ++;
acctToIndex[initialAcctList[i]] = numberOfAccts;
acctAccessList.push(AccountAccessDetails(initialAcctList[i], AccountAccess.FullAccess));
emit AccountAccessModified(initialAcctList[i], AccountAccess.FullAccess);
}
}
}
2018-08-31 04:35:35 -07:00
// Checks if the Node is already added. If yes then returns true
function updateAccountAccess(address _address, AccountAccess _accountAccess) external
2018-09-05 19:40:21 -07:00
{
2018-11-02 03:42:14 -07:00
// Check if account already exists
uint acctIndex = getAcctIndex(_address);
if (acctToIndex[_address] != 0){
acctAccessList[acctIndex].acctAccess = _accountAccess;
}
else{
numberOfAccts ++;
acctToIndex[_address] = numberOfAccts;
acctAccessList.push(AccountAccessDetails(_address, _accountAccess));
}
2018-11-15 19:07:10 -08:00
emit AccountAccessModified(_address, _accountAccess);
2018-09-05 19:40:21 -07:00
}
// Add voting account
function addVoter(address _address) external
2018-09-05 19:40:21 -07:00
{
// Check if account already exists
2018-11-02 03:42:14 -07:00
for (uint i=0; i<voterAcctList.length; i++){
if (voterAcctList[i] == _address){
2018-09-05 19:40:21 -07:00
return;
}
}
2018-11-02 03:42:14 -07:00
voterAcctList.push(_address);
2018-09-05 19:40:21 -07:00
}
// Remove voting account
function removeVoter(address _address) external
2018-09-05 19:40:21 -07:00
{
// Check if account already exists
2018-11-02 03:42:14 -07:00
for (uint i=0; i<voterAcctList.length; i++){
if (voterAcctList[i] == _address){
for (uint j=i; j<voterAcctList.length -1; j++){
voterAcctList[j] = voterAcctList[j+1];
2018-09-05 19:40:21 -07:00
}
2018-11-02 03:42:14 -07:00
delete voterAcctList[voterAcctList.length - 1];
voterAcctList.length --;
2018-09-05 19:40:21 -07:00
}
}
}
/* private functions */
function getNodeIndex(string _enodeId) internal view returns (uint)
2018-09-05 19:40:21 -07:00
{
return nodeIdToIndex[keccak256(abi.encodePacked(_enodeId))] - 1;
}
2018-11-02 03:42:14 -07:00
/* private functions */
function getAcctIndex(address _acct) internal view returns (uint)
{
return acctToIndex[_acct] - 1;
}
function checkVotingAccountExist() internal view returns (bool)
2018-09-05 19:40:21 -07:00
{
2018-11-02 03:42:14 -07:00
if (voterAcctList.length == 0){
2018-09-05 19:40:21 -07:00
return false;
} else {
return true;
}
}
2018-07-11 00:25:45 -07:00
}