123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804 |
- // Copyright 2015 The go-ethereum Authors
- // This file is part of the go-ethereum library.
- //
- // The go-ethereum library is free software: you can redistribute it and/or modify
- // it under the terms of the GNU Lesser General Public License as published by
- // the Free Software Foundation, either version 3 of the License, or
- // (at your option) any later version.
- //
- // The go-ethereum library is distributed in the hope that it will be useful,
- // but WITHOUT ANY WARRANTY; without even the implied warranty of
- // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- // GNU Lesser General Public License for more details.
- //
- // You should have received a copy of the GNU Lesser General Public License
- // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
- package node
- import (
- "crypto/ecdsa"
- "errors"
- "fmt"
- "net/http"
- "os"
- "path/filepath"
- "reflect"
- "strings"
- "sync"
- "github.com/ethereum/go-ethereum/accounts"
- "github.com/ethereum/go-ethereum/core/rawdb"
- "github.com/ethereum/go-ethereum/core/types"
- "github.com/ethereum/go-ethereum/ethdb"
- "github.com/ethereum/go-ethereum/event"
- "github.com/ethereum/go-ethereum/log"
- "github.com/ethereum/go-ethereum/p2p"
- "github.com/ethereum/go-ethereum/plugin"
- "github.com/ethereum/go-ethereum/plugin/security"
- "github.com/ethereum/go-ethereum/rpc"
- "github.com/prometheus/tsdb/fileutil"
- )
- // Node is a container on which services can be registered.
- type Node struct {
- eventmux *event.TypeMux
- config *Config
- accman *accounts.Manager
- log log.Logger
- ephemKeystore string // if non-empty, the key directory that will be removed by Stop
- dirLock fileutil.Releaser // prevents concurrent use of instance directory
- stop chan struct{} // Channel to wait for termination notifications
- server *p2p.Server // Currently running P2P networking layer
- qserver *p2p.Server // Currently running P2P networking layer for QLight
- startStopLock sync.Mutex // Start/Stop are protected by an additional lock
- state int // Tracks state of node lifecycle
- lock sync.Mutex
- lifecycles []Lifecycle // All registered backends, services, and auxiliary services that have a lifecycle
- rpcAPIs []rpc.API // List of APIs currently provided by the node
- http *httpServer //
- ws *httpServer //
- ipc *ipcServer // Stores information about the ipc http server
- inprocHandler *rpc.Server // In-process RPC request handler to process the API requests
- databases map[*closeTrackingDB]struct{} // All open databases
- // Quorum
- pluginManager *plugin.PluginManager // Manage all plugins for this node. If plugin is not enabled, an EmptyPluginManager is set.
- // End Quorum
- }
- const (
- initializingState = iota
- runningState
- closedState
- )
- // New creates a new P2P node, ready for protocol registration.
- func New(conf *Config) (*Node, error) {
- // Copy config and resolve the datadir so future changes to the current
- // working directory don't affect the node.
- confCopy := *conf
- conf = &confCopy
- if conf.DataDir != "" {
- absdatadir, err := filepath.Abs(conf.DataDir)
- if err != nil {
- return nil, err
- }
- conf.DataDir = absdatadir
- }
- if conf.Logger == nil {
- conf.Logger = log.New()
- }
- // Ensure that the instance name doesn't cause weird conflicts with
- // other files in the data directory.
- if strings.ContainsAny(conf.Name, `/\`) {
- return nil, errors.New(`Config.Name must not contain '/' or '\'`)
- }
- if conf.Name == datadirDefaultKeyStore {
- return nil, errors.New(`Config.Name cannot be "` + datadirDefaultKeyStore + `"`)
- }
- if strings.HasSuffix(conf.Name, ".ipc") {
- return nil, errors.New(`Config.Name cannot end in ".ipc"`)
- }
- node := &Node{
- config: conf,
- inprocHandler: rpc.NewProtectedServer(nil, conf.EnableMultitenancy),
- eventmux: new(event.TypeMux),
- log: conf.Logger,
- stop: make(chan struct{}),
- server: &p2p.Server{Config: conf.P2P},
- databases: make(map[*closeTrackingDB]struct{}),
- pluginManager: plugin.NewEmptyPluginManager(),
- }
- if conf.QP2P != nil {
- node.qserver = &p2p.Server{Config: *conf.QP2P}
- }
- // Register built-in APIs.
- node.rpcAPIs = append(node.rpcAPIs, node.apis()...)
- // Acquire the instance directory lock.
- if err := node.openDataDir(); err != nil {
- return nil, err
- }
- // Ensure that the AccountManager method works before the node has started. We rely on
- // this in cmd/geth.
- am, ephemeralKeystore, err := makeAccountManager(conf)
- if err != nil {
- return nil, err
- }
- node.accman = am
- node.ephemKeystore = ephemeralKeystore
- // Initialize the p2p server. This creates the node key and discovery databases.
- node.server.Config.PrivateKey = node.config.NodeKey()
- node.server.Config.Name = node.config.NodeName()
- node.server.Config.Logger = node.log
- if node.server.Config.StaticNodes == nil {
- node.server.Config.StaticNodes = node.config.StaticNodes()
- }
- if node.server.Config.TrustedNodes == nil {
- node.server.Config.TrustedNodes = node.config.TrustedNodes()
- }
- if node.server.Config.NodeDatabase == "" {
- node.server.Config.NodeDatabase = node.config.NodeDB()
- }
- if node.qserver != nil {
- node.qserver.Config.PrivateKey = node.config.NodeKey()
- node.qserver.Config.Name = "qgeth"
- node.qserver.Config.Logger = node.log
- node.qserver.Config.NodeDatabase = node.config.QNodeDB()
- node.qserver.Config.DataDir = node.config.DataDir
- }
- // Check HTTP/WS prefixes are valid.
- if err := validatePrefix("HTTP", conf.HTTPPathPrefix); err != nil {
- return nil, err
- }
- if err := validatePrefix("WebSocket", conf.WSPathPrefix); err != nil {
- return nil, err
- }
- // Quorum
- node.server.Config.EnableNodePermission = node.config.EnableNodePermission
- node.server.Config.DataDir = node.config.DataDir
- // End Quorum
- // Check HTTP/WS prefixes are valid.
- if err := validatePrefix("HTTP", conf.HTTPPathPrefix); err != nil {
- return nil, err
- }
- if err := validatePrefix("WebSocket", conf.WSPathPrefix); err != nil {
- return nil, err
- }
- // Configure RPC servers.
- node.http = newHTTPServer(node.log, conf.HTTPTimeouts).withMultitenancy(node.config.EnableMultitenancy)
- node.ws = newHTTPServer(node.log, rpc.DefaultHTTPTimeouts).withMultitenancy(node.config.EnableMultitenancy)
- node.ipc = newIPCServer(node.log, conf.IPCEndpoint()).withMultitenancy(node.config.EnableMultitenancy)
- return node, nil
- }
- // Start starts all registered lifecycles, RPC services and p2p networking.
- // Node can only be started once.
- func (n *Node) Start() error {
- n.startStopLock.Lock()
- defer n.startStopLock.Unlock()
- n.lock.Lock()
- switch n.state {
- case runningState:
- n.lock.Unlock()
- return ErrNodeRunning
- case closedState:
- n.lock.Unlock()
- return ErrNodeStopped
- }
- n.state = runningState
- // Quorum
- // Start the plugin manager before as might be needed for TLS and Auth manager for networking/rpc.
- if err := n.PluginManager().Start(); err != nil {
- n.doClose(nil)
- return err
- }
- // End Quorum
- // open networking and RPC endpoints
- err := n.openEndpoints()
- lifecycles := make([]Lifecycle, len(n.lifecycles))
- copy(lifecycles, n.lifecycles)
- n.lock.Unlock()
- // Check if endpoint startup failed.
- if err != nil {
- n.doClose(nil)
- return err
- }
- // Start all registered lifecycles.
- var started []Lifecycle
- for _, lifecycle := range lifecycles {
- if err = lifecycle.Start(); err != nil {
- break
- }
- started = append(started, lifecycle)
- }
- // Check if any lifecycle failed to start.
- if err != nil {
- n.stopServices(started)
- n.doClose(nil)
- }
- return err
- }
- // Close stops the Node and releases resources acquired in
- // Node constructor New.
- func (n *Node) Close() error {
- n.startStopLock.Lock()
- defer n.startStopLock.Unlock()
- n.lock.Lock()
- state := n.state
- n.lock.Unlock()
- switch state {
- case initializingState:
- // The node was never started.
- return n.doClose(nil)
- case runningState:
- // The node was started, release resources acquired by Start().
- var errs []error
- if err := n.stopServices(n.lifecycles); err != nil {
- errs = append(errs, err)
- }
- return n.doClose(errs)
- case closedState:
- return ErrNodeStopped
- default:
- panic(fmt.Sprintf("node is in unknown state %d", state))
- }
- }
- // doClose releases resources acquired by New(), collecting errors.
- func (n *Node) doClose(errs []error) error {
- // Close databases. This needs the lock because it needs to
- // synchronize with OpenDatabase*.
- n.lock.Lock()
- n.state = closedState
- errs = append(errs, n.closeDatabases()...)
- n.lock.Unlock()
- if err := n.accman.Close(); err != nil {
- errs = append(errs, err)
- }
- if n.ephemKeystore != "" {
- if err := os.RemoveAll(n.ephemKeystore); err != nil {
- errs = append(errs, err)
- }
- }
- // Release instance directory lock.
- n.closeDataDir()
- // Unblock n.Wait.
- close(n.stop)
- // Report any errors that might have occurred.
- switch len(errs) {
- case 0:
- return nil
- case 1:
- return errs[0]
- default:
- return fmt.Errorf("%v", errs)
- }
- }
- // openEndpoints starts all network and RPC endpoints.
- func (n *Node) openEndpoints() error {
- // start networking endpoints
- n.log.Info("Starting peer-to-peer node", "instance", n.server.Name)
- if err := n.server.Start(); err != nil {
- return convertFileLockError(err)
- }
- // Quorum
- if n.qserver != nil {
- if err := n.qserver.Start(); err != nil {
- return convertFileLockError(err)
- }
- }
- // End Quorum
- // start RPC endpoints
- err := n.startRPC()
- if err != nil {
- n.stopRPC()
- n.server.Stop()
- }
- return err
- }
- // containsLifecycle checks if 'lfs' contains 'l'.
- func containsLifecycle(lfs []Lifecycle, l Lifecycle) bool {
- for _, obj := range lfs {
- if obj == l {
- return true
- }
- }
- return false
- }
- // stopServices terminates running services, RPC and p2p networking.
- // It is the inverse of Start.
- func (n *Node) stopServices(running []Lifecycle) error {
- n.stopRPC()
- // Stop running lifecycles in reverse order.
- failure := &StopError{Services: make(map[reflect.Type]error)}
- // Quorum
- if err := n.PluginManager().Stop(); err != nil {
- failure.Services[reflect.TypeOf(n.PluginManager())] = err
- }
- // End Quorum
- for i := len(running) - 1; i >= 0; i-- {
- if err := running[i].Stop(); err != nil {
- failure.Services[reflect.TypeOf(running[i])] = err
- }
- }
- // Stop p2p networking.
- n.server.Stop()
- if n.qserver != nil {
- n.qserver.Stop()
- }
- if len(failure.Services) > 0 {
- return failure
- }
- return nil
- }
- func (n *Node) openDataDir() error {
- if n.config.DataDir == "" {
- return nil // ephemeral
- }
- instdir := filepath.Join(n.config.DataDir, n.config.name())
- if err := os.MkdirAll(instdir, 0700); err != nil {
- return err
- }
- // Lock the instance directory to prevent concurrent use by another instance as well as
- // accidental use of the instance directory as a database.
- release, _, err := fileutil.Flock(filepath.Join(instdir, "LOCK"))
- if err != nil {
- return convertFileLockError(err)
- }
- n.dirLock = release
- return nil
- }
- func (n *Node) closeDataDir() {
- // Release instance directory lock.
- if n.dirLock != nil {
- if err := n.dirLock.Release(); err != nil {
- n.log.Error("Can't release datadir lock", "err", err)
- }
- n.dirLock = nil
- }
- }
- // configureRPC is a helper method to configure all the various RPC endpoints during node
- // startup. It's not meant to be called at any time afterwards as it makes certain
- // assumptions about the state of the node.
- // Quorum
- // 1. Inject mutlitenancy flag into rpc server when appropriate
- func (n *Node) startRPC() error {
- if err := n.startInProc(); err != nil {
- return err
- }
- // Configure IPC.
- if n.ipc.endpoint != "" {
- if err := n.ipc.start(n.rpcAPIs); err != nil {
- return err
- }
- }
- tls, auth, err := n.GetSecuritySupports()
- if err != nil {
- return err
- }
- // Configure HTTP.
- if n.config.HTTPHost != "" {
- config := httpConfig{
- CorsAllowedOrigins: n.config.HTTPCors,
- Vhosts: n.config.HTTPVirtualHosts,
- Modules: n.config.HTTPModules,
- prefix: n.config.HTTPPathPrefix,
- }
- server := n.http
- if err := server.setListenAddr(n.config.HTTPHost, n.config.HTTPPort); err != nil {
- return err
- }
- if err := server.enableRPC(n.rpcAPIs, config, auth); err != nil {
- return err
- }
- }
- // Configure WebSocket.
- if n.config.WSHost != "" {
- server := n.wsServerForPort(n.config.WSPort)
- config := wsConfig{
- Modules: n.config.WSModules,
- Origins: n.config.WSOrigins,
- prefix: n.config.WSPathPrefix,
- }
- if err := server.setListenAddr(n.config.WSHost, n.config.WSPort); err != nil {
- return err
- }
- if err := server.enableWS(n.rpcAPIs, config, auth); err != nil {
- return err
- }
- }
- if err := n.http.start(tls); err != nil {
- return err
- }
- return n.ws.start(tls)
- }
- func (n *Node) wsServerForPort(port int) *httpServer {
- if n.config.HTTPHost == "" || n.http.port == port {
- return n.http
- }
- return n.ws
- }
- func (n *Node) stopRPC() {
- n.http.stop()
- n.ws.stop()
- n.ipc.stop()
- n.stopInProc()
- }
- // startInProc registers all RPC APIs on the inproc server.
- // Quorum
- // 1. Inject mutlitenancy flag into rpc server
- func (n *Node) startInProc() error {
- for _, api := range n.rpcAPIs {
- if err := n.inprocHandler.RegisterName(api.Namespace, api.Service); err != nil {
- return err
- }
- }
- return n.eventmux.Post(rpc.InProcServerReadyEvent{})
- }
- // stopInProc terminates the in-process RPC endpoint.
- func (n *Node) stopInProc() {
- n.inprocHandler.Stop()
- }
- // Wait blocks until the node is closed.
- func (n *Node) Wait() {
- <-n.stop
- }
- // RegisterLifecycle registers the given Lifecycle on the node.
- func (n *Node) RegisterLifecycle(lifecycle Lifecycle) {
- n.lock.Lock()
- defer n.lock.Unlock()
- if n.state != initializingState {
- panic("can't register lifecycle on running/stopped node")
- }
- if containsLifecycle(n.lifecycles, lifecycle) {
- panic(fmt.Sprintf("attempt to register lifecycle %T more than once", lifecycle))
- }
- n.lifecycles = append(n.lifecycles, lifecycle)
- }
- // RegisterProtocols adds backend's protocols to the node's p2p server.
- func (n *Node) RegisterProtocols(protocols []p2p.Protocol) {
- n.lock.Lock()
- defer n.lock.Unlock()
- if n.state != initializingState {
- panic("can't register protocols on running/stopped node")
- }
- n.server.Protocols = append(n.server.Protocols, protocols...)
- }
- func (n *Node) RegisterQProtocols(protocols []p2p.Protocol) {
- n.lock.Lock()
- defer n.lock.Unlock()
- if n.state != initializingState {
- panic("can't register protocols on running/stopped node")
- }
- n.qserver.Protocols = append(n.qserver.Protocols, protocols...)
- }
- // RegisterAPIs registers the APIs a service provides on the node.
- func (n *Node) RegisterAPIs(apis []rpc.API) {
- n.lock.Lock()
- defer n.lock.Unlock()
- if n.state != initializingState {
- panic("can't register APIs on running/stopped node")
- }
- n.rpcAPIs = append(n.rpcAPIs, apis...)
- }
- // RegisterHandler mounts a handler on the given path on the canonical HTTP server.
- //
- // The name of the handler is shown in a log message when the HTTP server starts
- // and should be a descriptive term for the service provided by the handler.
- func (n *Node) RegisterHandler(name, path string, handler http.Handler) {
- n.lock.Lock()
- defer n.lock.Unlock()
- if n.state != initializingState {
- panic("can't register HTTP handler on running/stopped node")
- }
- n.http.mux.Handle(path, handler)
- n.http.handlerNames[path] = name
- }
- // Attach creates an RPC client attached to an in-process API handler.
- func (n *Node) Attach() (*rpc.Client, error) {
- return rpc.DialInProc(n.inprocHandler), nil
- }
- // AttachWithPSI creates a PSI-specific RPC client attached to an in-process API handler.
- func (n *Node) AttachWithPSI(psi types.PrivateStateIdentifier) (*rpc.Client, error) {
- client, err := n.Attach()
- if err != nil {
- return nil, err
- }
- return client.WithPSI(psi), nil
- }
- // RPCHandler returns the in-process RPC request handler.
- func (n *Node) RPCHandler() (*rpc.Server, error) {
- n.lock.Lock()
- defer n.lock.Unlock()
- if n.state == closedState {
- return nil, ErrNodeStopped
- }
- return n.inprocHandler, nil
- }
- // Config returns the configuration of node.
- func (n *Node) Config() *Config {
- return n.config
- }
- // Server retrieves the currently running P2P network layer. This method is meant
- // only to inspect fields of the currently running server. Callers should not
- // start or stop the returned server.
- func (n *Node) Server() *p2p.Server {
- n.lock.Lock()
- defer n.lock.Unlock()
- return n.server
- }
- func (n *Node) QServer() *p2p.Server {
- n.lock.Lock()
- defer n.lock.Unlock()
- return n.qserver
- }
- // DataDir retrieves the current datadir used by the protocol stack.
- // Deprecated: No files should be stored in this directory, use InstanceDir instead.
- func (n *Node) DataDir() string {
- return n.config.DataDir
- }
- // InstanceDir retrieves the instance directory used by the protocol stack.
- func (n *Node) InstanceDir() string {
- return n.config.instanceDir()
- }
- // AccountManager retrieves the account manager used by the protocol stack.
- func (n *Node) AccountManager() *accounts.Manager {
- return n.accman
- }
- // IPCEndpoint retrieves the current IPC endpoint used by the protocol stack.
- func (n *Node) IPCEndpoint() string {
- return n.ipc.endpoint
- }
- // HTTPEndpoint returns the URL of the HTTP server. Note that this URL does not
- // contain the JSON-RPC path prefix set by HTTPPathPrefix.
- func (n *Node) HTTPEndpoint() string {
- return "http://" + n.http.listenAddr()
- }
- // WSEndpoint returns the current JSON-RPC over WebSocket endpoint.
- func (n *Node) WSEndpoint() string {
- if n.http.wsAllowed() {
- return "ws://" + n.http.listenAddr() + n.http.wsConfig.prefix
- }
- return "ws://" + n.ws.listenAddr() + n.ws.wsConfig.prefix
- }
- // EventMux retrieves the event multiplexer used by all the network services in
- // the current protocol stack.
- func (n *Node) EventMux() *event.TypeMux {
- return n.eventmux
- }
- // OpenDatabase opens an existing database with the given name (or creates one if no
- // previous can be found) from within the node's instance directory. If the node is
- // ephemeral, a memory database is returned.
- func (n *Node) OpenDatabase(name string, cache, handles int, namespace string, readonly bool) (ethdb.Database, error) {
- n.lock.Lock()
- defer n.lock.Unlock()
- if n.state == closedState {
- return nil, ErrNodeStopped
- }
- var db ethdb.Database
- var err error
- if n.config.DataDir == "" {
- db = rawdb.NewMemoryDatabase()
- } else {
- db, err = rawdb.NewLevelDBDatabase(n.ResolvePath(name), cache, handles, namespace, readonly)
- }
- if err == nil {
- db = n.wrapDatabase(db)
- }
- return db, err
- }
- // OpenDatabaseWithFreezer opens an existing database with the given name (or
- // creates one if no previous can be found) from within the node's data directory,
- // also attaching a chain freezer to it that moves ancient chain data from the
- // database to immutable append-only files. If the node is an ephemeral one, a
- // memory database is returned.
- func (n *Node) OpenDatabaseWithFreezer(name string, cache, handles int, freezer, namespace string, readonly bool) (ethdb.Database, error) {
- n.lock.Lock()
- defer n.lock.Unlock()
- if n.state == closedState {
- return nil, ErrNodeStopped
- }
- var db ethdb.Database
- var err error
- if n.config.DataDir == "" {
- db = rawdb.NewMemoryDatabase()
- } else {
- root := n.ResolvePath(name)
- switch {
- case freezer == "":
- freezer = filepath.Join(root, "ancient")
- case !filepath.IsAbs(freezer):
- freezer = n.ResolvePath(freezer)
- }
- db, err = rawdb.NewLevelDBDatabaseWithFreezer(root, cache, handles, freezer, namespace, readonly)
- }
- if err == nil {
- db = n.wrapDatabase(db)
- }
- return db, err
- }
- // ResolvePath returns the absolute path of a resource in the instance directory.
- func (n *Node) ResolvePath(x string) string {
- return n.config.ResolvePath(x)
- }
- // closeTrackingDB wraps the Close method of a database. When the database is closed by the
- // service, the wrapper removes it from the node's database map. This ensures that Node
- // won't auto-close the database if it is closed by the service that opened it.
- type closeTrackingDB struct {
- ethdb.Database
- n *Node
- }
- func (db *closeTrackingDB) Close() error {
- db.n.lock.Lock()
- delete(db.n.databases, db)
- db.n.lock.Unlock()
- return db.Database.Close()
- }
- // wrapDatabase ensures the database will be auto-closed when Node is closed.
- func (n *Node) wrapDatabase(db ethdb.Database) ethdb.Database {
- wrapper := &closeTrackingDB{db, n}
- n.databases[wrapper] = struct{}{}
- return wrapper
- }
- // closeDatabases closes all open databases.
- func (n *Node) closeDatabases() (errors []error) {
- for db := range n.databases {
- delete(n.databases, db)
- if err := db.Database.Close(); err != nil {
- errors = append(errors, err)
- }
- }
- return errors
- }
- // Quorum
- func (n *Node) GetSecuritySupports() (tlsConfigSource security.TLSConfigurationSource, authManager security.AuthenticationManager, err error) {
- if n.pluginManager.IsEnabled(plugin.SecurityPluginInterfaceName) {
- sp := new(plugin.SecurityPluginTemplate)
- if err = n.pluginManager.GetPluginTemplate(plugin.SecurityPluginInterfaceName, sp); err != nil {
- return
- }
- if tlsConfigSource, err = sp.TLSConfigurationSource(); err != nil {
- return
- }
- if authManager, err = sp.AuthenticationManager(); err != nil {
- return
- }
- } else {
- log.Info("Security Plugin is not enabled")
- }
- return
- }
- // Quorum
- //
- // delegate call to node.Config
- func (n *Node) IsPermissionEnabled() bool {
- return n.config.IsPermissionEnabled()
- }
- // Quorum
- //
- // delegate call to node.Config
- func (n *Node) GetNodeKey() *ecdsa.PrivateKey {
- return n.config.NodeKey()
- }
- // Quorum
- //
- // This can be used to inspect plugins used in the current node
- func (n *Node) PluginManager() *plugin.PluginManager {
- return n.pluginManager
- }
- // Quorum
- //
- // This can be used to set the plugin manager in the node (replacing the default Empty one)
- func (n *Node) SetPluginManager(pm *plugin.PluginManager) {
- n.pluginManager = pm
- }
- // Quorum
- //
- // Lifecycle retrieves a currently lifecycle registered of a specific type.
- func (n *Node) Lifecycle(lifecycle interface{}) error {
- n.lock.Lock()
- defer n.lock.Unlock()
- // Short circuit if the node's not running
- if n.server == nil {
- return ErrNodeStopped
- }
- // Otherwise try to find the service to return
- element := reflect.ValueOf(lifecycle).Elem()
- for _, runningLifecycle := range n.lifecycles {
- lElem := reflect.TypeOf(runningLifecycle)
- if lElem == element.Type() {
- element.Set(reflect.ValueOf(runningLifecycle))
- return nil
- }
- }
- return ErrServiceUnknown
- }
|