2018-10-29 19:41:01 -07:00
|
|
|
package quorum
|
|
|
|
|
|
|
|
import (
|
2018-11-14 01:58:57 -08:00
|
|
|
"crypto/ecdsa"
|
2018-10-31 05:46:54 -07:00
|
|
|
"fmt"
|
2018-10-31 22:45:16 -07:00
|
|
|
"math/big"
|
2018-11-06 21:58:51 -08:00
|
|
|
"strconv"
|
2018-11-18 19:58:34 -08:00
|
|
|
"strings"
|
2018-10-31 22:45:16 -07:00
|
|
|
|
2018-10-31 05:46:54 -07:00
|
|
|
"github.com/ethereum/go-ethereum/accounts"
|
|
|
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
|
|
|
"github.com/ethereum/go-ethereum/common"
|
|
|
|
pbind "github.com/ethereum/go-ethereum/controls/bind"
|
2018-10-29 19:41:01 -07:00
|
|
|
"github.com/ethereum/go-ethereum/core"
|
2018-10-31 05:46:54 -07:00
|
|
|
"github.com/ethereum/go-ethereum/core/types"
|
2018-10-29 19:41:01 -07:00
|
|
|
"github.com/ethereum/go-ethereum/ethclient"
|
2018-10-31 22:12:11 -07:00
|
|
|
"github.com/ethereum/go-ethereum/internal/ethapi"
|
2018-10-31 05:46:54 -07:00
|
|
|
"github.com/ethereum/go-ethereum/log"
|
2018-10-29 19:41:01 -07:00
|
|
|
"github.com/ethereum/go-ethereum/p2p/discover"
|
2018-10-31 05:46:54 -07:00
|
|
|
"github.com/ethereum/go-ethereum/params"
|
2018-10-30 00:05:41 -07:00
|
|
|
)
|
|
|
|
|
2018-10-31 22:45:16 -07:00
|
|
|
//default gas limit to use if not passed in sendTxArgs
|
2018-10-31 05:46:54 -07:00
|
|
|
var defaultGasLimit = uint64(470000000)
|
2018-10-31 22:45:16 -07:00
|
|
|
|
|
|
|
//default gas price to use if not passed in sendTxArgs
|
2018-10-30 00:05:41 -07:00
|
|
|
var defaultGasPrice = big.NewInt(0)
|
2018-10-29 19:41:01 -07:00
|
|
|
|
2018-10-31 22:45:16 -07:00
|
|
|
// PermAction represents actions in permission contract
|
2018-10-31 05:46:54 -07:00
|
|
|
type PermAction int
|
|
|
|
|
|
|
|
const (
|
|
|
|
ProposeNode PermAction = iota
|
|
|
|
ApproveNode
|
2018-11-05 07:44:23 -08:00
|
|
|
ProposeNodeDeactivation
|
|
|
|
ApproveNodeDeactivation
|
|
|
|
ProposeNodeActivation
|
|
|
|
ApproveNodeActivation
|
|
|
|
ProposeNodeBlacklisting
|
|
|
|
ApproveNodeBlacklisting
|
2018-10-31 05:46:54 -07:00
|
|
|
AddVoter
|
|
|
|
RemoveVoter
|
2018-11-06 21:58:51 -08:00
|
|
|
SetAccountAccess
|
2018-10-31 05:46:54 -07:00
|
|
|
)
|
|
|
|
|
2018-10-31 22:45:16 -07:00
|
|
|
// OrgKeyAction represents an action in cluster contract
|
2018-10-31 05:46:54 -07:00
|
|
|
type OrgKeyAction int
|
|
|
|
|
|
|
|
const (
|
|
|
|
AddOrgKey OrgKeyAction = iota
|
|
|
|
RemoveOrgKey
|
|
|
|
)
|
|
|
|
|
2018-10-31 22:45:16 -07:00
|
|
|
// PermissionAPI provides an API to access Quorum's node permission and org key management related services
|
2018-10-29 19:41:01 -07:00
|
|
|
type PermissionAPI struct {
|
2018-10-31 00:15:34 -07:00
|
|
|
txPool *core.TxPool
|
|
|
|
ethClnt *ethclient.Client
|
2018-10-31 05:46:54 -07:00
|
|
|
acntMgr *accounts.Manager
|
|
|
|
txOpt *bind.TransactOpts
|
2018-10-31 00:15:34 -07:00
|
|
|
permContr *pbind.Permissions
|
2018-10-30 00:59:08 -07:00
|
|
|
clustContr *pbind.Cluster
|
2018-11-14 01:58:57 -08:00
|
|
|
key *ecdsa.PrivateKey
|
2018-11-18 19:58:34 -08:00
|
|
|
enabled bool
|
2018-10-29 19:41:01 -07:00
|
|
|
}
|
|
|
|
|
2018-10-31 22:45:16 -07:00
|
|
|
// txArgs holds arguments required for execute functions
|
2018-10-31 05:46:54 -07:00
|
|
|
type txArgs struct {
|
2018-11-12 00:16:56 -08:00
|
|
|
voter common.Address
|
|
|
|
nodeId string
|
|
|
|
orgId string
|
|
|
|
keyId string
|
|
|
|
txa ethapi.SendTxArgs
|
|
|
|
acctId common.Address
|
2018-11-06 21:58:51 -08:00
|
|
|
accessType string
|
2018-10-31 05:46:54 -07:00
|
|
|
}
|
|
|
|
|
2018-11-12 00:16:56 -08:00
|
|
|
type nodeStatus struct {
|
2018-11-20 05:29:03 -08:00
|
|
|
EnodeId string
|
|
|
|
Status string
|
2018-11-12 00:16:56 -08:00
|
|
|
}
|
|
|
|
|
2018-11-15 20:21:50 -08:00
|
|
|
type accountInfo struct {
|
|
|
|
Address string
|
|
|
|
Access string
|
|
|
|
}
|
|
|
|
|
2018-11-12 00:16:56 -08:00
|
|
|
type ExecStatus struct {
|
|
|
|
Status bool
|
|
|
|
Msg string
|
|
|
|
}
|
2018-11-15 20:21:50 -08:00
|
|
|
|
2018-11-15 19:07:10 -08:00
|
|
|
var (
|
2018-11-15 20:21:50 -08:00
|
|
|
ErrNoVoterAccount = ExecStatus{false, "No voter account registered. Add voter first"}
|
|
|
|
ErrInvalidNode = ExecStatus{false, "Invalid node id"}
|
|
|
|
ErrAccountNotAVoter = ExecStatus{false, "Account is not a voter. Action cannot be approved"}
|
|
|
|
ErrInvalidAccount = ExecStatus{false, "Invalid account id"}
|
2018-11-19 23:43:56 -08:00
|
|
|
ErrInvalidAccountAccess = ExecStatus{false, "Invalid account access type"}
|
2018-11-15 20:21:50 -08:00
|
|
|
ErrFailedExecution = ExecStatus{false, "Failed to execute permission action"}
|
2018-11-18 19:58:34 -08:00
|
|
|
ErrNodeDetailsMismatch = ExecStatus{false, "Node details mismatch"}
|
|
|
|
ErrPermissionDisabled = ExecStatus{false, "Permissions control not enabled"}
|
2018-11-19 23:43:56 -08:00
|
|
|
ErrAccountAccess = ExecStatus{false, "Account does not have sufficient access for operation"}
|
2018-11-20 05:29:03 -08:00
|
|
|
ErrVoterAccountAccess = ExecStatus{false, "Voter account does not have sufficient access"}
|
2018-11-15 20:21:50 -08:00
|
|
|
ExecSuccess = ExecStatus{true, "Action completed successfully"}
|
2018-11-15 19:07:10 -08:00
|
|
|
)
|
|
|
|
|
2018-11-15 20:21:50 -08:00
|
|
|
var (
|
|
|
|
nodeApproveStatus = map[uint8]string{
|
|
|
|
0: "Unknown",
|
|
|
|
1: "PendingApproval",
|
|
|
|
2: "Approved",
|
|
|
|
3: "PendingDeactivation",
|
|
|
|
4: "Deactivated",
|
|
|
|
5: "PendingActivation",
|
|
|
|
6: "PendingBlacklisting",
|
|
|
|
7: "Blacklisted",
|
|
|
|
}
|
2018-11-12 00:16:56 -08:00
|
|
|
|
2018-11-15 20:21:50 -08:00
|
|
|
accountPermMap = map[uint8]string{
|
|
|
|
0: "FullAccess",
|
|
|
|
1: "ReadOnly",
|
|
|
|
2: "Transact",
|
|
|
|
3: "ContractDeploy",
|
|
|
|
}
|
|
|
|
)
|
2018-11-14 20:32:11 -08:00
|
|
|
|
2018-10-31 22:45:16 -07:00
|
|
|
// NewPermissionAPI creates a new PermissionAPI to access quorum services
|
2018-10-31 00:15:34 -07:00
|
|
|
func NewPermissionAPI(tp *core.TxPool, am *accounts.Manager) *PermissionAPI {
|
2018-11-18 19:58:34 -08:00
|
|
|
return &PermissionAPI{tp, nil, am, nil, nil, nil, nil, false}
|
2018-11-14 01:58:57 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// helper function decodes the node status to string
|
|
|
|
func decodeNodeStatus(nodeStatus uint8) string {
|
2018-11-14 20:32:11 -08:00
|
|
|
if status, ok := nodeApproveStatus[nodeStatus]; ok {
|
|
|
|
return status
|
2018-11-14 01:58:57 -08:00
|
|
|
}
|
2018-11-14 20:32:11 -08:00
|
|
|
return "Unknown"
|
2018-10-29 19:41:01 -07:00
|
|
|
}
|
|
|
|
|
2018-10-31 22:45:16 -07:00
|
|
|
//Init initializes PermissionAPI with eth client, permission contract and org key management control
|
2018-11-14 02:03:50 -08:00
|
|
|
func (p *PermissionAPI) Init(ethClnt *ethclient.Client, key *ecdsa.PrivateKey) error {
|
2018-10-30 00:05:41 -07:00
|
|
|
p.ethClnt = ethClnt
|
2018-10-30 00:59:08 -07:00
|
|
|
permContr, err := pbind.NewPermissions(params.QuorumPermissionsContract, p.ethClnt)
|
2018-10-30 00:05:41 -07:00
|
|
|
if err != nil {
|
|
|
|
return err
|
2018-10-29 19:41:01 -07:00
|
|
|
}
|
2018-10-30 00:05:41 -07:00
|
|
|
p.permContr = permContr
|
2018-10-30 00:59:08 -07:00
|
|
|
clustContr, err := pbind.NewCluster(params.QuorumPrivateKeyManagementContract, p.ethClnt)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
p.clustContr = clustContr
|
2018-11-14 01:58:57 -08:00
|
|
|
p.key = key
|
2018-11-18 19:58:34 -08:00
|
|
|
p.enabled = true
|
2018-10-29 19:41:01 -07:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2018-11-14 02:24:28 -08:00
|
|
|
// Returns the list of Nodes and status of each
|
2018-11-12 00:16:56 -08:00
|
|
|
func (s *PermissionAPI) PermissionNodeList() []nodeStatus {
|
2018-11-20 06:36:24 -08:00
|
|
|
if !s.enabled {
|
|
|
|
nodeStatArr := make([]nodeStatus, 1)
|
|
|
|
nodeStatArr[0].EnodeId = "Permisssions control not enabled for network"
|
|
|
|
return nodeStatArr
|
|
|
|
}
|
2018-11-15 21:40:36 -08:00
|
|
|
ps := s.newPermSessionWithNodeKeySigner()
|
2018-11-14 01:58:57 -08:00
|
|
|
// get the total number of nodes on the contract
|
|
|
|
nodeCnt, err := ps.GetNumberOfNodes()
|
2018-11-15 19:07:10 -08:00
|
|
|
if err != nil {
|
|
|
|
return nil
|
|
|
|
}
|
2018-11-14 20:32:11 -08:00
|
|
|
nodeCntI := nodeCnt.Int64()
|
|
|
|
nodeStatArr := make([]nodeStatus, nodeCntI)
|
2018-11-14 01:58:57 -08:00
|
|
|
// loop for each index and get the node details from the contract
|
2018-11-15 19:07:10 -08:00
|
|
|
i := int64(0)
|
|
|
|
for i < nodeCntI {
|
2018-11-18 19:58:34 -08:00
|
|
|
nodeDtls, err := ps.GetNodeDetailsFromIndex(big.NewInt(i))
|
2018-11-15 20:21:50 -08:00
|
|
|
if err != nil {
|
|
|
|
log.Error("error getting node details", "err", err)
|
|
|
|
} else {
|
2018-11-20 05:29:03 -08:00
|
|
|
nodeStatArr[i].EnodeId = "enode://" + nodeDtls.EnodeId + "@" + nodeDtls.IpAddrPort
|
|
|
|
nodeStatArr[i].EnodeId += "?discport=" + nodeDtls.DiscPort
|
2018-11-15 20:21:50 -08:00
|
|
|
if len(nodeDtls.RaftPort) > 0 {
|
2018-11-20 05:29:03 -08:00
|
|
|
nodeStatArr[i].EnodeId += "&raftport=" + nodeDtls.RaftPort
|
2018-11-15 20:21:50 -08:00
|
|
|
}
|
|
|
|
nodeStatArr[i].Status = decodeNodeStatus(nodeDtls.NodeStatus)
|
2018-11-14 01:58:57 -08:00
|
|
|
}
|
2018-11-15 19:07:10 -08:00
|
|
|
i++
|
2018-11-12 00:16:56 -08:00
|
|
|
}
|
|
|
|
return nodeStatArr
|
|
|
|
}
|
|
|
|
|
2018-11-15 20:21:50 -08:00
|
|
|
func (s *PermissionAPI) PermissionAccountList() []accountInfo {
|
2018-11-20 06:36:24 -08:00
|
|
|
if !s.enabled {
|
|
|
|
acctInfoArr := make([]accountInfo, 1)
|
|
|
|
acctInfoArr[0].Address = "Account access control not enable for the network"
|
|
|
|
return acctInfoArr
|
|
|
|
}
|
2018-11-15 21:40:36 -08:00
|
|
|
ps := s.newPermSessionWithNodeKeySigner()
|
2018-11-15 20:21:50 -08:00
|
|
|
// 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
|
|
|
|
}
|
|
|
|
|
2018-11-15 21:40:36 -08:00
|
|
|
func (s *PermissionAPI) VoterList() []string {
|
2018-11-20 06:51:49 -08:00
|
|
|
if !s.enabled {
|
|
|
|
voterArr := make([]string, 1)
|
|
|
|
voterArr[0] = "Permissions control not enabled for the network"
|
|
|
|
return voterArr
|
|
|
|
}
|
2018-11-15 21:40:36 -08:00
|
|
|
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)
|
|
|
|
voterArr := make([]string, voterCntI)
|
|
|
|
// loop for each index and get the node details from the contract
|
|
|
|
i := int64(0)
|
|
|
|
for i < voterCntI {
|
|
|
|
a, err := ps.GetVoter(big.NewInt(i))
|
|
|
|
if err != nil {
|
|
|
|
log.Error("error getting voter info", "err", err)
|
|
|
|
} else {
|
|
|
|
voterArr[i] = a.String()
|
|
|
|
}
|
|
|
|
i++
|
|
|
|
}
|
|
|
|
return voterArr
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *PermissionAPI) 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
|
|
|
|
}
|
|
|
|
|
2018-11-15 20:21:50 -08:00
|
|
|
func decodeAccountPermission(access uint8) string {
|
|
|
|
if status, ok := accountPermMap[access]; ok {
|
|
|
|
return status
|
|
|
|
}
|
|
|
|
return "Unknown"
|
|
|
|
}
|
|
|
|
|
2018-10-31 22:45:16 -07:00
|
|
|
// AddVoter adds an account to the list of accounts that can approve nodes proposed or deactivated
|
2018-11-12 00:16:56 -08:00
|
|
|
func (s *PermissionAPI) AddVoter(vaddr common.Address, txa ethapi.SendTxArgs) ExecStatus {
|
2018-10-31 22:12:11 -07:00
|
|
|
return s.executePermAction(AddVoter, txArgs{voter: vaddr, txa: txa})
|
2018-10-30 00:05:41 -07:00
|
|
|
}
|
|
|
|
|
2018-10-31 22:45:16 -07:00
|
|
|
// RemoveVoter removes an account from the list of accounts that can approve nodes proposed or deactivated
|
2018-11-12 00:16:56 -08:00
|
|
|
func (s *PermissionAPI) RemoveVoter(vaddr common.Address, txa ethapi.SendTxArgs) ExecStatus {
|
2018-10-31 22:12:11 -07:00
|
|
|
return s.executePermAction(RemoveVoter, txArgs{voter: vaddr, txa: txa})
|
2018-10-31 05:46:54 -07:00
|
|
|
}
|
2018-10-31 00:15:34 -07:00
|
|
|
|
2018-10-31 22:45:16 -07:00
|
|
|
// ProposeNode proposes a node to join the network
|
2018-11-12 00:16:56 -08:00
|
|
|
func (s *PermissionAPI) ProposeNode(nodeId string, txa ethapi.SendTxArgs) ExecStatus {
|
2018-10-31 22:12:11 -07:00
|
|
|
return s.executePermAction(ProposeNode, txArgs{nodeId: nodeId, txa: txa})
|
2018-10-31 05:46:54 -07:00
|
|
|
}
|
2018-10-30 00:05:41 -07:00
|
|
|
|
2018-10-31 22:45:16 -07:00
|
|
|
// ApproveNode approves a proposed node to join the network
|
2018-11-12 00:16:56 -08:00
|
|
|
func (s *PermissionAPI) ApproveNode(nodeId string, txa ethapi.SendTxArgs) ExecStatus {
|
2018-10-31 22:12:11 -07:00
|
|
|
return s.executePermAction(ApproveNode, txArgs{nodeId: nodeId, txa: txa})
|
2018-10-31 05:46:54 -07:00
|
|
|
}
|
2018-10-30 00:05:41 -07:00
|
|
|
|
2018-10-31 22:45:16 -07:00
|
|
|
// DeactivateNode requests a node to get deactivated
|
2018-11-12 00:16:56 -08:00
|
|
|
func (s *PermissionAPI) ProposeNodeDeactivation(nodeId string, txa ethapi.SendTxArgs) ExecStatus {
|
2018-11-05 07:44:23 -08:00
|
|
|
return s.executePermAction(ProposeNodeDeactivation, txArgs{nodeId: nodeId, txa: txa})
|
2018-10-30 00:05:41 -07:00
|
|
|
}
|
2018-10-29 19:41:01 -07:00
|
|
|
|
2018-10-31 22:45:16 -07:00
|
|
|
// ApproveDeactivateNode approves a node to get deactivated
|
2018-11-12 00:16:56 -08:00
|
|
|
func (s *PermissionAPI) ApproveNodeDeactivation(nodeId string, txa ethapi.SendTxArgs) ExecStatus {
|
2018-11-05 07:44:23 -08:00
|
|
|
return s.executePermAction(ApproveNodeDeactivation, txArgs{nodeId: nodeId, txa: txa})
|
2018-10-31 05:46:54 -07:00
|
|
|
}
|
2018-10-29 19:41:01 -07:00
|
|
|
|
2018-11-05 07:44:23 -08:00
|
|
|
// DeactivateNode requests a node to get deactivated
|
2018-11-12 00:16:56 -08:00
|
|
|
func (s *PermissionAPI) ProposeNodeActivation(nodeId string, txa ethapi.SendTxArgs) ExecStatus {
|
2018-11-05 07:44:23 -08:00
|
|
|
return s.executePermAction(ProposeNodeActivation, txArgs{nodeId: nodeId, txa: txa})
|
|
|
|
}
|
|
|
|
|
|
|
|
// ApproveDeactivateNode approves a node to get deactivated
|
2018-11-12 00:16:56 -08:00
|
|
|
func (s *PermissionAPI) ApproveNodeActivation(nodeId string, txa ethapi.SendTxArgs) ExecStatus {
|
2018-11-05 07:44:23 -08:00
|
|
|
return s.executePermAction(ApproveNodeActivation, txArgs{nodeId: nodeId, txa: txa})
|
|
|
|
}
|
|
|
|
|
|
|
|
// DeactivateNode requests a node to get deactivated
|
2018-11-12 00:16:56 -08:00
|
|
|
func (s *PermissionAPI) ProposeNodeBlacklisting(nodeId string, txa ethapi.SendTxArgs) ExecStatus {
|
2018-11-05 07:44:23 -08:00
|
|
|
return s.executePermAction(ProposeNodeBlacklisting, txArgs{nodeId: nodeId, txa: txa})
|
|
|
|
}
|
|
|
|
|
|
|
|
// ApproveDeactivateNode approves a node to get deactivated
|
2018-11-12 00:16:56 -08:00
|
|
|
func (s *PermissionAPI) ApproveNodeBlacklisting(nodeId string, txa ethapi.SendTxArgs) ExecStatus {
|
2018-11-05 07:44:23 -08:00
|
|
|
return s.executePermAction(ApproveNodeBlacklisting, txArgs{nodeId: nodeId, txa: txa})
|
|
|
|
}
|
2018-11-12 00:16:56 -08:00
|
|
|
|
2018-10-31 22:45:16 -07:00
|
|
|
// RemoveOrgKey removes an org key combination from the org key map
|
2018-11-12 00:16:56 -08:00
|
|
|
func (s *PermissionAPI) RemoveOrgKey(orgId string, pvtKey string, txa ethapi.SendTxArgs) ExecStatus {
|
2018-10-31 22:12:11 -07:00
|
|
|
return s.executeOrgKeyAction(RemoveOrgKey, txArgs{txa: txa, orgId: orgId, keyId: pvtKey})
|
|
|
|
}
|
|
|
|
|
2018-10-31 22:45:16 -07:00
|
|
|
// AddOrgKey adds an org key combination to the org key map
|
2018-11-12 00:16:56 -08:00
|
|
|
func (s *PermissionAPI) AddOrgKey(orgId string, pvtKey string, txa ethapi.SendTxArgs) ExecStatus {
|
2018-10-31 22:12:11 -07:00
|
|
|
return s.executeOrgKeyAction(AddOrgKey, txArgs{txa: txa, orgId: orgId, keyId: pvtKey})
|
2018-10-30 00:05:41 -07:00
|
|
|
}
|
|
|
|
|
2018-11-12 00:16:56 -08:00
|
|
|
func (s *PermissionAPI) SetAccountAccess(acct common.Address, access string, txa ethapi.SendTxArgs) ExecStatus {
|
2018-11-06 21:58:51 -08:00
|
|
|
return s.executePermAction(SetAccountAccess, txArgs{acctId: acct, accessType: access, txa: txa})
|
|
|
|
}
|
|
|
|
|
2018-10-31 22:45:16 -07:00
|
|
|
// executePermAction helps to execute an action in permission contract
|
2018-11-12 00:16:56 -08:00
|
|
|
func (s *PermissionAPI) executePermAction(action PermAction, args txArgs) ExecStatus {
|
2018-11-18 22:59:10 -08:00
|
|
|
|
2018-11-18 19:58:34 -08:00
|
|
|
if !s.enabled {
|
|
|
|
return ErrPermissionDisabled
|
|
|
|
}
|
2018-11-07 19:35:29 -08:00
|
|
|
var err error
|
|
|
|
var w accounts.Wallet
|
2018-11-12 00:16:56 -08:00
|
|
|
|
2018-11-07 19:35:29 -08:00
|
|
|
w, err = s.validateAccount(args.txa.From)
|
2018-10-30 00:05:41 -07:00
|
|
|
if err != nil {
|
2018-11-15 19:07:10 -08:00
|
|
|
return ErrInvalidAccount
|
2018-10-30 00:05:41 -07:00
|
|
|
}
|
2018-10-31 22:12:11 -07:00
|
|
|
ps := s.newPermSession(w, args.txa)
|
2018-10-31 05:46:54 -07:00
|
|
|
var tx *types.Transaction
|
2018-11-07 19:35:29 -08:00
|
|
|
var node *discover.Node
|
2018-10-31 05:46:54 -07:00
|
|
|
|
|
|
|
switch action {
|
|
|
|
case AddVoter:
|
2018-11-20 05:29:03 -08:00
|
|
|
if !checkVoterAccountAccess(args.voter){
|
|
|
|
return ErrVoterAccountAccess
|
|
|
|
}
|
2018-10-31 05:46:54 -07:00
|
|
|
tx, err = ps.AddVoter(args.voter)
|
2018-11-13 00:15:28 -08:00
|
|
|
|
2018-10-31 05:46:54 -07:00
|
|
|
case RemoveVoter:
|
|
|
|
tx, err = ps.RemoveVoter(args.voter)
|
2018-11-13 00:15:28 -08:00
|
|
|
|
2018-10-31 05:46:54 -07:00
|
|
|
case ProposeNode:
|
2018-11-14 02:24:28 -08:00
|
|
|
if !checkVoterExists(ps) {
|
2018-11-15 19:07:10 -08:00
|
|
|
return ErrNoVoterAccount
|
2018-11-13 00:15:28 -08:00
|
|
|
}
|
|
|
|
node, err = discover.ParseNode(args.nodeId)
|
|
|
|
if err != nil {
|
|
|
|
log.Error("invalid node id: %v", err)
|
2018-11-15 19:07:10 -08:00
|
|
|
return ErrInvalidNode
|
2018-11-05 07:44:23 -08:00
|
|
|
}
|
2018-11-13 00:15:28 -08:00
|
|
|
enodeID := node.ID.String()
|
|
|
|
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
|
|
|
|
|
|
|
|
tx, err = ps.ProposeNode(enodeID, ipAddrPort, discPort, raftPort)
|
|
|
|
|
2018-11-05 07:44:23 -08:00
|
|
|
case ApproveNode:
|
2018-11-14 02:24:28 -08:00
|
|
|
if !checkIsVoter(ps, args.txa.From) {
|
2018-11-15 19:07:10 -08:00
|
|
|
return ErrAccountNotAVoter
|
2018-11-13 00:15:28 -08:00
|
|
|
}
|
2018-11-07 19:35:29 -08:00
|
|
|
node, err = discover.ParseNode(args.nodeId)
|
2018-10-31 05:46:54 -07:00
|
|
|
if err != nil {
|
|
|
|
log.Error("invalid node id: %v", err)
|
2018-11-15 19:07:10 -08:00
|
|
|
return ErrInvalidNode
|
2018-10-31 05:46:54 -07:00
|
|
|
}
|
|
|
|
enodeID := node.ID.String()
|
2018-11-18 19:58:34 -08:00
|
|
|
|
|
|
|
if !checkNodeDetails(ps, enodeID, node) {
|
|
|
|
return ErrNodeDetailsMismatch
|
|
|
|
}
|
2018-11-05 07:44:23 -08:00
|
|
|
tx, err = ps.ApproveNode(enodeID)
|
2018-11-13 00:15:28 -08:00
|
|
|
|
2018-11-05 07:44:23 -08:00
|
|
|
case ProposeNodeDeactivation:
|
2018-11-14 02:24:28 -08:00
|
|
|
if !checkVoterExists(ps) {
|
2018-11-15 19:07:10 -08:00
|
|
|
return ErrNoVoterAccount
|
2018-11-05 07:44:23 -08:00
|
|
|
}
|
2018-11-13 00:15:28 -08:00
|
|
|
node, err = discover.ParseNode(args.nodeId)
|
|
|
|
if err != nil {
|
|
|
|
log.Error("invalid node id: %v", err)
|
2018-11-15 19:07:10 -08:00
|
|
|
return ErrInvalidNode
|
2018-11-13 00:15:28 -08:00
|
|
|
}
|
|
|
|
enodeID := node.ID.String()
|
|
|
|
tx, err = ps.ProposeDeactivation(enodeID)
|
|
|
|
|
2018-11-05 07:44:23 -08:00
|
|
|
case ApproveNodeDeactivation:
|
2018-11-14 02:24:28 -08:00
|
|
|
if !checkIsVoter(ps, args.txa.From) {
|
2018-11-15 19:07:10 -08:00
|
|
|
return ErrAccountNotAVoter
|
2018-11-13 00:15:28 -08:00
|
|
|
}
|
2018-11-07 19:35:29 -08:00
|
|
|
node, err = discover.ParseNode(args.nodeId)
|
2018-10-31 05:46:54 -07:00
|
|
|
if err != nil {
|
|
|
|
log.Error("invalid node id: %v", err)
|
2018-11-15 19:07:10 -08:00
|
|
|
return ErrInvalidNode
|
2018-10-31 05:46:54 -07:00
|
|
|
}
|
|
|
|
enodeID := node.ID.String()
|
2018-11-18 19:58:34 -08:00
|
|
|
if !checkNodeDetails(ps, enodeID, node) {
|
|
|
|
return ErrNodeDetailsMismatch
|
|
|
|
}
|
2018-11-05 07:44:23 -08:00
|
|
|
tx, err = ps.DeactivateNode(enodeID)
|
2018-11-13 00:15:28 -08:00
|
|
|
|
2018-11-05 07:44:23 -08:00
|
|
|
case ProposeNodeActivation:
|
2018-11-14 02:24:28 -08:00
|
|
|
if !checkVoterExists(ps) {
|
2018-11-15 19:07:10 -08:00
|
|
|
return ErrNoVoterAccount
|
2018-11-13 00:15:28 -08:00
|
|
|
}
|
|
|
|
node, err = discover.ParseNode(args.nodeId)
|
|
|
|
if err != nil {
|
|
|
|
log.Error("invalid node id: %v", err)
|
2018-11-15 19:07:10 -08:00
|
|
|
return ErrInvalidNode
|
2018-11-05 07:44:23 -08:00
|
|
|
}
|
2018-11-13 00:15:28 -08:00
|
|
|
enodeID := node.ID.String()
|
|
|
|
tx, err = ps.ProposeNodeActivation(enodeID)
|
|
|
|
|
2018-11-05 07:44:23 -08:00
|
|
|
case ApproveNodeActivation:
|
2018-11-14 02:24:28 -08:00
|
|
|
if !checkIsVoter(ps, args.txa.From) {
|
2018-11-15 19:07:10 -08:00
|
|
|
return ErrAccountNotAVoter
|
2018-11-13 00:15:28 -08:00
|
|
|
}
|
2018-11-07 19:35:29 -08:00
|
|
|
node, err = discover.ParseNode(args.nodeId)
|
2018-10-31 05:46:54 -07:00
|
|
|
if err != nil {
|
|
|
|
log.Error("invalid node id: %v", err)
|
2018-11-15 19:07:10 -08:00
|
|
|
return ErrInvalidNode
|
2018-10-31 05:46:54 -07:00
|
|
|
}
|
|
|
|
enodeID := node.ID.String()
|
2018-11-18 19:58:34 -08:00
|
|
|
if !checkNodeDetails(ps, enodeID, node) {
|
|
|
|
return ErrNodeDetailsMismatch
|
|
|
|
}
|
2018-11-05 07:44:23 -08:00
|
|
|
tx, err = ps.ActivateNode(enodeID)
|
2018-11-13 00:15:28 -08:00
|
|
|
|
2018-11-05 07:44:23 -08:00
|
|
|
case ProposeNodeBlacklisting:
|
2018-11-14 02:24:28 -08:00
|
|
|
if !checkVoterExists(ps) {
|
2018-11-15 19:07:10 -08:00
|
|
|
return ErrNoVoterAccount
|
2018-11-13 00:15:28 -08:00
|
|
|
}
|
|
|
|
node, err = discover.ParseNode(args.nodeId)
|
|
|
|
if err != nil {
|
|
|
|
log.Error("invalid node id: %v", err)
|
2018-11-15 19:07:10 -08:00
|
|
|
return ErrInvalidNode
|
2018-11-05 07:44:23 -08:00
|
|
|
}
|
2018-11-13 00:15:28 -08:00
|
|
|
enodeID := node.ID.String()
|
|
|
|
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
|
|
|
|
|
|
|
|
tx, err = ps.ProposeNodeBlacklisting(enodeID, ipAddrPort, discPort, raftPort)
|
2018-11-05 07:44:23 -08:00
|
|
|
case ApproveNodeBlacklisting:
|
2018-11-14 02:24:28 -08:00
|
|
|
if !checkIsVoter(ps, args.txa.From) {
|
2018-11-15 19:07:10 -08:00
|
|
|
return ErrAccountNotAVoter
|
2018-11-13 00:15:28 -08:00
|
|
|
}
|
2018-11-07 19:35:29 -08:00
|
|
|
node, err = discover.ParseNode(args.nodeId)
|
2018-10-31 05:46:54 -07:00
|
|
|
if err != nil {
|
|
|
|
log.Error("invalid node id: %v", err)
|
2018-11-15 19:07:10 -08:00
|
|
|
return ErrInvalidNode
|
2018-10-31 05:46:54 -07:00
|
|
|
}
|
|
|
|
enodeID := node.ID.String()
|
2018-11-18 19:58:34 -08:00
|
|
|
if !checkNodeDetails(ps, enodeID, node) {
|
|
|
|
return ErrNodeDetailsMismatch
|
|
|
|
}
|
2018-11-05 07:44:23 -08:00
|
|
|
tx, err = ps.BlacklistNode(enodeID)
|
2018-11-13 00:15:28 -08:00
|
|
|
|
2018-11-06 21:58:51 -08:00
|
|
|
case SetAccountAccess:
|
2018-11-07 19:35:29 -08:00
|
|
|
var access uint64
|
|
|
|
access, err = strconv.ParseUint(args.accessType, 10, 8)
|
2018-11-06 21:58:51 -08:00
|
|
|
if err != nil {
|
2018-11-15 19:07:10 -08:00
|
|
|
return ErrInvalidAccountAccess
|
2018-11-06 21:58:51 -08:00
|
|
|
}
|
2018-11-19 23:43:56 -08:00
|
|
|
if !checkAccountAccess(args.txa.From, uint8(access)) {
|
|
|
|
return ErrAccountAccess
|
|
|
|
}
|
2018-11-06 21:58:51 -08:00
|
|
|
tx, err = ps.UpdateAccountAccess(args.acctId, uint8(access))
|
2018-11-07 19:35:29 -08:00
|
|
|
}
|
2018-11-13 00:15:28 -08:00
|
|
|
|
2018-11-07 19:35:29 -08:00
|
|
|
if err != nil {
|
|
|
|
log.Error("Failed to execute permission action", "action", action, "err", err)
|
2018-11-15 19:07:10 -08:00
|
|
|
return ErrFailedExecution
|
2018-10-30 00:05:41 -07:00
|
|
|
}
|
2018-10-31 05:46:54 -07:00
|
|
|
log.Debug("executed permission action", "action", action, "tx", tx)
|
2018-11-15 19:07:10 -08:00
|
|
|
return ExecSuccess
|
2018-10-30 00:05:41 -07:00
|
|
|
}
|
|
|
|
|
2018-10-31 22:45:16 -07:00
|
|
|
// executeOrgKeyAction helps to execute an action in cluster contract
|
2018-11-12 00:16:56 -08:00
|
|
|
func (s *PermissionAPI) executeOrgKeyAction(action OrgKeyAction, args txArgs) ExecStatus {
|
2018-11-18 19:58:34 -08:00
|
|
|
if !s.enabled {
|
|
|
|
return ErrPermissionDisabled
|
|
|
|
}
|
2018-10-31 22:12:11 -07:00
|
|
|
w, err := s.validateAccount(args.txa.From)
|
2018-10-30 00:05:41 -07:00
|
|
|
if err != nil {
|
2018-11-12 00:16:56 -08:00
|
|
|
return ExecStatus{false, err.Error()}
|
2018-10-30 00:05:41 -07:00
|
|
|
}
|
2018-10-31 22:12:11 -07:00
|
|
|
ps := s.newClusterSession(w, args.txa)
|
2018-10-31 05:46:54 -07:00
|
|
|
var tx *types.Transaction
|
2018-10-30 00:05:41 -07:00
|
|
|
|
2018-10-31 05:46:54 -07:00
|
|
|
switch action {
|
|
|
|
case AddOrgKey:
|
|
|
|
tx, err = ps.AddOrgKey(args.orgId, args.keyId)
|
|
|
|
case RemoveOrgKey:
|
|
|
|
tx, err = ps.DeleteOrgKey(args.orgId, args.keyId)
|
|
|
|
}
|
2018-10-30 00:05:41 -07:00
|
|
|
if err != nil {
|
2018-10-31 05:46:54 -07:00
|
|
|
log.Error("Failed to execute orgKey action", "action", action, "err", err)
|
2018-11-12 00:16:56 -08:00
|
|
|
return ExecStatus{false, err.Error()}
|
2018-10-30 00:05:41 -07:00
|
|
|
}
|
2018-10-31 05:46:54 -07:00
|
|
|
log.Debug("executed orgKey action", "action", action, "tx", tx)
|
2018-11-12 00:16:56 -08:00
|
|
|
return ExecStatus{true, ""}
|
2018-10-30 00:05:41 -07:00
|
|
|
}
|
|
|
|
|
2018-10-31 22:45:16 -07:00
|
|
|
// validateAccount validates the account and returns the wallet associated with that for signing the transaction
|
2018-10-31 22:12:11 -07:00
|
|
|
func (s *PermissionAPI) validateAccount(from common.Address) (accounts.Wallet, error) {
|
2018-10-31 05:46:54 -07:00
|
|
|
acct := accounts.Account{Address: from}
|
|
|
|
w, err := s.acntMgr.Find(acct)
|
|
|
|
if err != nil {
|
2018-10-31 22:12:11 -07:00
|
|
|
return nil, err
|
2018-10-29 19:41:01 -07:00
|
|
|
}
|
2018-10-31 22:12:11 -07:00
|
|
|
return w, nil
|
2018-10-29 19:41:01 -07:00
|
|
|
}
|
|
|
|
|
2018-11-05 07:44:23 -08:00
|
|
|
// checkVoterExists checks if any vote accounts are there. If yes returns true, else false
|
|
|
|
func checkVoterExists(ps *pbind.PermissionsSession) bool {
|
|
|
|
tx, err := ps.GetNumberOfVoters()
|
2018-11-12 00:16:56 -08:00
|
|
|
log.Debug("number of voters", "count", tx)
|
2018-11-05 07:44:23 -08:00
|
|
|
if err == nil && tx.Cmp(big.NewInt(0)) > 0 {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2018-11-13 00:15:28 -08:00
|
|
|
// 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)
|
|
|
|
if err == nil && tx {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
2018-11-14 02:24:28 -08:00
|
|
|
|
2018-10-31 22:45:16 -07:00
|
|
|
// newPermSession creates a new permission contract session
|
2018-10-31 22:12:11 -07:00
|
|
|
func (s *PermissionAPI) newPermSession(w accounts.Wallet, txa ethapi.SendTxArgs) *pbind.PermissionsSession {
|
|
|
|
frmAcct, transactOpts, gasLimit, gasPrice, nonce := s.getTxParams(txa, w)
|
2018-10-31 05:46:54 -07:00
|
|
|
ps := &pbind.PermissionsSession{
|
2018-10-31 00:15:34 -07:00
|
|
|
Contract: s.permContr,
|
|
|
|
CallOpts: bind.CallOpts{
|
|
|
|
Pending: true,
|
|
|
|
},
|
|
|
|
TransactOpts: bind.TransactOpts{
|
2018-10-31 22:12:11 -07:00
|
|
|
From: frmAcct.Address,
|
|
|
|
GasLimit: gasLimit,
|
|
|
|
GasPrice: gasPrice,
|
2018-10-31 05:46:54 -07:00
|
|
|
Signer: transactOpts.Signer,
|
2018-10-31 22:12:11 -07:00
|
|
|
Nonce: nonce,
|
2018-10-31 00:15:34 -07:00
|
|
|
},
|
|
|
|
}
|
2018-10-31 05:46:54 -07:00
|
|
|
return ps
|
2018-10-31 00:15:34 -07:00
|
|
|
}
|
|
|
|
|
2018-10-31 22:45:16 -07:00
|
|
|
// newClusterSession creates a new cluster contract session
|
2018-10-31 22:12:11 -07:00
|
|
|
func (s *PermissionAPI) newClusterSession(w accounts.Wallet, txa ethapi.SendTxArgs) *pbind.ClusterSession {
|
|
|
|
frmAcct, transactOpts, gasLimit, gasPrice, nonce := s.getTxParams(txa, w)
|
|
|
|
cs := &pbind.ClusterSession{
|
2018-10-30 00:59:08 -07:00
|
|
|
Contract: s.clustContr,
|
|
|
|
CallOpts: bind.CallOpts{
|
|
|
|
Pending: true,
|
|
|
|
},
|
|
|
|
TransactOpts: bind.TransactOpts{
|
2018-10-31 22:12:11 -07:00
|
|
|
From: frmAcct.Address,
|
|
|
|
GasLimit: gasLimit,
|
|
|
|
GasPrice: gasPrice,
|
2018-10-31 05:46:54 -07:00
|
|
|
Signer: transactOpts.Signer,
|
2018-10-31 22:12:11 -07:00
|
|
|
Nonce: nonce,
|
2018-10-30 00:59:08 -07:00
|
|
|
},
|
|
|
|
}
|
2018-10-31 22:12:11 -07:00
|
|
|
return cs
|
|
|
|
}
|
|
|
|
|
2018-10-31 22:45:16 -07:00
|
|
|
// getTxParams extracts the transaction related parameters
|
2018-10-31 22:12:11 -07:00
|
|
|
func (s *PermissionAPI) getTxParams(txa ethapi.SendTxArgs, w accounts.Wallet) (accounts.Account, *bind.TransactOpts, uint64, *big.Int, *big.Int) {
|
|
|
|
frmAcct := accounts.Account{Address: txa.From}
|
|
|
|
transactOpts := bind.NewWalletTransactor(w, frmAcct)
|
|
|
|
gasLimit := defaultGasLimit
|
|
|
|
gasPrice := defaultGasPrice
|
|
|
|
if txa.GasPrice != nil {
|
|
|
|
gasPrice = txa.GasPrice.ToInt()
|
|
|
|
}
|
|
|
|
if txa.Gas != nil {
|
|
|
|
gasLimit = uint64(*txa.Gas)
|
|
|
|
}
|
|
|
|
var nonce *big.Int
|
|
|
|
if txa.Nonce != nil {
|
|
|
|
nonce = new(big.Int).SetUint64(uint64(*txa.Nonce))
|
|
|
|
} else {
|
|
|
|
nonce = new(big.Int).SetUint64(s.txPool.Nonce(frmAcct.Address))
|
|
|
|
}
|
|
|
|
return frmAcct, transactOpts, gasLimit, gasPrice, nonce
|
2018-10-30 00:59:08 -07:00
|
|
|
}
|
2018-11-18 19:58:34 -08:00
|
|
|
|
|
|
|
// checks if the input node details for approval is matching with details stored
|
|
|
|
// in contract
|
|
|
|
func checkNodeDetails (ps *pbind.PermissionsSession, enodeID string, node *discover.Node ) bool {
|
|
|
|
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
|
|
|
|
|
|
|
|
cnode, err := ps.GetNodeDetails(enodeID)
|
|
|
|
if err == nil {
|
|
|
|
if strings.Compare(ipAddrPort, cnode.IpAddrPort) == 0 && strings.Compare(discPort, cnode.DiscPort) == 0 && strings.Compare(raftPort, cnode.RaftPort) == 0 {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
2018-11-19 23:43:56 -08:00
|
|
|
|
|
|
|
// checks if the account performing the operation has sufficient access privileges
|
|
|
|
func checkAccountAccess (from common.Address, accessType uint8) bool {
|
|
|
|
acctAccess := types.GetAcctAccess(from)
|
|
|
|
|
|
|
|
if acctAccess == types.FullAccess {
|
|
|
|
return true
|
|
|
|
} else if acctAccess == types.ContractDeploy && accessType != uint8(types.FullAccess) {
|
|
|
|
return true
|
|
|
|
} else if acctAccess == types.Transact && (accessType == uint8(types.Transact) || accessType == uint8(types.ReadOnly)) {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
2018-11-20 05:29:03 -08:00
|
|
|
|
|
|
|
// checks if the account performing the operation has sufficient access privileges
|
|
|
|
func checkVoterAccountAccess (account common.Address) bool {
|
|
|
|
acctAccess := types.GetAcctAccess(account)
|
|
|
|
if acctAccess == types.ReadOnly {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|