Merge remote-tracking branch 'qeng/feature/permissioning-1.8.18' into feature/permissioning-1.8.18

This commit is contained in:
vsmk98 2019-04-01 18:30:51 +08:00
commit 2fd649bb36
8 changed files with 196 additions and 675 deletions

View File

@ -403,7 +403,7 @@ func startQuorumPermissionService(ctx *cli.Context, stack *node.Node) {
}
if err = pc.Start(); err == nil {
quorumApis = []string{"quorumNodeMgmt"}
quorumApis = []string{"quorumPermission"}
} else {
utils.Fatalf("Failed to start Quorum Permission contract service %v", err)
}
@ -421,7 +421,7 @@ func startQuorumPermissionService(ctx *cli.Context, stack *node.Node) {
}
qapi := v.(*quorum.QuorumControlsAPI)
err = qapi.Init(stateReader, stack.GetNodeKey(), apiName, &permissionConfig)
err = qapi.Init(stateReader, stack.GetNodeKey(), apiName, &permissionConfig, pc.Interface())
if err != nil {
log.Info("Failed to starts API", "apiName", apiName)
} else {

File diff suppressed because one or more lines are too long

View File

@ -149,20 +149,20 @@ contract PermissionsImplementation {
}
}
function updateOrgStatus(string calldata _orgId, uint _status) external
function updateOrgStatus(string calldata _orgId, uint _status, address _caller) external
onlyProxy
orgExists(_orgId)
networkAdmin(msg.sender)
networkAdmin(_caller)
{
uint pendingOp;
pendingOp = org.updateOrg(_orgId, _status);
voter.addVotingItem(adminOrg, _orgId, "", address(0), pendingOp);
}
function approveOrgStatus(string calldata _orgId, uint _status) external
function approveOrgStatus(string calldata _orgId, uint _status, address _caller) external
onlyProxy
orgExists(_orgId)
networkAdmin(msg.sender)
networkAdmin(_caller)
{
require ((_status == 3 || _status == 5), "Operation not allowed");
uint pendingOp;

View File

@ -77,12 +77,12 @@ contract PermissionsInterface {
function updateOrgStatus(string calldata _orgId, uint _status) external
{
permImplementation.updateOrgStatus(_orgId, _status);
permImplementation.updateOrgStatus(_orgId, _status, msg.sender);
}
function approveOrgStatus(string calldata _orgId, uint _status) external
{
permImplementation.approveOrgStatus(_orgId, _status);
permImplementation.approveOrgStatus(_orgId, _status, msg.sender);
}
// returns org and master org details based on org index
function getOrgInfo(uint _orgIndex) external view returns (string memory, uint)

View File

@ -66,6 +66,10 @@ type PermissionCtrl struct {
permConfig *types.PermissionConfig
}
func (p *PermissionCtrl) Interface() *pbind.PermInterface {
return p.permInterf
}
// This function takes the local config data where all the information is in string
// converts that to address and populates the global permissions config
func populateConfig(config PermissionLocalConfig) types.PermissionConfig {

View File

@ -3,11 +3,6 @@ package quorum
import (
"crypto/ecdsa"
"errors"
"fmt"
"github.com/ethereum/go-ethereum/p2p/enode"
"math/big"
"strings"
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
@ -19,6 +14,7 @@ import (
"github.com/ethereum/go-ethereum/internal/ethapi"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"
"math/big"
)
//default gas limit to use if not passed in sendTxArgs
@ -31,18 +27,17 @@ var defaultGasPrice = big.NewInt(0)
type PermAction int
const (
ProposeNode PermAction = iota
ApproveNode
ProposeNodeDeactivation
ApproveNodeDeactivation
ProposeNodeActivation
ApproveNodeActivation
ProposeNodeBlacklisting
ApproveNodeBlacklisting
AddVoter
RemoveVoter
SetAccountAccess
CancelPendingOperation
AddOrg PermAction = iota
ApproveOrg
UpdateOrgStatus
ApproveOrgStatus
AddNode
UpdateNodeStatus
AssignOrgAdminAccount
ApproveOrgAdminAccount
AddNewRole
RemoveRole
AssignAccountRole
)
// OrgKeyAction represents an action in cluster contract
@ -63,9 +58,6 @@ type NodeCheckRetVal int
const (
Success NodeCheckRetVal = iota
DetailsMismatch
NothingToApprove
NothingToCancel
)
// Voter access type
@ -76,6 +68,10 @@ const (
Inactive
)
type PermissionContracts struct {
PermInterf *pbind.PermInterface
}
// QuorumControlsAPI provides an API to access Quorum's node permission and org key management related services
type QuorumControlsAPI struct {
txPool *core.TxPool
@ -88,18 +84,22 @@ type QuorumControlsAPI struct {
permEnabled bool
orgEnabled bool
permConfig *types.PermissionConfig
permInterf *pbind.PermInterface
}
// txArgs holds arguments required for execute functions
type txArgs struct {
voter common.Address
nodeId string
orgId string
url string
roleId string
isVoter bool
acctId common.Address
accessType uint8
status uint8
voter common.Address
morgId string
tmKey string
txa ethapi.SendTxArgs
acctId common.Address
accessType uint8
}
type nodeStatus struct {
@ -187,7 +187,7 @@ var (
// NewQuorumControlsAPI creates a new QuorumControlsAPI to access quorum services
func NewQuorumControlsAPI(tp *core.TxPool, am *accounts.Manager) *QuorumControlsAPI {
return &QuorumControlsAPI{tp, nil, am, nil, nil, nil, nil, false, false, nil}
return &QuorumControlsAPI{tp, nil, am, nil, nil, nil, nil, false, false, nil, nil}
}
// helper function decodes the node status to string
@ -207,9 +207,9 @@ func decodePendingOp(pendingOp uint8) string {
}
//Init initializes QuorumControlsAPI with eth client, permission contract and org key management control
func (p *QuorumControlsAPI) Init(ethClnt *ethclient.Client, key *ecdsa.PrivateKey, apiName string, pconfig *types.PermissionConfig) error {
func (p *QuorumControlsAPI) Init(ethClnt *ethclient.Client, key *ecdsa.PrivateKey, apiName string, pconfig *types.PermissionConfig, pc *pbind.PermInterface) error {
p.ethClnt = ethClnt
if apiName == "quorumNodeMgmt" || apiName == "quorumAcctMgmt" {
if apiName == "quorumPermission" {
var contractAddress common.Address
//TODO: to be updated with new contract API
//if pconfig.IsEmpty() {
@ -233,43 +233,10 @@ func (p *QuorumControlsAPI) Init(ethClnt *ethclient.Client, key *ecdsa.PrivateKe
p.orgEnabled = true
}
p.key = key
p.permInterf = pc
return nil
}
// Returns the list of Nodes and status of each
func (s *QuorumControlsAPI) PermissionNodeList() []nodeStatus {
if !s.permEnabled {
nodeStatArr := make([]nodeStatus, 1)
nodeStatArr[0].EnodeId = "Permisssions control not enabled for network"
return nodeStatArr
}
ps := s.newPermSessionWithNodeKeySigner()
// get the total number of nodes on the contract
nodeCnt, err := ps.GetNumberOfNodes()
if err != nil {
return nil
}
nodeCntI := nodeCnt.Int64()
nodeStatArr := make([]nodeStatus, nodeCntI)
// loop for each index and get the node details from the contract
i := int64(0)
for i < nodeCntI {
nodeDtls, err := ps.GetNodeDetailsFromIndex(big.NewInt(i))
if err != nil {
log.Error("error getting node details", "err", err)
} else {
nodeStatArr[i].EnodeId = "enode://" + nodeDtls.EnodeId + "@" + nodeDtls.IpAddrPort
nodeStatArr[i].EnodeId += "?discport=" + nodeDtls.DiscPort
if len(nodeDtls.RaftPort) > 0 {
nodeStatArr[i].EnodeId += "&raftport=" + nodeDtls.RaftPort
}
nodeStatArr[i].Status = decodeNodeStatus(nodeDtls.NodeStatus)
}
i++
}
return nodeStatArr
}
func (s *QuorumControlsAPI) OrgList() []types.OrgInfo {
return types.OrgInfoMap.GetOrgList()
}
@ -286,86 +253,6 @@ func (s *QuorumControlsAPI) AcctList() []types.AccountInfo {
return types.AcctInfoMap.GetAcctList()
}
// Returns the list of permissioned accounts and access type of each
func (s *QuorumControlsAPI) PermissionAccountList() []accountInfo {
if !s.permEnabled {
acctInfoArr := make([]accountInfo, 1)
acctInfoArr[0].Address = "Account access control not enable for the network"
return acctInfoArr
}
ps := s.newPermSessionWithNodeKeySigner()
// get the total number of accounts with permissions
acctCnt, err := ps.GetNumberOfAccounts()
if err != nil {
return nil
}
acctCntI := acctCnt.Int64()
log.Debug("total permission accounts", "count", acctCntI)
acctInfoArr := make([]accountInfo, acctCntI)
// loop for each index and get the node details from the contract
i := int64(0)
for i < acctCntI {
a, err := ps.GetAccountDetails(big.NewInt(i))
if err != nil {
log.Error("error getting account info", "err", err)
} else {
acctInfoArr[i].Address = a.Acct.String()
acctInfoArr[i].Access = decodeAccountPermission(a.AcctAccess)
}
i++
}
return acctInfoArr
}
// Returns the list of voters for node management
func (s *QuorumControlsAPI) VoterList() []string {
if !s.permEnabled {
voterArr := make([]string, 1)
voterArr[0] = "Permissions control not enabled for the network"
return voterArr
}
ps := s.newPermSessionWithNodeKeySigner()
// get the total number of accounts with permissions
voterCnt, err := ps.GetNumberOfVoters()
if err != nil {
return nil
}
voterCntI := voterCnt.Int64()
log.Debug("total voters", "count", voterCntI)
var voterArr []string
// loop for each index and get the node details from the contract
i := int64(0)
for i < voterCntI {
voter, err := ps.GetVoter(big.NewInt(i))
if err != nil {
log.Error("error getting voter info", "err", err)
} else {
if voter.VoterStatus == uint8(Active) {
voterArr = append(voterArr, voter.Addr.String())
}
}
i++
}
return voterArr
}
func (s *QuorumControlsAPI) newPermSessionWithNodeKeySigner() *pbind.PermissionsSession {
auth := bind.NewKeyedTransactor(s.key)
ps := &pbind.PermissionsSession{
Contract: s.permContr,
CallOpts: bind.CallOpts{
Pending: true,
},
TransactOpts: bind.TransactOpts{
From: auth.From,
Signer: auth.Signer,
GasLimit: 4700000,
GasPrice: big.NewInt(0),
},
}
return ps
}
func (s *QuorumControlsAPI) newOrgKeySessionWithNodeKeySigner() *obind.ClusterSession {
auth := bind.NewKeyedTransactor(s.key)
cs := &obind.ClusterSession{
@ -382,66 +269,50 @@ func (s *QuorumControlsAPI) newOrgKeySessionWithNodeKeySigner() *obind.ClusterSe
}
return cs
}
func decodeAccountPermission(access uint8) string {
if status, ok := accountPermMap[access]; ok {
return status
}
return "Unknown"
func (s *QuorumControlsAPI) AddOrg(orgId string, url string, txa ethapi.SendTxArgs) ExecStatus {
return s.executePermAction(AddOrg, txArgs{orgId: orgId, url: url, txa: txa})
}
// AddVoter adds an account to the list of accounts that can approve nodes proposed or deactivated
func (s *QuorumControlsAPI) AddVoter(vaddr common.Address, txa ethapi.SendTxArgs) ExecStatus {
return s.executePermAction(AddVoter, txArgs{voter: vaddr, txa: txa})
func (s *QuorumControlsAPI) ApproveOrg(orgId string, url string, txa ethapi.SendTxArgs) ExecStatus {
return s.executePermAction(ApproveOrg, txArgs{orgId: orgId, url: url, txa: txa})
}
// RemoveVoter removes an account from the list of accounts that can approve nodes proposed or deactivated
func (s *QuorumControlsAPI) RemoveVoter(vaddr common.Address, txa ethapi.SendTxArgs) ExecStatus {
return s.executePermAction(RemoveVoter, txArgs{voter: vaddr, txa: txa})
func (s *QuorumControlsAPI) UpdateOrgStatus(orgId string, status uint8, txa ethapi.SendTxArgs) ExecStatus {
log.Info("AJ-update org status", "org", orgId, "status", status)
return s.executePermAction(UpdateOrgStatus, txArgs{orgId: orgId, status: status, txa: txa})
}
// ProposeNode proposes a node to join the network
func (s *QuorumControlsAPI) ProposeNode(nodeId string, txa ethapi.SendTxArgs) ExecStatus {
return s.executePermAction(ProposeNode, txArgs{nodeId: nodeId, txa: txa})
func (s *QuorumControlsAPI) AddNode(orgId string, url string, txa ethapi.SendTxArgs) ExecStatus {
return s.executePermAction(AddNode, txArgs{orgId: orgId, url: url, txa: txa})
}
// ApproveNode approves a proposed node to join the network
func (s *QuorumControlsAPI) ApproveNode(nodeId string, txa ethapi.SendTxArgs) ExecStatus {
return s.executePermAction(ApproveNode, txArgs{nodeId: nodeId, txa: txa})
func (s *QuorumControlsAPI) UpdateNodeStatus(orgId string, url string, status uint8, txa ethapi.SendTxArgs) ExecStatus {
return s.executePermAction(UpdateNodeStatus, txArgs{orgId: orgId, url: url, status: status, txa: txa})
}
// DeactivateNode requests a node to get deactivated
func (s *QuorumControlsAPI) ProposeNodeDeactivation(nodeId string, txa ethapi.SendTxArgs) ExecStatus {
return s.executePermAction(ProposeNodeDeactivation, txArgs{nodeId: nodeId, txa: txa})
func (s *QuorumControlsAPI) ApproveOrgStatus(orgId string, status uint8, txa ethapi.SendTxArgs) ExecStatus {
return s.executePermAction(ApproveOrgStatus, txArgs{orgId: orgId, status: status, txa: txa})
}
// ApproveDeactivateNode approves a node to get deactivated
func (s *QuorumControlsAPI) ApproveNodeDeactivation(nodeId string, txa ethapi.SendTxArgs) ExecStatus {
return s.executePermAction(ApproveNodeDeactivation, txArgs{nodeId: nodeId, txa: txa})
func (s *QuorumControlsAPI) AssignOrgAdminAccount(orgId string, acct common.Address, txa ethapi.SendTxArgs) ExecStatus {
return s.executePermAction(AssignOrgAdminAccount, txArgs{orgId: orgId, acctId: acct, txa: txa})
}
// ActivateNode requests a deactivated node to get activated
func (s *QuorumControlsAPI) ProposeNodeActivation(nodeId string, txa ethapi.SendTxArgs) ExecStatus {
return s.executePermAction(ProposeNodeActivation, txArgs{nodeId: nodeId, txa: txa})
func (s *QuorumControlsAPI) ApproveOrgAdminAccount(acct common.Address, txa ethapi.SendTxArgs) ExecStatus {
return s.executePermAction(ApproveOrgAdminAccount, txArgs{acctId: acct, txa: txa})
}
// ApproveNodeActivation approves a node to get activated back
func (s *QuorumControlsAPI) ApproveNodeActivation(nodeId string, txa ethapi.SendTxArgs) ExecStatus {
return s.executePermAction(ApproveNodeActivation, txArgs{nodeId: nodeId, txa: txa})
func (s *QuorumControlsAPI) AddNewRole(roleId string, orgId string, access uint8, isVoter bool, txa ethapi.SendTxArgs) ExecStatus {
return s.executePermAction(AddNewRole, txArgs{orgId: orgId, roleId: roleId, accessType: access, isVoter: isVoter, txa: txa})
}
// Request a node to be blacklisted
func (s *QuorumControlsAPI) ProposeNodeBlacklisting(nodeId string, txa ethapi.SendTxArgs) ExecStatus {
return s.executePermAction(ProposeNodeBlacklisting, txArgs{nodeId: nodeId, txa: txa})
func (s *QuorumControlsAPI) RemoveRole(roleId string, orgId string, txa ethapi.SendTxArgs) ExecStatus {
return s.executePermAction(RemoveRole, txArgs{orgId: orgId, roleId: roleId, txa: txa})
}
// Approves blacklisting of a node proposed for blacklisting
func (s *QuorumControlsAPI) ApproveNodeBlacklisting(nodeId string, txa ethapi.SendTxArgs) ExecStatus {
return s.executePermAction(ApproveNodeBlacklisting, txArgs{nodeId: nodeId, txa: txa})
}
// CancelPendingOperation cancels a pending operation
func (s *QuorumControlsAPI) CancelPendingOperation(nodeId string, txa ethapi.SendTxArgs) ExecStatus {
return s.executePermAction(CancelPendingOperation, txArgs{nodeId: nodeId, txa: txa})
func (s *QuorumControlsAPI) AssignAccountRole(acct common.Address, roleId string, orgId string, txa ethapi.SendTxArgs) ExecStatus {
return s.executePermAction(AssignAccountRole, txArgs{orgId: orgId, roleId: roleId, acctId: acct, txa: txa})
}
// AddMasterOrg adds an new master organization to the contract
@ -479,129 +350,13 @@ func (s *QuorumControlsAPI) ApprovePendingOp(orgId string, txa ethapi.SendTxArgs
return s.executeOrgKeyAction(ApprovePendingOp, txArgs{txa: txa, orgId: orgId})
}
// SetAccountAccess sets the account access to the given type
func (s *QuorumControlsAPI) SetAccountAccess(acct common.Address, access uint8, txa ethapi.SendTxArgs) ExecStatus {
return s.executePermAction(SetAccountAccess, txArgs{acctId: acct, accessType: access, txa: txa})
}
// returns node details given the enode id
func getNodeDetailsFromEnode(nodeId string) (string, string, string, string, error) {
node, err := enode.ParseV4(nodeId)
if err != nil {
log.Error("invalid node id: %v", err)
return "", "", "", "", err
}
enodeID := node.EnodeID()
ipAddr := node.IP().String()
port := fmt.Sprintf("%v", node.TCP)
discPort := fmt.Sprintf("%v", node.UDP)
raftPort := fmt.Sprintf("%v", node.RaftPort)
ipAddrPort := ipAddr + ":" + port
return enodeID, discPort, raftPort, ipAddrPort, nil
}
// checks if the input node details for approval is matching with details stored in contract
func checkNodeDetails(ps *pbind.PermissionsSession, nodeId string, action PermAction) (error, ExecStatus) {
enodeID, discPort, raftPort, ipAddrPort, err := getNodeDetailsFromEnode(nodeId)
cnode, err := ps.GetNodeDetails(enodeID)
log.Info("SMK-checkNodeDetails @481", "err", err, "nodeStatus", cnode.NodeStatus)
if err == nil {
log.Info("SMK-checkNodeDetails @483")
nodeStatus := decodeNodeStatus(cnode.NodeStatus)
// if node status is Blacklisted no activities are allowed on the same.
if nodeStatus == "Blacklisted" {
return errors.New("Cannot propose blacklisted node"), ErrBlacklistedNode
}
if nodeStatus == "NotInNetwork" && action != ProposeNode && action != ProposeNodeBlacklisting {
return errors.New("operation cannot be performed"), ErrOpNotAllowed
}
newNode := false
if nodeStatus == "NotInNetwork" && len(cnode.IpAddrPort) == 0 {
newNode = true
}
detailsMatch := false
if strings.Compare(ipAddrPort, cnode.IpAddrPort) == 0 && strings.Compare(discPort, cnode.DiscPort) == 0 && strings.Compare(raftPort, cnode.RaftPort) == 0 {
detailsMatch = true
}
// if the node is not in network and is being proposed for blacklisting or as a new node
// allow the operation. For anyother operation, the node will be in the network and all details
// should match
if action == ProposeNode || action == ProposeNodeBlacklisting {
if !newNode && !detailsMatch {
return errors.New("Details Mismtach"), ErrNodeDetailsMismatch
}
} else if !detailsMatch {
return errors.New("Details Mismtach"), ErrNodeDetailsMismatch
}
// if propose action, check if node status allows the operation
if (action == ProposeNode && nodeStatus != "NotInNetwork") ||
(action == ProposeNodeDeactivation && nodeStatus != "Approved") ||
(action == ProposeNodeActivation && nodeStatus != "Deactivated") {
return errors.New("operation cannot be performed"), ErrOpNotAllowed
}
// if approval action, check if anything pendinga approval
if (action == ApproveNode && nodeStatus != "PendingApproval") ||
(action == ApproveNodeDeactivation && nodeStatus != "PendingDeactivation") ||
(action == ApproveNodeActivation && nodeStatus != "PendingActivation") ||
(action == ApproveNodeBlacklisting && nodeStatus != "PendingBlacklisting") {
return errors.New("Nothing to approve"), ErrNothingToApprove
}
if action == CancelPendingOperation && nodeStatus != "PendingApproval" &&
nodeStatus != "PendingDeactivation" && nodeStatus != "PendingActivation" &&
nodeStatus != "PendingBlacklisting" {
return errors.New("Nothing to cancel"), ErrNothingToCancel
}
if (action == ProposeNode && nodeStatus == "PendingApproval") ||
(action == ProposeNodeDeactivation && nodeStatus == "PendingDeactivation") ||
(action == ProposeNodeActivation && nodeStatus == "PendingActivation") ||
(action == ProposeNodeBlacklisting && nodeStatus == "PendingBlacklisting") {
return errors.New("Node already proposed"), ErrNodeProposed
}
}
return nil, ExecSuccess
}
// performs all necessary validation before the request can be processed
func (s *QuorumControlsAPI) validateOpDetails(ps *pbind.PermissionsSession, enodeID string, from common.Address, action PermAction) (error, ExecStatus) {
// check if the input node is fine
err, execStatus := checkNodeDetails(ps, enodeID, action)
if err != nil {
return errors.New("Node details mismatch"), execStatus
}
// if action is propose type then check if voter nodes are there in the network
if action == ProposeNode || action == ProposeNodeDeactivation || action == ProposeNodeActivation || action == ProposeNodeBlacklisting {
if !checkVoterExists(ps) {
return errors.New("No voter account"), ErrNoVoterAccount
}
}
// if approval process, check if the account is a voter account
if action == ApproveNode || action == ApproveNodeDeactivation || action == ApproveNodeActivation || action == ApproveNodeBlacklisting || action == CancelPendingOperation {
if !checkIsVoter(ps, from) {
return errors.New("Not a voter account"), ErrAccountNotAVoter
}
}
return nil, ExecSuccess
}
// executePermAction helps to execute an action in permission contract
func (s *QuorumControlsAPI) executePermAction(action PermAction, args txArgs) ExecStatus {
if !s.permEnabled {
return ErrPermissionDisabled
}
log.Info("AJ-exec perm action", "action", action, "txargs", args)
var err error
var w accounts.Wallet
@ -609,133 +364,44 @@ func (s *QuorumControlsAPI) executePermAction(action PermAction, args txArgs) Ex
if err != nil {
return ErrInvalidAccount
}
ps := s.newPermSession(w, args.txa)
var tx *types.Transaction
var node *enode.Node
var execStatus ExecStatus
if action != SetAccountAccess && action != AddVoter && action != RemoveVoter {
err, execStatus = s.validateOpDetails(ps, args.nodeId, args.txa.From, action)
if err != nil {
return execStatus
}
}
pinterf := s.newPermInterfaceSession(w, args.txa)
var tx *types.Transaction
switch action {
case AddVoter:
if locErr, execStatus := valAccountAccessVoter(args.txa.From, args.voter); locErr != nil {
return execStatus
}
if checkIsVoter(ps, args.voter) {
return ErrVoterExists
}
tx, err = ps.AddVoter(args.voter)
case RemoveVoter:
if locErr, execStatus := valAccountAccessVoter(args.txa.From, common.Address{}); locErr != nil {
return execStatus
}
if !checkIsVoter(ps, args.voter) {
return ErrAccountIsNotVoter
}
tx, err = ps.RemoveVoter(args.voter)
case AddOrg:
tx, err = pinterf.AddOrg(args.orgId, args.url)
case ProposeNode:
enodeID, discPort, raftPort, ipAddrPort, locerr := getNodeDetailsFromEnode(args.nodeId)
if locerr != nil {
log.Error("invalid node id: %v", err)
return ErrInvalidNode
}
case ApproveOrg:
tx, err = pinterf.ApproveOrg(args.orgId, args.url)
tx, err = ps.ProposeNode(enodeID, ipAddrPort, discPort, raftPort)
case UpdateOrgStatus:
tx, err = pinterf.UpdateOrgStatus(args.orgId, big.NewInt(int64(args.status)))
case ApproveNode:
node, err = enode.ParseV4(args.nodeId)
if err != nil {
log.Error("invalid node id: %v", err)
return ErrInvalidNode
}
enodeID := node.EnodeID()
case ApproveOrgStatus:
tx, err = pinterf.ApproveOrgStatus(args.orgId, big.NewInt(int64(args.status)))
tx, err = ps.ApproveNode(enodeID)
case AddNode:
tx, err = pinterf.AddNode(args.orgId, args.url)
case ProposeNodeDeactivation:
node, err = enode.ParseV4(args.nodeId)
if err != nil {
log.Error("invalid node id: %v", err)
return ErrInvalidNode
}
enodeID := node.EnodeID()
tx, err = ps.ProposeDeactivation(enodeID)
case UpdateNodeStatus:
tx, err = pinterf.UpdateNodeStatus(args.orgId, args.url, big.NewInt(int64(args.status)))
case ApproveNodeDeactivation:
node, err = enode.ParseV4(args.nodeId)
if err != nil {
log.Error("invalid node id: %v", err)
return ErrInvalidNode
}
enodeID := node.EnodeID()
case AssignOrgAdminAccount:
tx, err = pinterf.AssignOrgAdminAccount(args.orgId, args.acctId)
tx, err = ps.DeactivateNode(enodeID)
case ApproveOrgAdminAccount:
tx, err = pinterf.ApproveOrgAdminAccount(args.acctId)
case ProposeNodeActivation:
node, err = enode.ParseV4(args.nodeId)
if err != nil {
log.Error("invalid node id: %v", err)
return ErrInvalidNode
}
enodeID := node.EnodeID()
tx, err = ps.ProposeNodeActivation(enodeID)
case AddNewRole:
tx, err = pinterf.AddNewRole(args.roleId, args.orgId, big.NewInt(int64(args.accessType)), args.isVoter)
case ApproveNodeActivation:
node, err = enode.ParseV4(args.nodeId)
if err != nil {
log.Error("invalid node id: %v", err)
return ErrInvalidNode
}
enodeID := node.EnodeID()
tx, err = ps.ActivateNode(enodeID)
case ProposeNodeBlacklisting:
enodeID, discPort, raftPort, ipAddrPort, locerr := getNodeDetailsFromEnode(args.nodeId)
if locerr != nil {
log.Error("invalid node id: %v", err)
return ErrInvalidNode
}
tx, err = ps.ProposeNodeBlacklisting(enodeID, ipAddrPort, discPort, raftPort)
case ApproveNodeBlacklisting:
node, err = enode.ParseV4(args.nodeId)
if err != nil {
log.Error("invalid node id: %v", err)
return ErrInvalidNode
}
enodeID := node.EnodeID()
tx, err = ps.BlacklistNode(enodeID)
case SetAccountAccess:
if args.accessType > 3 {
return ErrInvalidAccountAccess
}
if locErr, execStatus := validateAccoutOp(ps, args.txa.From, args.acctId, args.accessType); locErr != nil {
return execStatus
}
tx, err = ps.UpdateAccountAccess(args.acctId, args.accessType)
case CancelPendingOperation:
if !checkIsVoter(ps, args.txa.From) {
return ErrAccountNotAVoter
}
node, err = enode.ParseV4(args.nodeId)
if err != nil {
log.Error("invalid node id: %v", err)
return ErrInvalidNode
}
enodeID := node.EnodeID()
tx, err = ps.CancelPendingOperation(enodeID)
case RemoveRole:
tx, err = pinterf.RemoveRole(args.roleId, args.orgId)
case AssignAccountRole:
tx, err = pinterf.AssignAccountRole(args.acctId, args.orgId, args.roleId)
}
if err != nil {
@ -746,34 +412,6 @@ func (s *QuorumControlsAPI) executePermAction(action PermAction, args txArgs) Ex
return ExecSuccess
}
// returns the voter list for a given organization
func (s *QuorumControlsAPI) GetOrgVoterList(morgId string) []string {
if !s.orgEnabled {
voterArr := make([]string, 1)
voterArr[0] = "Org management control not enabled for the network"
return voterArr
}
ps := s.newOrgKeySessionWithNodeKeySigner()
// get the total number of accounts with permissions
voterCnt, err := ps.GetNumberOfVoters(morgId)
if err != nil {
return nil
}
voterCntI := voterCnt.Int64()
log.Debug("total voters", "count", voterCntI)
var voterArr []string
// loop for each index and get the node details from the contract
i := int64(0)
for i < voterCntI {
voter, err := ps.GetVoter(morgId, big.NewInt(i))
if err == nil && voter.Active {
voterArr = append(voterArr, voter.Addr.String())
}
i++
}
return voterArr
}
// returns the master org, org and linked key details
func (s *QuorumControlsAPI) OrgKeyInfo() []orgInfo {
if !s.orgEnabled {
@ -823,27 +461,6 @@ func (s *QuorumControlsAPI) OrgKeyInfo() []orgInfo {
return orgArr
}
// this function returns the approval pending action at sub org level
func (s *QuorumControlsAPI) GetPendingOpDetails(orgId string) PendingOpInfo {
if !s.orgEnabled {
return PendingOpInfo{"Org key management not enabled for the network", "None"}
}
ps := s.newOrgKeySessionWithNodeKeySigner()
ret, _ := ps.CheckOrgExists(orgId)
if ret {
// get the total number of accounts with permissions
pendingKey, pendingOp, err := ps.GetOrgPendingOp(orgId)
if err == nil {
pendOpInfo := PendingOpInfo{pendingKey, decodePendingOp(pendingOp)}
return pendOpInfo
} else {
return PendingOpInfo{"Info not found", "None"}
}
} else {
return PendingOpInfo{"Org not found", "None"}
}
}
// executeOrgKeyAction helps to execute an action in cluster contract
func (s *QuorumControlsAPI) executeOrgKeyAction(action OrgKeyAction, args txArgs) ExecStatus {
if !s.orgEnabled {
@ -981,25 +598,10 @@ func (s *QuorumControlsAPI) validateAccount(from common.Address) (accounts.Walle
return w, nil
}
// checkVoterExists checks if any vote accounts are there. If yes returns true, else false
func checkVoterExists(ps *pbind.PermissionsSession) bool {
tx, err := ps.GetNumberOfValidVoters()
log.Debug("number of voters", "count", tx)
return (err == nil && tx.Cmp(big.NewInt(0)) > 0)
}
// checks if any accounts is a valid voter to approve the action
func checkIsVoter(ps *pbind.PermissionsSession, acctId common.Address) bool {
tx, err := ps.IsVoter(acctId)
return (err == nil && tx)
}
// newPermSession creates a new permission contract session
func (s *QuorumControlsAPI) newPermSession(w accounts.Wallet, txa ethapi.SendTxArgs) *pbind.PermissionsSession {
func (s *QuorumControlsAPI) newPermInterfaceSession(w accounts.Wallet, txa ethapi.SendTxArgs) *pbind.PermInterfaceSession {
frmAcct, transactOpts, gasLimit, gasPrice, nonce := s.getTxParams(txa, w)
ps := &pbind.PermissionsSession{
Contract: s.permContr,
ps := &pbind.PermInterfaceSession{
Contract: s.permInterf,
CallOpts: bind.CallOpts{
Pending: true,
},
@ -1054,43 +656,6 @@ func (s *QuorumControlsAPI) getTxParams(txa ethapi.SendTxArgs, w accounts.Wallet
return frmAcct, transactOpts, gasLimit, gasPrice, nonce
}
// checks if the account performing the operation has sufficient access privileges
// and if at least on full access account will be left after the operation
func validateAccoutOp(ps *pbind.PermissionsSession, from, targetAcct common.Address, accessType uint8) (error, ExecStatus) {
fromAcctAccess := types.GetAcctAccess(from)
targetAcctAccess := types.GetAcctAccess(targetAcct)
retVal := false
// Check if the from account is sufficient access rights to set the access
if fromAcctAccess == types.FullAccess {
retVal = true
} else if fromAcctAccess == types.ContractDeploy && accessType != uint8(types.FullAccess) {
retVal = true
} else if fromAcctAccess == types.Transact && (accessType == uint8(types.Transact) || accessType == uint8(types.ReadOnly)) {
retVal = true
}
if retVal && fromAcctAccess != types.FullAccess {
if (fromAcctAccess == types.ContractDeploy && targetAcctAccess == types.FullAccess) ||
(fromAcctAccess == types.Transact &&
(targetAcctAccess == types.ContractDeploy || targetAcctAccess == types.FullAccess)) {
retVal = false
}
}
if !retVal {
return errors.New("Account does not have sufficient access"), ErrAccountAccess
}
if targetAcctAccess == types.FullAccess && accessType != uint8(types.FullAccess) {
numFullAccessAcct, err := ps.GetFullAccessAccountCount()
if err == nil && numFullAccessAcct.Cmp(big.NewInt(1)) == 0 {
return errors.New("Last account with full access. Operation not allowed"), ErrLastFullAccessAcct
}
}
return nil, ExecSuccess
}
// checks if the account performing the operation has sufficient access privileges
func valAccountAccessVoter(fromAcct, targetAcct common.Address) (error, ExecStatus) {
acctAccess := types.GetAcctAccess(fromAcct)

View File

@ -338,13 +338,7 @@ func (s *Ethereum) APIs() []rpc.API {
Public: true,
},
{
Namespace: "quorumNodeMgmt",
Version: "1.0",
Service: quorum.NewQuorumControlsAPI(s.txPool, s.accountManager),
Public: true,
},
{
Namespace: "quorumAcctMgmt",
Namespace: "quorumPermission",
Version: "1.0",
Service: quorum.NewQuorumControlsAPI(s.txPool, s.accountManager),
Public: true,

View File

@ -18,24 +18,23 @@
package web3ext
var Modules = map[string]string{
"admin": Admin_JS,
"chequebook": Chequebook_JS,
"clique": Clique_JS,
"ethash": Ethash_JS,
"debug": Debug_JS,
"eth": Eth_JS,
"miner": Miner_JS,
"net": Net_JS,
"personal": Personal_JS,
"rpc": RPC_JS,
"shh": Shh_JS,
"swarmfs": SWARMFS_JS,
"txpool": TxPool_JS,
"raft": Raft_JS,
"istanbul": Istanbul_JS,
"quorumNodeMgmt": QUORUM_NODE_JS,
"quorumAcctMgmt": QUORUM_ACCT_JS,
"quorumOrgMgmt": QUORUM_ORG_JS,
"admin": Admin_JS,
"chequebook": Chequebook_JS,
"clique": Clique_JS,
"ethash": Ethash_JS,
"debug": Debug_JS,
"eth": Eth_JS,
"miner": Miner_JS,
"net": Net_JS,
"personal": Personal_JS,
"rpc": RPC_JS,
"shh": Shh_JS,
"swarmfs": SWARMFS_JS,
"txpool": TxPool_JS,
"raft": Raft_JS,
"istanbul": Istanbul_JS,
"quorumPermission": QUORUM_NODE_JS,
"quorumOrgMgmt": QUORUM_ORG_JS,
}
const Chequebook_JS = `
@ -713,13 +712,6 @@ web3._extend({
const Raft_JS = `
web3._extend({
property: 'raft',
methods:
[
new web3._extend.Method({
name: 'add1',
call: 'raft_add1'
}),
],
properties:
[
new web3._extend.Property({
@ -743,10 +735,6 @@ web3._extend({
new web3._extend.Property({
name: 'cluster',
getter: 'raft_cluster'
}),
new web3._extend.Property({
name: 'add2',
getter: 'raft_add2'
}),
]
})
@ -754,128 +742,98 @@ web3._extend({
const QUORUM_NODE_JS = `
web3._extend({
property: 'quorumNodeMgmt',
property: 'quorumPermission',
methods:
[
new web3._extend.Method({
name: 'addOrg',
call: 'quorumPermission_addOrg',
params: 3,
inputFormatter: [null,null,web3._extend.formatters.inputTransactionFormatter]
}),
new web3._extend.Method({
name: 'approveOrg',
call: 'quorumPermission_approveOrg',
params: 3,
inputFormatter: [null,null,web3._extend.formatters.inputTransactionFormatter]
}),
new web3._extend.Method({
name: 'addVoter',
call: 'quorumNodeMgmt_addVoter',
name: 'updateOrgStatus',
call: 'quorumPermission_updateOrgStatus',
params: 3,
inputFormatter: [null,null,web3._extend.formatters.inputTransactionFormatter]
}),
new web3._extend.Method({
name: 'approveOrgStatus',
call: 'quorumPermission_approveOrgStatus',
params: 3,
inputFormatter: [null,null,web3._extend.formatters.inputTransactionFormatter]
}),
new web3._extend.Method({
name: 'addNode',
call: 'quorumPermission_addNode',
params: 3,
inputFormatter: [null,null,web3._extend.formatters.inputTransactionFormatter]
}),
new web3._extend.Method({
name: 'updateNodeStatus',
call: 'quorumPermission_updateNodeStatus',
params: 4,
inputFormatter: [null,null,null,web3._extend.formatters.inputTransactionFormatter]
}),
new web3._extend.Method({
name: 'assignOrgAdminAccount',
call: 'quorumPermission_assignOrgAdminAccount',
params: 3,
inputFormatter: [null,web3._extend.formatters.inputAddressFormatter,web3._extend.formatters.inputTransactionFormatter]
}),
new web3._extend.Method({
name: 'approveOrgAdminAccount',
call: 'quorumPermission_approveOrgAdminAccount',
params: 2,
inputFormatter: [web3._extend.formatters.inputAddressFormatter,web3._extend.formatters.inputTransactionFormatter]
}),
new web3._extend.Method({
name: 'removeVoter',
call: 'quorumNodeMgmt_removeVoter',
params: 2,
inputFormatter: [web3._extend.formatters.inputAddressFormatter,web3._extend.formatters.inputTransactionFormatter]
name: 'addNewRole',
call: 'quorumPermission_addNewRole',
params: 5,
inputFormatter: [null,null,null,null,web3._extend.formatters.inputTransactionFormatter]
}),
new web3._extend.Method({
name: 'proposeNode',
call: 'quorumNodeMgmt_proposeNode',
params: 2,
inputFormatter: [null,web3._extend.formatters.inputTransactionFormatter]
name: 'removeRole',
call: 'quorumPermission_removeRole',
params: 3,
inputFormatter: [null,null,web3._extend.formatters.inputTransactionFormatter]
}),
new web3._extend.Method({
name: 'approveNode',
call: 'quorumNodeMgmt_approveNode',
params: 2,
inputFormatter: [null,web3._extend.formatters.inputTransactionFormatter]
}),
new web3._extend.Method({
name: 'proposeNodeDeactivation',
call: 'quorumNodeMgmt_proposeNodeDeactivation',
params: 2,
inputFormatter: [null,web3._extend.formatters.inputTransactionFormatter]
}),
new web3._extend.Method({
name: 'approveNodeDeactivation',
call: 'quorumNodeMgmt_approveNodeDeactivation',
params: 2,
inputFormatter: [null,web3._extend.formatters.inputTransactionFormatter]
}),
new web3._extend.Method({
name: 'proposeNodeActivation',
call: 'quorumNodeMgmt_proposeNodeActivation',
params: 2,
inputFormatter: [null,web3._extend.formatters.inputTransactionFormatter]
}),
new web3._extend.Method({
name: 'approveNodeActivation',
call: 'quorumNodeMgmt_approveNodeActivation',
params: 2,
inputFormatter: [null,web3._extend.formatters.inputTransactionFormatter]
}),
new web3._extend.Method({
name: 'proposeNodeBlacklisting',
call: 'quorumNodeMgmt_proposeNodeBlacklisting',
params: 2,
inputFormatter: [null,web3._extend.formatters.inputTransactionFormatter]
}),
new web3._extend.Method({
name: 'approveNodeBlacklisting',
call: 'quorumNodeMgmt_approveNodeBlacklisting',
params: 2,
inputFormatter: [null,web3._extend.formatters.inputTransactionFormatter]
}),
new web3._extend.Method({
name: 'cancelPendingOperation',
call: 'quorumNodeMgmt_cancelPendingOperation',
params: 2,
inputFormatter: [null,web3._extend.formatters.inputTransactionFormatter]
name: 'assignAccountRole',
call: 'quorumPermission_assignAccountRole',
params: 4,
inputFormatter: [web3._extend.formatters.inputAddressFormatter,null,null,web3._extend.formatters.inputTransactionFormatter]
}),
],
properties:
[
new web3._extend.Property({
name: 'permissionNodeList',
getter: 'quorumNodeMgmt_permissionNodeList'
}),
new web3._extend.Property({
name: 'voterList',
getter: 'quorumNodeMgmt_voterList'
}),
new web3._extend.Property({
name: 'orgList',
getter: 'quorumNodeMgmt_orgList'
getter: 'quorumPermission_orgList'
}),
new web3._extend.Property({
name: 'nodeList',
getter: 'quorumNodeMgmt_nodeList'
getter: 'quorumPermission_nodeList'
}),
new web3._extend.Property({
name: 'roleList',
getter: 'quorumNodeMgmt_roleList'
getter: 'quorumPermission_roleList'
}),
new web3._extend.Property({
name: 'acctList',
getter: 'quorumNodeMgmt_acctList'
getter: 'quorumPermission_acctList'
}),
]
})
`
const QUORUM_ACCT_JS = `
web3._extend({
property: 'quorumAcctMgmt',
methods:
[
new web3._extend.Method({
name: 'setAccountAccess',
call: 'quorumAcctMgmt_setAccountAccess',
params: 3,
inputFormatter: [web3._extend.formatters.inputAddressFormatter,null,web3._extend.formatters.inputTransactionFormatter]
}),
],
properties:
[
new web3._extend.Property({
name: 'permissionAccountList',
getter: 'quorumAcctMgmt_permissionAccountList'
}),
]
})
`
const QUORUM_ORG_JS = `
web3._extend({
property: 'quorumOrgMgmt',