Skip to content

Latest commit

 

History

History
45 lines (33 loc) · 3.62 KB

plugin.md

File metadata and controls

45 lines (33 loc) · 3.62 KB

How plugins work

All plugins in the libraries/plugins directory are iterated over by CMakeLists.txt. The manifest directory iterates through all plugins, adding them to the steem_plugins build target. Any other build target wanting to access all plugins available at build time should link to this target.

There is a plugin in example_plugins called example_api_plugin which is a working example of adding a custom API call.

Registering plugins

  • Plugins are enabled with the plugins config file option.
  • By default, steemd runs the chain, p2p, and webserver plugins.
  • Some plugins may keep records in the database (such as account_history). If you change whether such a plugin is disabled/enabled, you should also replay the chain. Detecting this situation and automatically replaying when needed will be implemented in a future release.
  • To make an API visible, include the associated plugin in the plugins config file option. Only APIs explicitly made available through the config will be registered.

Autogenerating code

A skeleton structure containing much of the boilerplate of creating a new plugin with an API can be autogenerated by running programs/util/newplugin.py.

  • Register signal handlers and custom evaluators in plugin_initialize() (if needed)
  • Register APIs in plugin_initialize()
  • API plugins should be separate from the stateful plugin they grant access to. This allows for the API to be disabled while keeping track of state for the plugin.

Startup/Shutdown of Plugins

  • Plugins can specify dependencies with the APPBASE_PLUGIN_REQUIRES macro, which takes a bubble list of dependencies.
  • There is undefined behavior if there are circular dependencies. Be careful how you design the data flow between plugins to eliminate circular dependencies.
  • plugin_initialze and plugin_startup both guarantee that any dependencies are already initialized or started before the dependent plugin is called.
  • plugin_shutdown is called in the reverse order from startup. Any dependencies will still be running when shutdown is called.
  • You can get a reference to a plugin with appbase::app().get_plugin< PLUIGN >() or a pointer with appbase::app().find_plugin< PLUGIN >(). get_plugin will fail and find_plugin will return a nullptr if the plugin is not registered or has not been initialized. These methods guarantee you are accessing initialized date.
  • Because of the inialization order, it is safe to call get/find_plugin on dependencies in initialization, startup, and shutdown.
  • It is only safe to call get/find_plugin on an optional dependency in startup. An optional dependency is not explicitly specified. It is simply some optional behavior if a plugin is enabled. See condenser_api for an example of optional dependencies.

Asynchronous APIs

-The json rpc plugin dispatches API requests asynchronously. This means your API call can be preempted or delayed and must be designed with parallelism in mind.

  • To help, chainbase provides a simple read/write locking mechanism: with_read_lock and with_write_lock.
  • This is a global lock over the entire database.
  • The methods take a lambda that will be protected with the lock. For most API calls, with_read_lock will be sufficient.
  • To ensure consistent block times, the read lock automatically expires after 1 second. Design your API call with this in mind. If the API call takes longer than 1 second, your results are undefined. It is best to create limitations on the API call to ensure it does not take longer than 1 second to execute (shorter than 250ms is preferable).