Update today, add hook writing guide
This commit is contained in:
parent
322eb88b8c
commit
9c6b92c284
@ -4,4 +4,102 @@
|
||||
Hook Writing Guide
|
||||
==================
|
||||
|
||||
.. todo:: Austin: guide to writing plugin hooks
|
||||
If you're trying to interact with Geth in a way not already supported by
|
||||
PluGeth, we're happy to accept pull requests adding new hooks so long as they
|
||||
comply with certain standards. We strongly encourage you to :ref:`contact us <contact>`
|
||||
first. We may have suggestions on how to do what you're trying to do without
|
||||
adding new hooks, or easier ways to implement hooks to get the information you
|
||||
need.
|
||||
|
||||
.. warning::
|
||||
|
||||
Plugin hooks *must not* require plugins to import any packages from ``github.com/ethereum/go-ethereum``.
|
||||
Doing so means that plugins must be recompiled for each version of Geth.
|
||||
Many types have been re-implemented in ``github.com/openrelayxyz/plugeth-utils``.
|
||||
If you need a type for your hook not already provided by plugeth-utils, you
|
||||
may make a pull request to that project as well.
|
||||
|
||||
When extending the plugin API, a primary concern is leaving a minimal footprint
|
||||
in the core Geth codebase to avoid future merge conflicts. To achieve this,
|
||||
when we want to add a hook within some existing Geth code, we create a
|
||||
plugin_hooks.go in the same package. For example, in the core/rawdb package we
|
||||
have:
|
||||
|
||||
|
||||
.. code-block:: Go
|
||||
|
||||
// This file is part of the package we are adding hooks to
|
||||
package rawdb
|
||||
|
||||
// Import whatever is necessary
|
||||
import (
|
||||
"github.com/ethereum/go-ethereum/plugins"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
)
|
||||
|
||||
|
||||
// PluginAppendAncient is the public plugin hook function, available for testing
|
||||
func PluginAppendAncient(pl *plugins.PluginLoader, number uint64, hash, header, body, receipts, td []byte) {
|
||||
fnList := pl.Lookup("AppendAncient", func(item interface{}) bool {
|
||||
_, ok := item.(func(number uint64, hash, header, body, receipts, td []byte))
|
||||
return ok
|
||||
})
|
||||
for _, fni := range fnList {
|
||||
if fn, ok := fni.(func(number uint64, hash, header, body, receipts, td []byte)); ok {
|
||||
fn(number, hash, header, body, receipts, td)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// pluginAppendAncient is the private plugin hook function
|
||||
func pluginAppendAncient(number uint64, hash, header, body, receipts, td []byte) {
|
||||
if plugins.DefaultPluginLoader == nil {
|
||||
log.Warn("Attempting AppendAncient, but default PluginLoader has not been initialized")
|
||||
return
|
||||
}
|
||||
PluginAppendAncient(plugins.DefaultPluginLoader, number, hash, header, body, receipts, td)
|
||||
}
|
||||
|
||||
The Public Plugin Hook Function
|
||||
*******************************
|
||||
|
||||
The public plugin hook function should follow the naming convention
|
||||
Plugin$HookName. The first argument should be a ``*plugins.PluginLoader``, followed
|
||||
by any arguments required by the functions to be provided by nay plugins
|
||||
implementing this hook.
|
||||
|
||||
The plugin hook function should use ``PluginLoader.Lookup("$HookName", func(item interface{}) bool``
|
||||
to get a list of the plugin-provided functions to be invoked. The provided
|
||||
function should verify that the provided function implements the expected
|
||||
interface. After the first time a given hook is looked up through the plugin
|
||||
loader, the PluginLoader will cache references to those hooks.
|
||||
|
||||
Given the function list provided by the plugin loader, the public plugin hook
|
||||
function should iterate over the list, cast the elements to the appropriate
|
||||
type, and call the function with the provided arguments.
|
||||
|
||||
Unless there is a clear justification to the contrary, the function should be
|
||||
called in the current goroutine. Plugins may choose to spawn off a separate
|
||||
goroutine as appropriate, but for the sake of thread safety we should generally
|
||||
not assume that plugins will be implemented in a threadsafe manner. If a plugin
|
||||
degrades the performance of Geth significantly, that will generally be obvious,
|
||||
and plugin authors can take appropriate measures to improve performance. If a
|
||||
plugin introduces thread safety issues, those can go unnoticed during testing.
|
||||
|
||||
The Private Plugin Hook Function
|
||||
********************************
|
||||
|
||||
The private plugin hook function should bear the same name as the public plugin
|
||||
hook function, but with a lower case first letter. The signature should match
|
||||
the public plugin hook function, except that the first argument referencing the
|
||||
PluginLoader should be removed. It should invoke the public plugin hook
|
||||
function on ``plugins.DefaultPluginLoader``. It should always verify that the
|
||||
DefaultPluginLoader is non-nil, log warning and return if the
|
||||
DefaultPluginLoader has not been initialized.
|
||||
|
||||
In-Line Invocation
|
||||
******************
|
||||
|
||||
Within the Geth codebase, the private plugin hook function should be invoked
|
||||
with the appropriate arguments in a single line, to minimize unexpected
|
||||
conflicts merging the upstream geth codebase into plugeth.
|
||||
|
@ -4,7 +4,7 @@
|
||||
Basic Types of Plugins
|
||||
======================
|
||||
|
||||
While PluGeth has been designed to be versatile and customizable, when learning the project it can be helpful to think of plugins as being of four different archetypes.
|
||||
While PluGeth has been designed to be versatile and customizable, when learning the project it can be helpful to think of plugins as being of four different archetypes.
|
||||
|
||||
.. contents:: :local:
|
||||
|
||||
@ -17,12 +17,12 @@ These plugins provide new json rpc methods to access several objects containing
|
||||
Subcommand
|
||||
------------
|
||||
|
||||
A subcommand redifines the total behavior of Geth and could stand on its own. In contrast with the other plugin types which, in general, are meant to capture and manipulate information, a subcommand is meant to change to overall behavior of Geth. It may do this in order to capture information but the primary fuctionality is a modulation of geth behaviour.
|
||||
A subcommand redifines the total behavior of Geth and could stand on its own. In contrast with the other plugin types which, in general, are meant to capture and manipulate information, a subcommand is meant to change to overall behavior of Geth. It may do this in order to capture information but the primary fuctionality is a modulation of geth behaviour.
|
||||
|
||||
Tracers
|
||||
-------
|
||||
|
||||
Tracers rely on historic data recompiled after execution to give insight into a transaction.
|
||||
Tracers rely on historic data recompiled after execution to give insight into a transaction.
|
||||
|
||||
**placeholder for eventual discusion of LiveTracers**
|
||||
|
||||
@ -30,13 +30,18 @@ Tracers rely on historic data recompiled after execution to give insight into a
|
||||
Subscriptions
|
||||
-------------
|
||||
|
||||
Subscriptions provide real time notification of data from the EVM as it processes transactions.
|
||||
Subscriptions provide real time notification of data from the EVM as it processes transactions.
|
||||
|
||||
.. NOTE:: Plugins are not limited to a singular functionality and can be customized to operate as hybrids of the above. See `blockupdates`_ as an example.
|
||||
.. NOTE:: Plugins are not limited to a singular functionality and can be customized to operate as hybrids of the above. See `blockupdates`_ as an example.
|
||||
|
||||
.. todo:: Austin: I don't love this page. The informations is too
|
||||
shallow.
|
||||
.. todo:: Austin: I don't love this page. The informations is too
|
||||
shallow.
|
||||
|
||||
Reply: I'd be inclined to add links out to the tutorial page for each
|
||||
of the types. I think it's useful to have brief descriptions of each
|
||||
type in one place, but putting each of the tutorials all on one page
|
||||
is a bit much. It might also be a good idea to link to real plugins
|
||||
that exemplify each type, though we won't have one of each type yet.
|
||||
|
||||
|
||||
.. _blockupdates: https://github.com/openrelayxyz/plugeth-plugins/tree/master/packages/blockupdates
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user