github.com/Night-mk/quorum@v21.1.0+incompatible/permission/backend.go (about)

     1  package permission
     2  
     3  import (
     4  	"crypto/ecdsa"
     5  	"errors"
     6  	"math/big"
     7  	"sync"
     8  	"time"
     9  
    10  	"github.com/ethereum/go-ethereum/accounts"
    11  	"github.com/ethereum/go-ethereum/accounts/abi/bind"
    12  	"github.com/ethereum/go-ethereum/common"
    13  	"github.com/ethereum/go-ethereum/eth"
    14  	"github.com/ethereum/go-ethereum/internal/ethapi"
    15  	"github.com/ethereum/go-ethereum/log"
    16  	"github.com/ethereum/go-ethereum/node"
    17  	"github.com/ethereum/go-ethereum/p2p"
    18  	"github.com/ethereum/go-ethereum/permission/core"
    19  	ptype "github.com/ethereum/go-ethereum/permission/core/types"
    20  	"github.com/ethereum/go-ethereum/permission/v1"
    21  	"github.com/ethereum/go-ethereum/permission/v2"
    22  	"github.com/ethereum/go-ethereum/rpc"
    23  )
    24  
    25  type PermissionCtrl struct {
    26  	node               *node.Node
    27  	ethClnt            bind.ContractBackend
    28  	eth                *eth.Ethereum
    29  	key                *ecdsa.PrivateKey
    30  	dataDir            string
    31  	permConfig         *ptype.PermissionConfig
    32  	contract           ptype.InitService
    33  	backend            ptype.Backend
    34  	useDns             bool
    35  	isRaft             bool
    36  	startWaitGroup     *sync.WaitGroup // waitgroup to make sure all dependencies are ready before we start the service
    37  	errorChan          chan error      // channel to capture error when starting aysnc
    38  	networkInitialized bool
    39  	controlService     ptype.ControlService
    40  }
    41  
    42  var permissionService *PermissionCtrl
    43  
    44  func setPermissionService(ps *PermissionCtrl) {
    45  	if permissionService == nil {
    46  		permissionService = ps
    47  	}
    48  }
    49  
    50  // Create a service instance for permissioning
    51  //
    52  // Permission Service depends on the following:
    53  // 1. EthService to be ready
    54  // 2. Downloader to sync up blocks
    55  // 3. InProc RPC server to be ready
    56  func NewQuorumPermissionCtrl(stack *node.Node, pconfig *ptype.PermissionConfig, useDns bool) (*PermissionCtrl, error) {
    57  	wg := &sync.WaitGroup{}
    58  	wg.Add(1)
    59  
    60  	p := &PermissionCtrl{
    61  		node:           stack,
    62  		key:            stack.GetNodeKey(),
    63  		dataDir:        stack.DataDir(),
    64  		permConfig:     pconfig,
    65  		startWaitGroup: wg,
    66  		errorChan:      make(chan error),
    67  		useDns:         useDns,
    68  		isRaft:         false,
    69  	}
    70  
    71  	err := p.populateBackEnd()
    72  	if err != nil {
    73  		return nil, err
    74  	}
    75  	stopChan, stopSubscription := ptype.SubscribeStopEvent()
    76  	inProcRPCServerSub := stack.EventMux().Subscribe(rpc.InProcServerReadyEvent{})
    77  	log.Debug("permission service: waiting for InProcRPC Server")
    78  
    79  	go func(_wg *sync.WaitGroup) {
    80  		defer func(start time.Time) {
    81  			log.Debug("permission service: InProcRPC server is ready", "took", time.Since(start))
    82  			stopSubscription.Unsubscribe()
    83  			inProcRPCServerSub.Unsubscribe()
    84  			_wg.Done()
    85  		}(time.Now())
    86  		select {
    87  		case <-inProcRPCServerSub.Chan():
    88  		case <-stopChan:
    89  		}
    90  	}(wg) // wait for inproc RPC to be ready
    91  	return p, nil
    92  }
    93  
    94  func (p *PermissionCtrl) Start(srvr *p2p.Server) error {
    95  	log.Info("permission service: starting")
    96  	go func() {
    97  		log.Info("permission service: starting async")
    98  		p.asyncStart()
    99  	}()
   100  	return nil
   101  }
   102  
   103  func (p *PermissionCtrl) Protocols() []p2p.Protocol {
   104  	return []p2p.Protocol{}
   105  }
   106  
   107  func (p *PermissionCtrl) APIs() []rpc.API {
   108  	return []rpc.API{
   109  		{
   110  			Namespace: "quorumPermission",
   111  			Version:   "1.0",
   112  			Service:   NewQuorumControlsAPI(p),
   113  			Public:    true,
   114  		},
   115  	}
   116  }
   117  
   118  func (p *PermissionCtrl) Stop() error {
   119  	log.Info("permission service: stopping")
   120  	ptype.StopFeed.Send(ptype.StopEvent{})
   121  	log.Info("permission service: stopped")
   122  	return nil
   123  }
   124  
   125  func (p *PermissionCtrl) IsV2Permission() bool {
   126  	return p.permConfig.PermissionsModel == ptype.PERMISSION_V2
   127  }
   128  
   129  func NewPermissionContractService(ethClnt bind.ContractBackend, permissionV2 bool, key *ecdsa.PrivateKey,
   130  	permConfig *ptype.PermissionConfig, isRaft, useDns bool) ptype.InitService {
   131  
   132  	contractBackEnd := ptype.ContractBackend{
   133  		EthClnt:    ethClnt,
   134  		Key:        key,
   135  		PermConfig: permConfig,
   136  		IsRaft:     isRaft,
   137  		UseDns:     useDns,
   138  	}
   139  
   140  	if permissionV2 {
   141  		return &v2.Init{
   142  			Backend: contractBackEnd,
   143  		}
   144  	}
   145  	return &v1.Init{
   146  		Backend: contractBackEnd,
   147  	}
   148  }
   149  
   150  func (p *PermissionCtrl) NewPermissionRoleService(txa ethapi.SendTxArgs) (ptype.RoleService, error) {
   151  	transactOpts, err := p.getTxParams(txa)
   152  	if err != nil {
   153  		return nil, err
   154  	}
   155  	return p.backend.GetRoleService(transactOpts, p.getContractBackend())
   156  }
   157  
   158  func (p *PermissionCtrl) NewPermissionOrgService(txa ethapi.SendTxArgs) (ptype.OrgService, error) {
   159  	transactOpts, err := p.getTxParams(txa)
   160  	if err != nil {
   161  		return nil, err
   162  	}
   163  	return p.backend.GetOrgService(transactOpts, p.getContractBackend())
   164  }
   165  
   166  func (p *PermissionCtrl) NewPermissionNodeService(txa ethapi.SendTxArgs) (ptype.NodeService, error) {
   167  	transactOpts, err := p.getTxParams(txa)
   168  	if err != nil {
   169  		return nil, err
   170  	}
   171  	return p.backend.GetNodeService(transactOpts, p.getContractBackend())
   172  }
   173  
   174  func (p *PermissionCtrl) NewPermissionAccountService(txa ethapi.SendTxArgs) (ptype.AccountService, error) {
   175  	transactOpts, err := p.getTxParams(txa)
   176  	if err != nil {
   177  		return nil, err
   178  	}
   179  	return p.backend.GetAccountService(transactOpts, p.getContractBackend())
   180  }
   181  
   182  func (p *PermissionCtrl) NewPermissionAuditService() (ptype.AuditService, error) {
   183  	return p.backend.GetAuditService(p.getContractBackend())
   184  }
   185  
   186  func (p *PermissionCtrl) NewPermissionControlService() (ptype.ControlService, error) {
   187  	return p.backend.GetControlService(p.getContractBackend())
   188  }
   189  
   190  func (p *PermissionCtrl) getContractBackend() ptype.ContractBackend {
   191  	return ptype.ContractBackend{EthClnt: p.ethClnt, Key: p.key, PermConfig: p.permConfig, IsRaft: p.isRaft, UseDns: p.isRaft}
   192  }
   193  
   194  func (p *PermissionCtrl) ConnectionAllowed(_enodeId, _ip string, _port, _raftPort uint16) (bool, error) {
   195  	cs, err := p.backend.GetControlService(p.getContractBackend())
   196  	if err != nil {
   197  		return false, err
   198  	}
   199  	return cs.ConnectionAllowed(_enodeId, _ip, _port, _raftPort)
   200  }
   201  
   202  func (p *PermissionCtrl) IsTransactionAllowed(_sender common.Address, _target common.Address, _value *big.Int, _gasPrice *big.Int, _gasLimit *big.Int, _payload []byte, transactionType core.TransactionType) error {
   203  	// If permissions model is not in use return nil
   204  	if core.PermissionModel == core.Default {
   205  		return nil
   206  	}
   207  
   208  	cs, err := p.backend.GetControlService(p.getContractBackend())
   209  	if err != nil {
   210  		return err
   211  	}
   212  
   213  	return cs.TransactionAllowed(_sender, _target, _value, _gasPrice, _gasLimit, _payload, transactionType)
   214  }
   215  
   216  func (p *PermissionCtrl) populateBackEnd() error {
   217  	backend := ptype.NewInterfaceBackend(p.node, false, p.dataDir)
   218  
   219  	switch p.permConfig.PermissionsModel {
   220  	case ptype.PERMISSION_V2:
   221  		p.backend = &v2.Backend{
   222  			Ib: *backend,
   223  		}
   224  		log.Info("permission service: using v2 permissions model")
   225  		return nil
   226  
   227  	case ptype.PERMISSION_V1:
   228  		p.backend = &v1.Backend{
   229  			Ib: *backend,
   230  		}
   231  		log.Info("permission service: using v1 permissions model")
   232  		return nil
   233  
   234  	default:
   235  		return errors.New("permission: invalid permissions model passed")
   236  	}
   237  
   238  }
   239  
   240  func (p *PermissionCtrl) updateBackEnd() {
   241  	p.contract = NewPermissionContractService(p.ethClnt, p.IsV2Permission(), p.key, p.permConfig, p.isRaft, p.useDns)
   242  	switch p.IsV2Permission() {
   243  	case true:
   244  		p.backend.(*v2.Backend).Contr = p.contract.(*v2.Init)
   245  		p.backend.(*v2.Backend).Ib.SetIsRaft(p.isRaft)
   246  
   247  	default:
   248  		p.backend.(*v1.Backend).Contr = p.contract.(*v1.Init)
   249  		p.backend.(*v1.Backend).Ib.SetIsRaft(p.isRaft)
   250  	}
   251  }
   252  
   253  // validateAccount validates the account and returns the wallet associated with that for signing the transaction
   254  func (p *PermissionCtrl) validateAccount(from common.Address) (accounts.Wallet, error) {
   255  	acct := accounts.Account{Address: from}
   256  	w, err := p.eth.AccountManager().Find(acct)
   257  	if err != nil {
   258  		return nil, err
   259  	}
   260  	return w, nil
   261  }
   262  
   263  // getTxParams extracts the transaction related parameters
   264  func (p *PermissionCtrl) getTxParams(txa ethapi.SendTxArgs) (*bind.TransactOpts, error) {
   265  	w, err := p.validateAccount(txa.From)
   266  	if err != nil {
   267  		return nil, ptype.ErrInvalidAccount
   268  	}
   269  	fromAcct := accounts.Account{Address: txa.From}
   270  	transactOpts := bind.NewWalletTransactor(w, fromAcct)
   271  
   272  	transactOpts.GasPrice = defaultGasPrice
   273  	if txa.GasPrice != nil {
   274  		transactOpts.GasPrice = txa.GasPrice.ToInt()
   275  	}
   276  
   277  	transactOpts.GasLimit = defaultGasLimit
   278  	if txa.Gas != nil {
   279  		transactOpts.GasLimit = uint64(*txa.Gas)
   280  	}
   281  	transactOpts.From = fromAcct.Address
   282  
   283  	return transactOpts, nil
   284  }