github.com/corverroos/quorum@v21.1.0+incompatible/plugin/service.go (about)

     1  package plugin
     2  
     3  import (
     4  	"fmt"
     5  	"reflect"
     6  	"sync"
     7  	"unsafe"
     8  
     9  	"github.com/ethereum/go-ethereum/accounts/pluggable"
    10  	"github.com/ethereum/go-ethereum/log"
    11  	"github.com/ethereum/go-ethereum/p2p"
    12  	"github.com/ethereum/go-ethereum/rpc"
    13  )
    14  
    15  // this implements geth service
    16  type PluginManager struct {
    17  	nodeName           string // geth node name
    18  	pluginBaseDir      string // base directory for all the plugins
    19  	verifier           Verifier
    20  	centralClient      *CentralClient
    21  	downloader         *Downloader
    22  	settings           *Settings
    23  	mux                sync.Mutex                            // control concurrent access to plugins cache
    24  	plugins            map[PluginInterfaceName]managedPlugin // lazy load the actual plugin templates
    25  	initializedPlugins map[PluginInterfaceName]managedPlugin // prepopulate during initialization of plugin manager, needed for starting/stopping/getting info
    26  }
    27  
    28  func (s *PluginManager) Protocols() []p2p.Protocol { return nil }
    29  
    30  // this is called after PluginManager service has been successfully started
    31  // See node/node.go#Start()
    32  func (s *PluginManager) APIs() []rpc.API {
    33  	return append([]rpc.API{
    34  		{
    35  			Namespace: "admin",
    36  			Service:   NewPluginManagerAPI(s),
    37  			Version:   "1.0",
    38  			Public:    false,
    39  		},
    40  	}, s.delegateAPIs()...)
    41  }
    42  
    43  func (s *PluginManager) Start(_ *p2p.Server) (err error) {
    44  	log.Info("Starting all plugins", "count", len(s.initializedPlugins))
    45  	startedPlugins := make([]managedPlugin, 0, len(s.initializedPlugins))
    46  	for _, p := range s.initializedPlugins {
    47  		if err = p.Start(); err != nil {
    48  			break
    49  		} else {
    50  			startedPlugins = append(startedPlugins, p)
    51  		}
    52  	}
    53  	if err != nil {
    54  		for _, p := range startedPlugins {
    55  			_ = p.Stop()
    56  		}
    57  	}
    58  	return
    59  }
    60  
    61  func (s *PluginManager) getPlugin(name PluginInterfaceName) (managedPlugin, bool) {
    62  	s.mux.Lock()
    63  	defer s.mux.Unlock()
    64  	p, ok := s.plugins[name] // check if it's been used before
    65  	if !ok {
    66  		p, ok = s.initializedPlugins[name] // check if it's been initialized before
    67  	}
    68  	return p, ok
    69  }
    70  
    71  // Check if a plugin is enabled/setup
    72  func (s *PluginManager) IsEnabled(name PluginInterfaceName) bool {
    73  	_, ok := s.initializedPlugins[name]
    74  	return ok
    75  }
    76  
    77  // store the plugin instance to the value of the pointer v and cache it
    78  // this function makes sure v value will never be nil
    79  func (s *PluginManager) GetPluginTemplate(name PluginInterfaceName, v managedPlugin) error {
    80  	rv := reflect.ValueOf(v)
    81  	if rv.Kind() != reflect.Ptr || rv.IsNil() {
    82  		return fmt.Errorf("invalid argument value, expected a pointer but got %s", reflect.TypeOf(v))
    83  	}
    84  	recoverToErrorFunc := func(f func()) (err error) {
    85  		defer func() {
    86  			if r := recover(); r != nil {
    87  				err = fmt.Errorf("%s", r)
    88  			}
    89  		}()
    90  		f()
    91  		return
    92  	}
    93  	if p, ok := s.plugins[name]; ok {
    94  		return recoverToErrorFunc(func() {
    95  			cachedValue := reflect.ValueOf(p)
    96  			rv.Elem().Set(cachedValue.Elem())
    97  		})
    98  	}
    99  	base, ok := s.initializedPlugins[name]
   100  	if !ok {
   101  		return fmt.Errorf("plugin: [%s] is not found", name)
   102  	}
   103  	if err := recoverToErrorFunc(func() {
   104  		basePluginValue := reflect.ValueOf(base)
   105  		// the first field in the plugin template object is the basePlugin
   106  		// it indicates that the plugin template "extends" basePlugin
   107  		basePluginField := rv.Elem().FieldByName("basePlugin")
   108  		if !basePluginField.IsValid() || basePluginField.Type() != basePluginPointerType {
   109  			panic(fmt.Sprintf("plugin template must extend *basePlugin"))
   110  		}
   111  		// need to have write access to the unexported field in the target object
   112  		basePluginField = reflect.NewAt(basePluginField.Type(), unsafe.Pointer(basePluginField.UnsafeAddr())).Elem()
   113  		basePluginField.Set(basePluginValue)
   114  	}); err != nil {
   115  		return err
   116  	}
   117  	s.mux.Lock()
   118  	defer s.mux.Unlock()
   119  	s.plugins[name] = v
   120  	return nil
   121  }
   122  
   123  func (s *PluginManager) Stop() error {
   124  	log.Info("Stopping all plugins", "count", len(s.initializedPlugins))
   125  	allErrors := make([]error, 0)
   126  	for _, p := range s.initializedPlugins {
   127  		if err := p.Stop(); err != nil {
   128  			allErrors = append(allErrors, err)
   129  		}
   130  	}
   131  	log.Info("All plugins stopped", "errors", allErrors)
   132  	if len(allErrors) == 0 {
   133  		return nil
   134  	}
   135  	return fmt.Errorf("%s", allErrors)
   136  }
   137  
   138  // Provide details of current plugins being used
   139  func (s *PluginManager) PluginsInfo() interface{} {
   140  	info := make(map[PluginInterfaceName]interface{})
   141  	if len(s.initializedPlugins) == 0 {
   142  		return info
   143  	}
   144  	info["baseDir"] = s.pluginBaseDir
   145  	for _, p := range s.initializedPlugins {
   146  		k, v := p.Info()
   147  		info[k] = v
   148  	}
   149  	return info
   150  }
   151  
   152  // AddAccountPluginToBackend adds the account plugin to the provided account backend
   153  func (s *PluginManager) AddAccountPluginToBackend(b *pluggable.Backend) error {
   154  	v := new(ReloadableAccountServiceFactory)
   155  	if err := s.GetPluginTemplate(AccountPluginInterfaceName, v); err != nil {
   156  		return err
   157  	}
   158  	service, err := v.Create()
   159  	if err != nil {
   160  		return err
   161  	}
   162  	if err := b.SetPluginService(service); err != nil {
   163  		return err
   164  	}
   165  	return nil
   166  }
   167  
   168  func (s *PluginManager) Reload(name PluginInterfaceName) (bool, error) {
   169  	p, ok := s.getPlugin(name)
   170  	if !ok {
   171  		return false, fmt.Errorf("no such plugin provider: %s", name)
   172  	}
   173  	_ = p.Stop()
   174  	if err := p.Start(); err != nil {
   175  		return false, err
   176  	}
   177  	return true, nil
   178  }
   179  
   180  // this is to configure delegate APIs call to the plugins
   181  func (s *PluginManager) delegateAPIs() []rpc.API {
   182  	apis := make([]rpc.API, 0)
   183  	for _, p := range s.initializedPlugins {
   184  		interfaceName, _ := p.Info()
   185  		if pluginProvider, ok := pluginProviders[interfaceName]; ok {
   186  			if pluginProvider.apiProviderFunc != nil {
   187  				namespace := fmt.Sprintf("plugin@%s", interfaceName)
   188  				log.Debug("adding RPC API delegate for plugin", "provider", interfaceName, "namespace", namespace)
   189  				if delegates, err := pluginProvider.apiProviderFunc(namespace, s); err != nil {
   190  					log.Error("unable to delegate RPC API calls to plugin", "provider", interfaceName, "error", err)
   191  				} else {
   192  					apis = append(apis, delegates...)
   193  				}
   194  			}
   195  		}
   196  	}
   197  	return apis
   198  }
   199  
   200  func NewPluginManager(nodeName string, settings *Settings, skipVerify bool, localVerify bool, publicKey string) (*PluginManager, error) {
   201  	pm := &PluginManager{
   202  		nodeName:           nodeName,
   203  		pluginBaseDir:      settings.BaseDir.String(),
   204  		centralClient:      NewPluginCentralClient(settings.CentralConfig),
   205  		plugins:            make(map[PluginInterfaceName]managedPlugin),
   206  		initializedPlugins: make(map[PluginInterfaceName]managedPlugin),
   207  		settings:           settings,
   208  	}
   209  	pm.downloader = NewDownloader(pm)
   210  	if skipVerify {
   211  		log.Warn("plugin: ignore integrity verification")
   212  		pm.verifier = NewNonVerifier()
   213  	} else {
   214  		var err error
   215  		if pm.verifier, err = NewVerifier(pm, localVerify, publicKey); err != nil {
   216  			return nil, err
   217  		}
   218  	}
   219  	for pluginName, pluginDefinition := range settings.Providers {
   220  		log.Debug("Preparing plugin", "provider", pluginName, "name", pluginDefinition.Name, "version", pluginDefinition.Version)
   221  		pluginProvider, ok := pluginProviders[pluginName]
   222  		if !ok {
   223  			return nil, fmt.Errorf("plugin: [%s] is not supported", pluginName)
   224  		}
   225  		base, err := newBasePlugin(pm, pluginName, pluginDefinition, pluginProvider.pluginSet)
   226  		if err != nil {
   227  			return nil, fmt.Errorf("plugin [%s] %s", pluginName, err.Error())
   228  		}
   229  		pm.initializedPlugins[pluginName] = base
   230  	}
   231  	return pm, nil
   232  }
   233  
   234  func NewEmptyPluginManager() *PluginManager {
   235  	return &PluginManager{
   236  		plugins: make(map[PluginInterfaceName]managedPlugin),
   237  	}
   238  }