permission: implement permission as standard service of the node

This commit is contained in:
amalraj.manigmail.com 2019-05-08 14:07:23 +08:00
parent 9d844b9dbf
commit 7e4b3ff310
17 changed files with 92 additions and 119 deletions

View File

@ -20,6 +20,9 @@ import (
"bufio"
"errors"
"fmt"
"github.com/ethereum/go-ethereum/controls/permission"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log"
"io"
"os"
"reflect"
@ -159,14 +162,20 @@ func makeFullNode(ctx *cli.Context) *node.Node {
ethChan := utils.RegisterEthService(stack, &cfg.Eth)
ethereum := <-ethChan
if ctx.GlobalBool(utils.RaftModeFlag.Name) {
RegisterRaftService(stack, ctx, cfg, ethChan)
RegisterRaftService(stack, ctx, cfg, ethereum)
}
if ctx.GlobalBool(utils.DashboardEnabledFlag.Name) {
utils.RegisterDashboardService(stack, &cfg.Dashboard, gitCommit)
}
if ctx.GlobalBool(utils.EnableNodePermissionFlag.Name) {
RegisterPermissionService(ctx, stack, ethereum)
}
// Whisper must be explicitly enabled by specifying at least 1 whisper flag or in dev mode
shhEnabled := enableWhisper(ctx)
shhAutoEnabled := !ctx.GlobalIsSet(utils.WhisperEnabledFlag.Name) && ctx.GlobalIsSet(utils.DeveloperFlag.Name)
@ -189,6 +198,27 @@ func makeFullNode(ctx *cli.Context) *node.Node {
}
return stack
}
func RegisterPermissionService(ctx *cli.Context, stack *node.Node, ethereum *eth.Ethereum) {
if err := stack.Register(func(sctx *node.ServiceContext) (node.Service, error) {
dataDir := ctx.GlobalString(utils.DataDirFlag.Name)
var permissionConfig types.PermissionConfig
var err error
if permissionConfig, err = permission.ParsePermissionConifg(dataDir); err != nil {
utils.Fatalf("loading of permission-config.json failed", "error")
}
// start the permissions management service
pc, err := permission.NewQuorumPermissionCtrl(stack, ctx.GlobalBool(utils.EnableNodePermissionFlag.Name), ctx.GlobalBool(utils.RaftModeFlag.Name), &permissionConfig)
if err != nil {
utils.Fatalf("Failed to load the permission contracts as given in permissions-config.json %v", err)
}
log.Info("permission service created")
return pc, nil
}); err != nil {
utils.Fatalf("Failed to register the permission service: %v", err)
}
log.Info("permission service registered")
}
// dumpConfig is the dumpconfig command.
func dumpConfig(ctx *cli.Context) error {
@ -209,7 +239,7 @@ func dumpConfig(ctx *cli.Context) error {
return nil
}
func RegisterRaftService(stack *node.Node, ctx *cli.Context, cfg gethConfig, ethChan <-chan *eth.Ethereum) {
func RegisterRaftService(stack *node.Node, ctx *cli.Context, cfg gethConfig, ethereum *eth.Ethereum) {
blockTimeMillis := ctx.GlobalInt(utils.RaftBlockTimeFlag.Name)
datadir := ctx.GlobalString(utils.DataDirFlag.Name)
joinExistingId := ctx.GlobalInt(utils.RaftJoinExistingFlag.Name)
@ -250,8 +280,6 @@ func RegisterRaftService(stack *node.Node, ctx *cli.Context, cfg gethConfig, eth
}
}
ethereum := <-ethChan
return raft.New(ctx, ethereum.ChainConfig(), myId, raftPort, joinExisting, blockTimeNanos, ethereum, peers, datadir)
}); err != nil {
utils.Fatalf("Failed to register the Raft service: %v", err)

View File

@ -19,7 +19,6 @@ package main
import (
"fmt"
"github.com/ethereum/go-ethereum/core/types"
"math"
"os"
godebug "runtime/debug"
@ -33,8 +32,6 @@ import (
"github.com/ethereum/go-ethereum/accounts/keystore"
"github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/console"
"github.com/ethereum/go-ethereum/controls/permission"
"github.com/ethereum/go-ethereum/core/quorum"
"github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/internal/debug"
@ -137,7 +134,6 @@ var (
utils.EVMInterpreterFlag,
configFileFlag,
utils.EnableNodePermissionFlag,
utils.PermissionContractAddressFlag,
utils.RaftModeFlag,
utils.RaftBlockTimeFlag,
utils.RaftJoinExistingFlag,
@ -346,9 +342,6 @@ func startNode(ctx *cli.Context, stack *node.Node) {
}
}()
//START - QUORUM Permissioning
go startQuorumPermissionService(ctx, stack)
// Start auxiliary services if enabled
if ctx.GlobalBool(utils.MiningEnabledFlag.Name) || ctx.GlobalBool(utils.DeveloperFlag.Name) {
// Mining only makes sense if a full Ethereum node is running
@ -376,57 +369,3 @@ func startNode(ctx *cli.Context, stack *node.Node) {
}
}
// Starts all permissioning services permissioning services will come up only when
// geth is brought up in --permissioned mode
func startQuorumPermissionService(ctx *cli.Context, stack *node.Node) {
var quorumApis []string
dataDir := ctx.GlobalString(utils.DataDirFlag.Name)
permEnabled := ctx.GlobalBool(utils.EnableNodePermissionFlag.Name)
var permissionConfig types.PermissionConfig
var err error
if permEnabled {
if permissionConfig, err = permission.ParsePermissionConifg(dataDir); err != nil {
log.Error("loading of permission-config.json failed", "error", err)
return
}
} else {
// permissions not enabled hence none of the services will be available.
return
}
// start the permissions management service
pc, err := permission.NewQuorumPermissionCtrl(stack, ctx.GlobalBool(utils.EnableNodePermissionFlag.Name), ctx.GlobalBool(utils.RaftModeFlag.Name), &permissionConfig)
if err != nil {
utils.Fatalf("Failed to load the permission contracts as given in permissions-config.json %v", err)
}
if err = pc.Start(); err == nil {
quorumApis = []string{"quorumPermission"}
} else {
utils.Fatalf("Failed to start Quorum Permission contract service %v", err)
}
rpcClient, err := stack.Attach() /**/
if err != nil {
utils.Fatalf("Unable to connect to the node: %v", err)
}
stateReader := ethclient.NewClient(rpcClient)
for _, apiName := range quorumApis {
v := stack.GetRPC(apiName)
if v == nil {
utils.Fatalf("Failed to start Quorum Permission API %s", apiName)
}
qapi := v.(*quorum.QuorumControlsAPI)
err = qapi.Init(stateReader, stack.GetNodeKey(), apiName, &permissionConfig, pc.Interface())
if err != nil {
log.Info("Failed to starts API", "apiName", apiName)
} else {
log.Info("API started", "apiName", apiName)
}
}
}

View File

@ -607,13 +607,6 @@ var (
Usage: "If enabled, the node will allow only a defined list of nodes to connect",
}
// Quorum permission contract
PermissionContractAddressFlag = cli.StringFlag{
Name: "permission.contract",
Usage: "If passed, the node will use this contract to bootstrap permission instead of contract from genesis.json",
Value: "0x",
}
// Istanbul settings
IstanbulRequestTimeoutFlag = cli.Uint64Flag{
Name: "istanbul.requesttimeout",

View File

@ -1,17 +1,14 @@
package quorum
package permission
import (
"crypto/ecdsa"
"errors"
"fmt"
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
obind "github.com/ethereum/go-ethereum/controls/bind/cluster"
pbind "github.com/ethereum/go-ethereum/controls/bind/permission"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/internal/ethapi"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/p2p/enode"
@ -70,16 +67,10 @@ type PermissionContracts struct {
// QuorumControlsAPI provides an API to access Quorum's node permission and org key management related services
type QuorumControlsAPI struct {
txPool *core.TxPool
ethClnt *ethclient.Client
acntMgr *accounts.Manager
txOpt *bind.TransactOpts
clustContr *obind.Cluster
key *ecdsa.PrivateKey
permEnabled bool
orgEnabled bool
permConfig *types.PermissionConfig
permInterf *pbind.PermInterface
txPool *core.TxPool
acctMgr *accounts.Manager
permConfig *types.PermissionConfig
permInterf *pbind.PermInterface
}
// txArgs holds arguments required for execute functions
@ -147,16 +138,15 @@ 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, false, false, nil, nil}
func NewQuorumControlsAPI(tp *core.TxPool, am *accounts.Manager, pcfg *types.PermissionConfig, pc *pbind.PermInterface) *QuorumControlsAPI {
return &QuorumControlsAPI{tp, am, pcfg, pc}
}
//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, pc *pbind.PermInterface) error {
/*//Init initializes QuorumControlsAPI with eth client, permission contract and org key management control
func (p *QuorumControlsAPI) Init(ethClnt *ethclient.Client, key *ecdsa.PrivateKey, pc *pbind.PermInterface) error {
// check if the interface contract is deployed or not. if not
// permissions apis will not work. return error
p.ethClnt = ethClnt
p.permConfig = pconfig
if _, err := pbind.NewPermInterface(p.permConfig.InterfAddress, p.ethClnt); err != nil {
return err
@ -166,7 +156,7 @@ func (p *QuorumControlsAPI) Init(ethClnt *ethclient.Client, key *ecdsa.PrivateKe
p.permInterf = pc
return nil
}
}*/
func (s *QuorumControlsAPI) OrgList() []types.OrgInfo {
return types.OrgInfoMap.GetOrgList()
@ -466,10 +456,6 @@ func (s *QuorumControlsAPI) valNodeDetails(url string) (ExecStatus, error) {
// executePermAction helps to execute an action in permission contract
func (s *QuorumControlsAPI) executePermAction(action PermAction, args txArgs) ExecStatus {
if !s.permEnabled {
return ErrPermissionDisabled
}
var err error
var w accounts.Wallet
@ -762,7 +748,7 @@ func (s *QuorumControlsAPI) executePermAction(action PermAction, args txArgs) Ex
// validateAccount validates the account and returns the wallet associated with that for signing the transaction
func (s *QuorumControlsAPI) validateAccount(from common.Address) (accounts.Wallet, error) {
acct := accounts.Account{Address: from}
w, err := s.acntMgr.Find(acct)
w, err := s.acctMgr.Find(acct)
if err != nil {
return nil, err
}

View File

@ -17,6 +17,7 @@ import (
"github.com/ethereum/go-ethereum/p2p/enode"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/raft"
"github.com/ethereum/go-ethereum/rpc"
"io/ioutil"
"math/big"
"os"
@ -66,6 +67,10 @@ type PermissionCtrl struct {
permRole *pbind.RoleManager
permOrg *pbind.OrgManager
permConfig *types.PermissionConfig
orgChan chan struct{}
nodeChan chan struct{}
roleChan chan struct{}
acctChan chan struct{}
}
func (p *PermissionCtrl) Interface() *pbind.PermInterface {
@ -146,7 +151,7 @@ func waitForSync(e *eth.Ethereum) {
// Creates the controls structure for permissions
func NewQuorumPermissionCtrl(stack *node.Node, permissionedMode, isRaft bool, pconfig *types.PermissionConfig) (*PermissionCtrl, error) {
// Create a new ethclient to for interfacing with the contract
stateReader, e, err := controls.CreateEthClient(stack)
clnt, e, err := controls.CreateEthClient(stack)
waitForSync(e)
if err != nil {
log.Error("Unable to create ethereum client for permissions check", "err", err)
@ -157,47 +162,47 @@ func NewQuorumPermissionCtrl(stack *node.Node, permissionedMode, isRaft bool, pc
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, stateReader)
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, stateReader)
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, stateReader)
pmAcct, err := pbind.NewAcctManager(pconfig.AccountAddress, clnt)
if err != nil {
log.Error("Permissions not enabled for the network", "err", err)
return nil, err
}
pmNode, err := pbind.NewNodeManager(pconfig.NodeAddress, stateReader)
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, stateReader)
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, stateReader)
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, stateReader, e, isRaft, permissionedMode, stack.GetNodeKey(), stack.DataDir(), pu, pm, pmNode, pmAcct, pmRole, pmOrg, pconfig}, nil
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
}
// Starts the node permissioning and event monitoring for permissions
// smart contracts
func (p *PermissionCtrl) Start() error {
func (p *PermissionCtrl) Start(srvr *p2p.Server) error {
// Permissions initialization
if err := p.init(); err != nil {
log.Error("Permissions init failed", "err", err)
@ -219,6 +224,32 @@ func (p *PermissionCtrl) Start() error {
return nil
}
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
}
// Sets the initial values for the network
func (p *PermissionCtrl) init() error {
// populate the initial list of permissioned nodes and account accesses
@ -280,6 +311,8 @@ func (p *PermissionCtrl) manageOrgPermissions() {
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")
}
}
}
@ -342,6 +375,9 @@ func (p *PermissionCtrl) manageNodePermissions() {
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
}
}
}
@ -480,6 +516,8 @@ func (p *PermissionCtrl) manageAccountPermissions() {
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")
}
}
}
@ -738,6 +776,8 @@ func (p *PermissionCtrl) manageRolePermissions() {
} else {
log.Error("Revoke role - cache is missing role", "org", evtRoleRevoked.OrgId, "role", evtRoleRevoked.RoleId)
}
case <-p.roleChan:
log.Info("quit role contract watch")
}
}
}

View File

@ -35,7 +35,6 @@ import (
istanbulBackend "github.com/ethereum/go-ethereum/consensus/istanbul/backend"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/bloombits"
"github.com/ethereum/go-ethereum/core/quorum"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
@ -337,18 +336,6 @@ func (s *Ethereum) APIs() []rpc.API {
Service: s.netRPCService,
Public: true,
},
{
Namespace: "quorumPermission",
Version: "1.0",
Service: quorum.NewQuorumControlsAPI(s.txPool, s.accountManager),
Public: true,
},
{
Namespace: "quorumOrgMgmt",
Version: "1.0",
Service: quorum.NewQuorumControlsAPI(s.txPool, s.accountManager),
Public: true,
},
}...)
return apis
}