Skip to content

Plugin Development

We leverage HashiCorp’s go-plugin to enable our plugin-based architecture using gRPC.

We recommend reading the go-plugin gRPC examples. Some advanced topics which are not available in the go-plugin documentation will be covered here.

Life Cycle

A plugin is started as a separate process and communicates with the Quorum client host process via gRPC service interfaces. This is done over a mutually-authenticated TLS connection on the local machine. The implementation is done inside go-plugin library. Usage is simplest when developing plugins in Golang. For plugins written in other languages, plugin authors need to have an understanding of the following lifecycle (see Advanced topics for non-Go plugins for more info):

  1. geth looks for the plugin distribution file after reading the plugin definition from settings
  2. geth verifies the plugin distribution file integrity
  3. geth generates a self-signed certificate (aka client certificate)
  4. geth spawns the plugin with the client certificate
  5. The plugin imports the client certificate and generates a self-signed server certificate for its RPC server
  6. The plugin includes the RPC server certificate in the handshake
  7. geth imports the plugin RPC server certificate
  8. geth and the plugin communicate via RPC over TLS using mutual TLS

Each plugin must implement the PluginInitializer gRPC service interface. After the plugin process is successfully started and connection with the Quorum client is successfully established, Quorum client invokes Init() gRPC method in order to initialize the plugin with configuration data read from the plugin definition’s config field in settings file.

Distribution

File format

Plugin distribution file must be a ZIP file. File name format is <name>-<version>.zip. <name> and <version> must be the same as the values defined in the PluginDefinition object in the settings file.

Metadata

A plugin metadata file plugin-meta.json must be included in the distribution ZIP file. plugin-meta.json contains a valid JSON object which has a flat structure with key value pairs.

Although the JSON object can include any desired information. There are mandatory key value pairs which must be present.

{
    "name": string,
    "version": string,
    "entrypoint": string,
    "parameters": array(string),
    ...
}
Fields Description
name (Required) Name of the plugin
version (Required) Version of the plugin
entrypoint (Required) Command to execute the plugin process
parameters (Optional) Command parameters to be passed to the plugin process

E.g.:

{
  "name": "quorum-plugin-helloWorld",
  "version": "1.0.0",
  "entrypoint": "helloWorldPlugin"
}

Advanced topics for non-Go plugins

Writing non-Go plugins is well-documented in go-plugin Github. Some additional advanced topics are described here.

Magic Cookie key and value are used as a very basic verification that a plugin is intended to be launched. This is not a security measure, just a UX feature.

Magic Cookie key and value are injected as an environment variable while executing the plugin process.

QUORUM_PLUGIN_MAGIC_COOKIE="CB9F51969613126D93468868990F77A8470EB9177503C5A38D437FEFF7786E0941152E05C06A9A3313391059132A7F9CED86C0783FE63A8B38F01623C8257664"

The plugin and the Quorum client’s magic cookies are compared. If they are equal then the plugin is loaded. If they are not equal, the plugin should show human-friendly output.

Mutual TLS Authentication

The Quorum client requires the plugin to authenticate and secure the connection via mutual TLS. PLUGIN_CLIENT_CERT environment variable is populated with Quorum Client certificate (in PEM format). A plugin would need to include this certificate to its trusted certificate pool, then generate a self-signed certificate and append the base64-encoded value of the certificate (in DER format) in the handshake message.

init.proto

It is mandatory that every plugin must implement this RPC service

Via this service, plugins receive a raw configuration sent by geth. It’s up to the plugin to interpret and parse the configuration then do the initialization to make sure the plugin is ready to serve

Services

PluginInitializer

Required RPC service to initialize the plugin after plugin process is started successfully

Method Name Request Type Response Type Description
Init PluginInitialization.Request PluginInitialization.Response

Messsages

PluginInitialization

A wrapper message to logically group other messages

PluginInitialization.Request

Initialization data for the plugin

Field Type Label Description
hostIdentity string geth node identity
rawConfiguration bytes Raw configuration to be processed by the plugin

PluginInitialization.Response

Examples

Please visit Overview page for a built-in HelloWorld plugin example.