quorum/permission/permission.go

781 lines
27 KiB
Go
Raw Normal View History

package permission
2018-07-12 03:00:19 -07:00
import (
2018-10-30 23:42:29 -07:00
"crypto/ecdsa"
"encoding/json"
"errors"
2018-07-12 03:00:19 -07:00
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
2018-10-31 22:45:16 -07:00
"github.com/ethereum/go-ethereum/controls"
pbind "github.com/ethereum/go-ethereum/controls/bind/permission"
2018-10-31 22:45:16 -07:00
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/eth"
2018-07-12 03:00:19 -07:00
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/p2p/enode"
2018-10-31 22:45:16 -07:00
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/raft"
"github.com/ethereum/go-ethereum/rpc"
"io/ioutil"
"math/big"
"os"
"path/filepath"
"sync"
"time"
2018-07-12 03:00:19 -07:00
)
type NodeOperation uint8
const (
NodeAdd NodeOperation = iota
NodeDelete
)
// permission config for bootstrapping
type PermissionLocalConfig struct {
UpgrdAddress string
InterfAddress string
ImplAddress string
NodeAddress string
AccountAddress string
RoleAddress string
VoterAddress string
OrgAddress string
NwAdminOrg string
NwAdminRole string
OrgAdminRole string
Accounts []string //initial list of account that need full access
SubOrgBreadth string
SubOrgDepth string
}
type PermissionCtrl struct {
2018-11-14 02:24:28 -08:00
node *node.Node
ethClnt *ethclient.Client
eth *eth.Ethereum
isRaft bool
2018-11-13 00:15:28 -08:00
permissionedMode bool
2018-11-14 02:24:28 -08:00
key *ecdsa.PrivateKey
dataDir string
permUpgr *pbind.PermUpgr
permInterf *pbind.PermInterface
permNode *pbind.NodeManager
permAcct *pbind.AcctManager
permRole *pbind.RoleManager
permOrg *pbind.OrgManager
permConfig *types.PermissionConfig
orgChan chan struct{}
nodeChan chan struct{}
roleChan chan struct{}
acctChan chan struct{}
}
2019-04-01 03:22:41 -07:00
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 {
var permConfig types.PermissionConfig
permConfig.UpgrdAddress = common.HexToAddress(config.UpgrdAddress)
permConfig.InterfAddress = common.HexToAddress(config.InterfAddress)
permConfig.ImplAddress = common.HexToAddress(config.ImplAddress)
permConfig.OrgAddress = common.HexToAddress(config.OrgAddress)
permConfig.RoleAddress = common.HexToAddress(config.RoleAddress)
permConfig.NodeAddress = common.HexToAddress(config.NodeAddress)
permConfig.AccountAddress = common.HexToAddress(config.AccountAddress)
permConfig.VoterAddress = common.HexToAddress(config.VoterAddress)
permConfig.NwAdminOrg = config.NwAdminOrg
permConfig.NwAdminRole = config.NwAdminRole
permConfig.OrgAdminRole = config.OrgAdminRole
// populate the account list as passed in config
for _, val := range config.Accounts {
permConfig.Accounts = append(permConfig.Accounts, common.HexToAddress(val))
}
permConfig.SubOrgBreadth.SetString(config.SubOrgBreadth, 10)
permConfig.SubOrgDepth.SetString(config.SubOrgDepth, 10)
return permConfig
}
// this function reads the permissions config file passed and populates the
// config structure accrodingly
func ParsePermissionConifg(dir string) (types.PermissionConfig, error) {
fileName := "permission-config.json"
fullPath := filepath.Join(dir, fileName)
blob, err := ioutil.ReadFile(fullPath)
if err != nil {
log.Error("error reading permission-config.json file", err)
return types.PermissionConfig{}, err
}
var permlocConfig PermissionLocalConfig
err = json.Unmarshal(blob, &permlocConfig)
if err != nil {
log.Error("error unmarshalling permission-config.json file", err)
return types.PermissionConfig{}, err
}
permConfig := populateConfig(permlocConfig)
if len(permConfig.Accounts) == 0 {
return types.PermissionConfig{}, errors.New("no accounts given in permission-config.json. Network cannot boot up")
}
if permConfig.SubOrgDepth.Cmp(big.NewInt(0)) == 0 || permConfig.SubOrgBreadth.Cmp(big.NewInt(0)) == 0 {
return types.PermissionConfig{}, errors.New("sub org breadth depth not passed in permission-config.json. Network cannot boot up")
}
return permConfig, nil
2018-10-25 21:33:23 -07:00
}
func waitForSync(e *eth.Ethereum) {
for !types.GetSyncStatus() {
time.Sleep(10 * time.Millisecond)
}
for e.Downloader().Synchronising() {
time.Sleep(10 * time.Millisecond)
}
}
2018-10-31 19:55:40 -07:00
// Creates the controls structure for permissions
func NewQuorumPermissionCtrl(stack *node.Node, permissionedMode, isRaft bool, pconfig *types.PermissionConfig) (*PermissionCtrl, error) {
2018-08-05 22:26:29 -07:00
// Create a new ethclient to for interfacing with the contract
clnt, e, err := controls.CreateEthClient(stack)
//waitForSync(e)
2018-08-05 22:26:29 -07:00
if err != nil {
2019-02-13 01:42:59 -08:00
log.Error("Unable to create ethereum client for permissions check", "err", err)
return nil, err
}
if pconfig.IsEmpty() && permissionedMode {
log.Error("permission-config.json is missing contract address")
return nil, errors.New("permission-config.json is missing contract address")
}
pu, err := pbind.NewPermUpgr(pconfig.UpgrdAddress, clnt)
if err != nil {
log.Error("Permissions not enabled for the network", "err", err)
return nil, err
}
// check if permissioning contract is there at address. If not return from here
pm, err := pbind.NewPermInterface(pconfig.InterfAddress, clnt)
if err != nil {
log.Error("Permissions not enabled for the network", "err", err)
return nil, err
}
pmAcct, err := pbind.NewAcctManager(pconfig.AccountAddress, clnt)
2018-11-02 03:42:14 -07:00
if err != nil {
2019-02-13 01:42:59 -08:00
log.Error("Permissions not enabled for the network", "err", err)
2018-11-02 03:42:14 -07:00
return nil, err
}
pmNode, err := pbind.NewNodeManager(pconfig.NodeAddress, clnt)
if err != nil {
log.Error("Permissions not enabled for the network", "err", err)
return nil, err
}
pmRole, err := pbind.NewRoleManager(pconfig.RoleAddress, clnt)
if err != nil {
log.Error("Permissions not enabled for the network", "err", err)
return nil, err
}
pmOrg, err := pbind.NewOrgManager(pconfig.OrgAddress, clnt)
if err != nil {
log.Error("Permissions not enabled for the network", "err", err)
return nil, err
}
return &PermissionCtrl{stack, clnt, e, isRaft, permissionedMode, stack.GetNodeKey(), stack.DataDir(), pu, pm, pmNode, pmAcct, pmRole, pmOrg, pconfig, make(chan struct{}), make(chan struct{}), make(chan struct{}), make(chan struct{})}, nil
2018-11-02 03:42:14 -07:00
}
// Starts the node permissioning and event monitoring for permissions
// smart contracts
func (p *PermissionCtrl) Start(srvr *p2p.Server) error {
log.Info("permission service started...")
// Permissions initialization
2018-11-02 03:42:14 -07:00
if err := p.init(); err != nil {
2019-02-13 01:42:59 -08:00
log.Error("Permissions init failed", "err", err)
2018-11-02 03:42:14 -07:00
return err
}
// monitor org management related events
go p.manageOrgPermissions()
// monitor org level node management events
go p.manageNodePermissions()
// monitor org level role management events
go p.manageRolePermissions()
// monitor org level account management events
go p.manageAccountPermissions()
2018-11-02 03:42:14 -07:00
return nil
}
2018-07-13 18:22:43 -07:00
func (s *PermissionCtrl) APIs() []rpc.API {
log.Info("permission rpc API called")
return []rpc.API{
{
Namespace: "quorumPermission",
Version: "1.0",
Service: NewQuorumControlsAPI(s.eth.TxPool(), s.eth.AccountManager(), s.permConfig, s.permInterf),
Public: true,
},
}
}
func (s *PermissionCtrl) Protocols() []p2p.Protocol {
return []p2p.Protocol{}
}
func (p *PermissionCtrl) Stop() error {
log.Info("stopping permission service...")
p.roleChan <- struct{}{}
p.orgChan <- struct{}{}
p.acctChan <- struct{}{}
p.nodeChan <- struct{}{}
log.Info("stopped permission service")
return nil
}
2019-02-12 20:31:11 -08:00
// Sets the initial values for the network
func (p *PermissionCtrl) init() error {
2018-11-02 03:42:14 -07:00
// populate the initial list of permissioned nodes and account accesses
if err := p.populateInitPermissions(); err != nil {
2018-11-02 03:42:14 -07:00
return err
}
2019-02-11 17:54:13 -08:00
// set the default access to ReadOnly
types.SetDefaultAccess()
types.SetAdminRole(p.permConfig.NwAdminRole, p.permConfig.OrgAdminRole)
2019-02-11 17:54:13 -08:00
return nil
}
// monitors org management related events happening via
// smart contracts
func (p *PermissionCtrl) manageOrgPermissions() {
chPendingApproval := make(chan *pbind.OrgManagerOrgPendingApproval, 1)
chOrgApproved := make(chan *pbind.OrgManagerOrgApproved, 1)
chOrgSuspended := make(chan *pbind.OrgManagerOrgSuspended, 1)
chOrgReactivated := make(chan *pbind.OrgManagerOrgSuspensionRevoked, 1)
var evtPendingApproval *pbind.OrgManagerOrgPendingApproval
var evtOrgApproved *pbind.OrgManagerOrgApproved
var evtOrgSuspended *pbind.OrgManagerOrgSuspended
var evtOrgReactivated *pbind.OrgManagerOrgSuspensionRevoked
opts := &bind.WatchOpts{}
var blockNumber uint64 = 1
opts.Start = &blockNumber
if _, err := p.permOrg.OrgManagerFilterer.WatchOrgPendingApproval(opts, chPendingApproval); err != nil {
log.Info("Failed WatchNodePendingApproval: %v", err)
}
if _, err := p.permOrg.OrgManagerFilterer.WatchOrgApproved(opts, chOrgApproved); err != nil {
log.Info("Failed WatchNodePendingApproval: %v", err)
}
if _, err := p.permOrg.OrgManagerFilterer.WatchOrgSuspended(opts, chOrgSuspended); err != nil {
log.Info("Failed WatchNodePendingApproval: %v", err)
}
if _, err := p.permOrg.OrgManagerFilterer.WatchOrgSuspensionRevoked(opts, chOrgReactivated); err != nil {
log.Info("Failed WatchNodePendingApproval: %v", err)
}
for {
select {
case evtPendingApproval = <-chPendingApproval:
types.OrgInfoMap.UpsertOrg(evtPendingApproval.OrgId, evtPendingApproval.PorgId, evtPendingApproval.UltParent, evtPendingApproval.Level, types.OrgStatus(evtPendingApproval.Status.Uint64()))
case evtOrgApproved = <-chOrgApproved:
types.OrgInfoMap.UpsertOrg(evtOrgApproved.OrgId, evtOrgApproved.PorgId, evtOrgApproved.UltParent, evtOrgApproved.Level, types.OrgApproved)
case evtOrgSuspended = <-chOrgSuspended:
types.OrgInfoMap.UpsertOrg(evtOrgSuspended.OrgId, evtOrgSuspended.PorgId, evtOrgSuspended.UltParent, evtOrgSuspended.Level, types.OrgSuspended)
case evtOrgReactivated = <-chOrgReactivated:
types.OrgInfoMap.UpsertOrg(evtOrgReactivated.OrgId, evtOrgReactivated.PorgId, evtOrgReactivated.UltParent, evtOrgReactivated.Level, types.OrgApproved)
case <-p.orgChan:
log.Info("quit org contract watch")
}
}
}
// Monitors node management events and updates cache accordingly
func (p *PermissionCtrl) manageNodePermissions() {
chNodeApproved := make(chan *pbind.NodeManagerNodeApproved, 1)
chNodeProposed := make(chan *pbind.NodeManagerNodeProposed, 1)
chNodeDeactivated := make(chan *pbind.NodeManagerNodeDeactivated, 1)
chNodeActivated := make(chan *pbind.NodeManagerNodeActivated, 1)
chNodeBlacklisted := make(chan *pbind.NodeManagerNodeBlacklisted)
var evtNodeApproved *pbind.NodeManagerNodeApproved
var evtNodeProposed *pbind.NodeManagerNodeProposed
var evtNodeDeactivated *pbind.NodeManagerNodeDeactivated
var evtNodeActivated *pbind.NodeManagerNodeActivated
var evtNodeBlacklisted *pbind.NodeManagerNodeBlacklisted
2018-07-13 18:22:43 -07:00
opts := &bind.WatchOpts{}
var blockNumber uint64 = 1
opts.Start = &blockNumber
if _, err := p.permNode.NodeManagerFilterer.WatchNodeApproved(opts, chNodeApproved); err != nil {
log.Info("Failed WatchNodeApproved", "error", err)
}
if _, err := p.permNode.NodeManagerFilterer.WatchNodeProposed(opts, chNodeProposed); err != nil {
log.Info("Failed WatchNodeProposed", "error", err)
}
if _, err := p.permNode.NodeManagerFilterer.WatchNodeDeactivated(opts, chNodeDeactivated); err != nil {
log.Info("Failed NodeDeactivated", "error", err)
2018-08-16 20:20:33 -07:00
}
if _, err := p.permNode.NodeManagerFilterer.WatchNodeActivated(opts, chNodeActivated); err != nil {
log.Info("Failed WatchNodeActivated", "error", err)
2018-08-16 20:20:33 -07:00
}
2018-08-05 22:26:29 -07:00
if _, err := p.permNode.NodeManagerFilterer.WatchNodeBlacklisted(opts, chNodeBlacklisted); err != nil {
log.Info("Failed NodeBlacklisting", "error", err)
2018-11-02 03:42:14 -07:00
}
2018-08-31 04:35:35 -07:00
for {
select {
case evtNodeApproved = <-chNodeApproved:
p.updatePermissionedNodes(evtNodeApproved.EnodeId, NodeAdd)
types.NodeInfoMap.UpsertNode(evtNodeApproved.OrgId, evtNodeApproved.EnodeId, types.NodeApproved)
case evtNodeProposed = <-chNodeProposed:
types.NodeInfoMap.UpsertNode(evtNodeProposed.OrgId, evtNodeProposed.EnodeId, types.NodePendingApproval)
case evtNodeDeactivated = <-chNodeDeactivated:
p.updatePermissionedNodes(evtNodeDeactivated.EnodeId, NodeDelete)
types.NodeInfoMap.UpsertNode(evtNodeDeactivated.OrgId, evtNodeDeactivated.EnodeId, types.NodeDeactivated)
case evtNodeActivated = <-chNodeActivated:
p.updatePermissionedNodes(evtNodeActivated.EnodeId, NodeAdd)
types.NodeInfoMap.UpsertNode(evtNodeActivated.OrgId, evtNodeActivated.EnodeId, types.NodeApproved)
case evtNodeBlacklisted = <-chNodeBlacklisted:
p.updatePermissionedNodes(evtNodeBlacklisted.EnodeId, NodeDelete)
p.updateDisallowedNodes(evtNodeBlacklisted.EnodeId)
types.NodeInfoMap.UpsertNode(evtNodeBlacklisted.OrgId, evtNodeBlacklisted.EnodeId, types.NodeBlackListed)
case <-p.nodeChan:
log.Info("quit node contract watch")
return
2018-08-31 04:35:35 -07:00
}
}
2018-08-31 04:35:35 -07:00
}
2018-11-07 04:50:49 -08:00
2019-02-12 20:31:11 -08:00
// Populates the new node information into the permissioned-nodes.json file
func (p *PermissionCtrl) updatePermissionedNodes(enodeId string, operation NodeOperation) {
log.Debug("updatePermissionedNodes", "DataDir", p.dataDir, "file", params.PERMISSIONED_CONFIG)
path := filepath.Join(p.dataDir, params.PERMISSIONED_CONFIG)
if _, err := os.Stat(path); err != nil {
2019-02-13 01:42:59 -08:00
log.Error("Read Error for permissioned-nodes.json file. This is because 'permissioned' flag is specified but no permissioned-nodes.json file is present", "err", err)
2019-02-11 17:54:13 -08:00
return
}
// Load the nodes from the config file
blob, err := ioutil.ReadFile(path)
if err != nil {
log.Error("updatePermissionedNodes: Failed to access permissioned-nodes.json", "err", err)
return
}
nodelist := []string{}
if err := json.Unmarshal(blob, &nodelist); err != nil {
log.Error("updatePermissionedNodes: Failed to load nodes list", "err", err)
2019-02-11 17:54:13 -08:00
return
}
// logic to update the permissioned-nodes.json file based on action
index := 0
recExists := false
for i, eid := range nodelist {
if eid == enodeId {
index = i
recExists = true
break
}
}
if operation == NodeAdd {
if !recExists {
nodelist = append(nodelist, enodeId)
2018-08-16 20:20:33 -07:00
}
} else {
if recExists {
nodelist = append(nodelist[:index], nodelist[index+1:]...)
}
p.disconnectNode(enodeId)
}
mu := sync.RWMutex{}
blob, _ = json.Marshal(nodelist)
mu.Lock()
2019-02-11 17:54:13 -08:00
if err := ioutil.WriteFile(path, blob, 0644); err != nil {
log.Error("updatePermissionedNodes: Error writing new node info to file", "err", err)
}
mu.Unlock()
}
2018-08-31 04:35:35 -07:00
2019-02-12 20:31:11 -08:00
//this function populates the black listed node information into the disallowed-nodes.json file
func (p *PermissionCtrl) updateDisallowedNodes(url string) {
log.Debug("updateDisallowedNodes", "DataDir", p.dataDir, "file", params.BLACKLIST_CONFIG)
2018-08-31 04:35:35 -07:00
2018-09-02 23:59:45 -07:00
fileExisted := true
path := filepath.Join(p.dataDir, params.BLACKLIST_CONFIG)
2018-09-02 23:59:45 -07:00
// Check if the file is existing. If the file is not existing create the file
2018-08-31 04:35:35 -07:00
if _, err := os.Stat(path); err != nil {
2019-02-13 01:42:59 -08:00
log.Error("Read Error for disallowed-nodes.json file", "err", err)
2018-08-31 04:35:35 -07:00
if _, err := os.OpenFile(path, os.O_CREATE|os.O_RDWR, 0644); err != nil {
2019-02-13 01:42:59 -08:00
log.Error("Failed to create disallowed-nodes.json file", "err", err)
return
2018-08-31 04:35:35 -07:00
}
2018-09-02 23:59:45 -07:00
fileExisted = false
2018-08-31 04:35:35 -07:00
}
nodelist := []string{}
2018-09-02 23:59:45 -07:00
// Load the nodes from the config file
if fileExisted == true {
blob, err := ioutil.ReadFile(path)
if err != nil {
log.Error("updateDisallowedNodes Failed to access disallowed-nodes.json", "err", err)
return
}
2018-10-31 22:45:16 -07:00
if blob != nil {
2018-09-02 23:59:45 -07:00
if err := json.Unmarshal(blob, &nodelist); err != nil {
log.Error("updateDisallowedNodes: Failed to load nodes list", "err", err)
return
2018-09-02 23:59:45 -07:00
}
2018-08-31 04:35:35 -07:00
}
}
nodelist = append(nodelist, url)
2018-08-31 04:35:35 -07:00
mu := sync.RWMutex{}
2018-09-02 23:59:45 -07:00
blob, _ := json.Marshal(nodelist)
2018-08-31 04:35:35 -07:00
mu.Lock()
if err := ioutil.WriteFile(path, blob, 0644); err != nil {
2018-08-31 04:35:35 -07:00
log.Error("updateDisallowedNodes: Error writing new node info to file", "err", err)
}
mu.Unlock()
// Disconnect the peer if it is already connected
p.disconnectNode(url)
2018-08-31 04:35:35 -07:00
}
// Monitors account access related events and updates the cache accordingly
2018-11-02 03:42:14 -07:00
func (p *PermissionCtrl) manageAccountPermissions() {
chAccessModified := make(chan *pbind.AcctManagerAccountAccessModified)
chAccessRevoked := make(chan *pbind.AcctManagerAccountAccessRevoked)
chStatusChanged := make(chan *pbind.AcctManagerAccountStatusChanged)
var evtAccessModified *pbind.AcctManagerAccountAccessModified
var evtAccessRevoked *pbind.AcctManagerAccountAccessRevoked
var evtStatusChanged *pbind.AcctManagerAccountStatusChanged
opts := &bind.WatchOpts{}
var blockNumber uint64 = 1
opts.Start = &blockNumber
if _, err := p.permAcct.AcctManagerFilterer.WatchAccountAccessModified(opts, chAccessModified); err != nil {
log.Info("Failed NewNodeProposed", "error", err)
}
if _, err := p.permAcct.AcctManagerFilterer.WatchAccountAccessRevoked(opts, chAccessRevoked); err != nil {
log.Info("Failed NewNodeProposed", "error", err)
}
if _, err := p.permAcct.AcctManagerFilterer.WatchAccountStatusChanged(opts, chStatusChanged); err != nil {
log.Info("Failed NewNodeProposed", "error", err)
}
for {
select {
case evtAccessModified = <-chAccessModified:
types.AcctInfoMap.UpsertAccount(evtAccessModified.OrgId, evtAccessModified.RoleId, evtAccessModified.Address, evtAccessModified.OrgAdmin, types.AcctStatus(int(evtAccessModified.Status.Uint64())))
case evtAccessRevoked = <-chAccessRevoked:
types.AcctInfoMap.UpsertAccount(evtAccessRevoked.OrgId, evtAccessRevoked.RoleId, evtAccessRevoked.Address, evtAccessRevoked.OrgAdmin, types.AcctActive)
case evtStatusChanged = <-chStatusChanged:
ac := types.AcctInfoMap.GetAccount(evtStatusChanged.Address)
types.AcctInfoMap.UpsertAccount(evtStatusChanged.OrgId, ac.RoleId, evtStatusChanged.Address, ac.IsOrgAdmin, types.AcctStatus(int(evtStatusChanged.Status.Uint64())))
case <-p.acctChan:
log.Info("quit account contract watch")
}
}
}
2018-09-19 18:51:36 -07:00
// Disconnect the node from the network
func (p *PermissionCtrl) disconnectNode(enodeId string) {
if p.isRaft {
2018-09-19 18:51:36 -07:00
var raftService *raft.RaftService
if err := p.node.Service(&raftService); err == nil {
2018-09-19 18:51:36 -07:00
raftApi := raft.NewPublicRaftAPI(raftService)
//get the raftId for the given enodeId
raftId, err := raftApi.GetRaftId(enodeId)
if err == nil {
raftApi.RemovePeer(raftId)
}
}
} else {
// Istanbul - disconnect the peer
server := p.node.Server()
2018-09-19 18:51:36 -07:00
if server != nil {
node, err := enode.ParseV4(enodeId)
2018-09-19 18:51:36 -07:00
if err == nil {
server.RemovePeer(node)
}
}
}
}
2018-09-19 22:55:57 -07:00
// Thus function checks if the its the initial network boot up status and if no
// populates permissioning model with details from permission-config.json
func (p *PermissionCtrl) populateInitPermissions() error {
auth := bind.NewKeyedTransactor(p.key)
permInterfSession := &pbind.PermInterfaceSession{
Contract: p.permInterf,
CallOpts: bind.CallOpts{
Pending: true,
},
TransactOpts: bind.TransactOpts{
From: auth.From,
Signer: auth.Signer,
GasLimit: 47000000,
GasPrice: big.NewInt(0),
},
}
networkInitialized, err := permInterfSession.GetNetworkBootStatus()
if err != nil {
// handle the scenario of no contract code.
log.Warn("Failed to retrieve network boot status ", "err", err)
return err
}
2018-11-02 03:42:14 -07:00
if !networkInitialized {
if err := p.bootupNetwork(permInterfSession); err != nil {
2018-11-02 03:42:14 -07:00
return err
}
} else {
//populate orgs, nodes, roles and accounts from contract
p.populateOrgsFromContract(auth)
p.populateNodesFromContract(auth)
p.populateRolesFromContract(auth)
p.populateAccountsFromContract(auth)
}
return nil
}
// initialize the permissions model and populate initial values
func (p *PermissionCtrl) bootupNetwork(permInterfSession *pbind.PermInterfaceSession) error {
permInterfSession.TransactOpts.Nonce = new(big.Int).SetUint64(p.eth.TxPool().Nonce(permInterfSession.TransactOpts.From))
if _, err := permInterfSession.SetPolicy(p.permConfig.NwAdminOrg, p.permConfig.NwAdminRole, p.permConfig.OrgAdminRole); err != nil {
log.Error("bootupNetwork SetPolicy failed", "err", err)
return err
}
permInterfSession.TransactOpts.Nonce = new(big.Int).SetUint64(p.eth.TxPool().Nonce(permInterfSession.TransactOpts.From))
if _, err := permInterfSession.Init(p.permConfig.OrgAddress, p.permConfig.RoleAddress, p.permConfig.AccountAddress, p.permConfig.VoterAddress, p.permConfig.NodeAddress, &p.permConfig.SubOrgBreadth, &p.permConfig.SubOrgDepth); err != nil {
log.Error("bootupNetwork init failed", "err", err)
return err
}
types.OrgInfoMap.UpsertOrg(p.permConfig.NwAdminOrg, "", "", big.NewInt(1), types.OrgApproved)
types.RoleInfoMap.UpsertRole(p.permConfig.NwAdminOrg, p.permConfig.NwAdminRole, true, true, types.FullAccess, true)
// populate the initial node list from static-nodes.json
if err := p.populateStaticNodesToContract(permInterfSession); err != nil {
return err
}
// populate initial account access to full access
if err := p.populateInitAccountAccess(permInterfSession); err != nil {
return err
}
// update network status to boot completed
if err := p.updateNetworkStatus(permInterfSession); err != nil {
log.Error("failed to updated network boot status", "error", err)
return err
}
return nil
}
// populates the account access details from contract into cache
func (p *PermissionCtrl) populateAccountsFromContract(auth *bind.TransactOpts) {
//populate accounts
permAcctSession := &pbind.AcctManagerSession{
Contract: p.permAcct,
CallOpts: bind.CallOpts{
Pending: true,
},
}
if numberOfRoles, err := permAcctSession.GetNumberOfAccounts(); err == nil {
iOrgNum := numberOfRoles.Uint64()
for k := uint64(0); k < iOrgNum; k++ {
if addr, org, role, status, orgAdmin, err := permAcctSession.GetAccountDetailsFromIndex(big.NewInt(int64(k))); err == nil {
2019-03-28 21:28:11 -07:00
types.AcctInfoMap.UpsertAccount(org, role, addr, orgAdmin, types.AcctStatus(int(status.Int64())))
}
}
}
}
// populates the role details from contract into cache
func (p *PermissionCtrl) populateRolesFromContract(auth *bind.TransactOpts) {
//populate roles
permRoleSession := &pbind.RoleManagerSession{
Contract: p.permRole,
CallOpts: bind.CallOpts{
Pending: true,
},
}
if numberOfRoles, err := permRoleSession.GetNumberOfRoles(); err == nil {
iOrgNum := numberOfRoles.Uint64()
for k := uint64(0); k < iOrgNum; k++ {
if roleStruct, err := permRoleSession.GetRoleDetailsFromIndex(big.NewInt(int64(k))); err == nil {
types.RoleInfoMap.UpsertRole(roleStruct.OrgId, roleStruct.RoleId, roleStruct.Voter, roleStruct.Admin, types.AccessType(int(roleStruct.AccessType.Int64())), roleStruct.Active)
}
}
}
}
// populates the node details from contract into cache
func (p *PermissionCtrl) populateNodesFromContract(auth *bind.TransactOpts) {
//populate nodes
permNodeSession := &pbind.NodeManagerSession{
Contract: p.permNode,
CallOpts: bind.CallOpts{
Pending: true,
},
}
if numberOfNodes, err := permNodeSession.GetNumberOfNodes(); err == nil {
iOrgNum := numberOfNodes.Uint64()
for k := uint64(0); k < iOrgNum; k++ {
permNodeSession.TransactOpts.Nonce = new(big.Int).SetUint64(p.eth.TxPool().Nonce(permNodeSession.TransactOpts.From))
if nodeStruct, err := permNodeSession.GetNodeDetailsFromIndex(big.NewInt(int64(k))); err == nil {
2019-03-28 21:28:11 -07:00
types.NodeInfoMap.UpsertNode(nodeStruct.OrgId, nodeStruct.EnodeId, types.NodeStatus(int(nodeStruct.NodeStatus.Int64())))
}
}
}
}
// populates the org details from contract into cache
func (p *PermissionCtrl) populateOrgsFromContract(auth *bind.TransactOpts) {
//populate orgs
permOrgSession := &pbind.OrgManagerSession{
Contract: p.permOrg,
CallOpts: bind.CallOpts{
Pending: true,
},
}
if numberOfOrgs, err := permOrgSession.GetNumberOfOrgs(); err == nil {
iOrgNum := numberOfOrgs.Uint64()
for k := uint64(0); k < iOrgNum; k++ {
if orgId, porgId, ultParent, level, status, err := permOrgSession.GetOrgInfo(big.NewInt(int64(k))); err == nil {
types.OrgInfoMap.UpsertOrg(orgId, porgId, ultParent, level, types.OrgStatus(int(status.Int64())))
}
}
}
2018-11-02 03:42:14 -07:00
}
// Reads the node list from static-nodes.json and populates into the contract
func (p *PermissionCtrl) populateStaticNodesToContract(permissionsSession *pbind.PermInterfaceSession) error {
2018-11-02 03:42:14 -07:00
nodes := p2p.ParsePermissionedNodes(p.dataDir)
for _, node := range nodes {
enodeID := node.EnodeID()
2018-11-02 03:42:14 -07:00
nonce := p.eth.TxPool().Nonce(permissionsSession.TransactOpts.From)
permissionsSession.TransactOpts.Nonce = new(big.Int).SetUint64(nonce)
_, err := permissionsSession.AddAdminNodes(node.String())
2018-11-02 03:42:14 -07:00
if err != nil {
log.Warn("Failed to propose node", "err", err, "enode", enodeID)
2018-11-02 03:42:14 -07:00
return err
}
types.NodeInfoMap.UpsertNode(p.permConfig.NwAdminOrg, node.String(), 2)
2018-11-02 03:42:14 -07:00
}
return nil
}
2019-02-12 20:31:11 -08:00
// Invokes the initAccounts function of smart contract to set the initial
// set of accounts access to full access
func (p *PermissionCtrl) populateInitAccountAccess(permissionsSession *pbind.PermInterfaceSession) error {
for _, a := range p.permConfig.Accounts {
nonce := p.eth.TxPool().Nonce(permissionsSession.TransactOpts.From)
permissionsSession.TransactOpts.Nonce = new(big.Int).SetUint64(nonce)
_, er := permissionsSession.AddAdminAccounts(a)
if er != nil {
log.Warn("Error adding permission initial account list", "err", er, "account", a)
return er
2019-03-19 00:29:53 -07:00
}
types.AcctInfoMap.UpsertAccount(p.permConfig.NwAdminOrg, p.permConfig.NwAdminRole, a, true, 2)
2019-03-19 00:29:53 -07:00
}
2018-11-02 03:42:14 -07:00
return nil
}
2019-02-12 20:31:11 -08:00
// updates network boot status to true
func (p *PermissionCtrl) updateNetworkStatus(permissionsSession *pbind.PermInterfaceSession) error {
2018-11-02 03:42:14 -07:00
nonce := p.eth.TxPool().Nonce(permissionsSession.TransactOpts.From)
permissionsSession.TransactOpts.Nonce = new(big.Int).SetUint64(nonce)
_, err := permissionsSession.UpdateNetworkBootStatus()
if err != nil {
log.Warn("Failed to udpate network boot status ", "err", err)
return err
}
2018-11-02 03:42:14 -07:00
return nil
}
// monitors role management related events and updated cache
func (p *PermissionCtrl) manageRolePermissions() {
chRoleCreated := make(chan *pbind.RoleManagerRoleCreated, 1)
chRoleRevoked := make(chan *pbind.RoleManagerRoleRevoked, 1)
var evtRoleCreated *pbind.RoleManagerRoleCreated
var evtRoleRevoked *pbind.RoleManagerRoleRevoked
opts := &bind.WatchOpts{}
var blockNumber uint64 = 1
opts.Start = &blockNumber
if _, err := p.permRole.RoleManagerFilterer.WatchRoleCreated(opts, chRoleCreated); err != nil {
log.Info("Failed WatchRoleCreated: %v", err)
}
if _, err := p.permRole.RoleManagerFilterer.WatchRoleRevoked(opts, chRoleRevoked); err != nil {
log.Info("Failed WatchRoleRemoved: %v", err)
}
for {
select {
case evtRoleCreated = <-chRoleCreated:
types.RoleInfoMap.UpsertRole(evtRoleCreated.OrgId, evtRoleCreated.RoleId, evtRoleCreated.IsVoter, evtRoleCreated.IsAdmin, types.AccessType(int(evtRoleCreated.BaseAccess.Uint64())), true)
case evtRoleRevoked = <-chRoleRevoked:
if r := types.RoleInfoMap.GetRole(evtRoleRevoked.OrgId, evtRoleRevoked.RoleId); r != nil {
types.RoleInfoMap.UpsertRole(evtRoleRevoked.OrgId, evtRoleRevoked.RoleId, r.IsVoter, r.IsAdmin, r.Access, false)
2019-03-28 21:28:11 -07:00
} else {
log.Error("Revoke role - cache is missing role", "org", evtRoleRevoked.OrgId, "role", evtRoleRevoked.RoleId)
2019-03-28 21:28:11 -07:00
}
case <-p.roleChan:
log.Info("quit role contract watch")
}
}
}