Update today, add hook writing guide
This commit is contained in:
parent
322eb88b8c
commit
9c6b92c284
@ -4,4 +4,102 @@
|
|||||||
Hook Writing Guide
|
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
|
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:
|
.. contents:: :local:
|
||||||
|
|
||||||
@ -17,12 +17,12 @@ These plugins provide new json rpc methods to access several objects containing
|
|||||||
Subcommand
|
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
|
||||||
-------
|
-------
|
||||||
|
|
||||||
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**
|
**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
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
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
|
.. todo:: Austin: I don't love this page. The informations is too
|
||||||
shallow.
|
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
|
.. _blockupdates: https://github.com/openrelayxyz/plugeth-plugins/tree/master/packages/blockupdates
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user