Refactor plugin system

When the plugin loader itself had to know the types in the arguments
and return values of the plugin functions, it was very difficult to
avoid import loops, given that the types were often defined in the
same package that needed to invoke the plugins.

Under this model, the plugin loader has much less knowledge of the
plugins themselves, and within each package we define functions to
interact with the plugins.
This commit is contained in:
Austin Roberts
2021-06-25 22:46:17 -05:00
parent 091a2f4884
commit 03808de29a
10 changed files with 283 additions and 256 deletions
-37
View File
@@ -1,37 +0,0 @@
package plugins
import (
"context"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
)
type StateDB interface {
Error() error
GetLogs(hash common.Hash) []*types.Log
Logs() []*types.Log
Preimages() map[common.Hash][]byte
Exist(addr common.Address) bool
Empty(addr common.Address) bool
GetBalance(addr common.Address) *big.Int
GetNonce(addr common.Address) uint64
TxIndex() int
BlockHash() common.Hash
GetCode(addr common.Address) []byte
GetCodeSize(addr common.Address) int
GetCodeHash(addr common.Address) common.Hash
GetState(addr common.Address, hash common.Hash) common.Hash
GetProof(addr common.Address) ([][]byte, error)
GetProofByHash(addrHash common.Hash) ([][]byte, error)
GetStorageProof(a common.Address, key common.Hash) ([][]byte, error)
GetStorageProofByHash(a common.Address, key common.Hash) ([][]byte, error)
GetCommittedState(addr common.Address, hash common.Hash) common.Hash
HasSuicided(addr common.Address) bool
ForEachStorage(addr common.Address, cb func(key, value common.Hash) bool) error
GetRefund() uint64
AddressInAccessList(addr common.Address) bool
SlotInAccessList(addr common.Address, slot common.Hash) (addressPresent bool, slotPresent bool)
}
+28 -205
View File
@@ -2,15 +2,8 @@ package plugins
import (
"plugin"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/consensus/ethash"
// "github.com/ethereum/go-ethereum/eth/ethconfig"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/params"
"gopkg.in/urfave/cli.v1"
"flag"
"io/ioutil"
@@ -29,19 +22,32 @@ type TracerResult interface {
type PluginLoader struct{
Plugins []plugin.Plugin
Tracers map[string]func(StateDB)TracerResult
StateHooks []interface{} // TODO: Set interface
// RPCPlugins []APILoader
Plugins []*plugin.Plugin
Subcommands map[string]Subcommand
Flags []*flag.FlagSet
CreateConsensusEngine func(stack *node.Node, chainConfig *params.ChainConfig, config *ethash.Config, notify []string, noverify bool, db ethdb.Database) consensus.Engine
UpdateBlockchainVMConfig func(*vm.Config)
PreProcessBlockList []func(*types.Block)
PreProcessTransactionList []func(*types.Transaction, *types.Block, int)
BlockProcessingErrorList []func(*types.Transaction, *types.Block, error)
PostProcessTransactionList []func(*types.Transaction, *types.Block, int, *types.Receipt)
PostProcessBlockList []func(*types.Block)
LookupCache map[string][]interface{}
}
func (pl *PluginLoader) Lookup(name string, validate func(interface{}) bool) []interface{} {
if v, ok := pl.LookupCache[name]; ok { return v }
results := []interface{}{}
for _, plugin := range pl.Plugins {
if v, err := plugin.Lookup(name); err == nil {
if validate(v) {
results = append(results, v)
}
}
}
pl.LookupCache[name] = results
return results
}
func Lookup(name string, validate func(interface{}) bool) []interface{} {
if DefaultPluginLoader == nil {
log.Warn("Lookup attempted, but PluginLoader is not initialized", "name", name)
return []interface{}{}
}
return DefaultPluginLoader.Lookup(name, validate)
}
@@ -50,21 +56,19 @@ var DefaultPluginLoader *PluginLoader
func NewPluginLoader(target string) (*PluginLoader, error) {
pl := &PluginLoader{
Plugins: []plugin.Plugin,
Plugins: []*plugin.Plugin{},
// RPCPlugins: []APILoader{},
Subcommands: make(map[string]Subcommand),
Tracers: make(map[string]func(StateDB)TracerResult),
Flags: []*flag.FlagSet{},
LookupCache: make(map[string][]interface{}),
// CreateConsensusEngine: ethconfig.CreateConsensusEngine,
UpdateBlockchainVMConfig: func(cfg *vm.Config) {},
// UpdateBlockchainVMConfig: func(cfg *vm.Config) {},
}
files, err := ioutil.ReadDir(target)
if err != nil {
log.Warn("Could not load plugins directory. Skipping.", "path", target)
return pl, nil
}
setConsensus := false
setUpdateBCVMCfg := false
for _, file := range files {
fpath := path.Join(target, file.Name())
if !strings.HasSuffix(file.Name(), ".so") {
@@ -100,97 +104,7 @@ func NewPluginLoader(target string) (*PluginLoader, error) {
}
}
}
tr, err := plug.Lookup("Tracers")
if err == nil {
tracers, ok := tr.(*map[string]func(StateDB)TracerResult)
if !ok {
log.Warn("Could not cast plugin.Tracers to `map[string]vm.Tracer`", "file", fpath)
} else {
for k, v := range *tracers {
if _, ok := pl.Tracers[k]; ok {
log.Warn("Tracer redeclared", "file", fpath, "tracer", k)
}
pl.Tracers[k] = v
}
}
}
ce, err := plug.Lookup("CreateConsensusEngine")
if err == nil {
cce, ok := ce.(func (stack *node.Node, chainConfig *params.ChainConfig, config *ethash.Config, notify []string, noverify bool, db ethdb.Database) consensus.Engine)
if !ok {
log.Warn("Could not cast plugin.CreateConsensusEngine to appropriate function", "file", fpath)
} else {
if setConsensus {
log.Warn("CreateConsensusEngine redeclared", "file", fpath)
}
pl.CreateConsensusEngine = cce
setConsensus = true
}
}
vmcfgu, err := plug.Lookup("UpdateBlockchainVMConfig")
if err == nil {
vmcfgfn, ok := vmcfgu.(func(*vm.Config))
if !ok {
log.Warn("Could not cast plugin.UpdateBlockchainVMConfig to appropriate function", "file", fpath)
} else {
if setUpdateBCVMCfg {
log.Warn("UpdateBlockchainVMConfig redeclared", "file", fpath)
}
pl.UpdateBlockchainVMConfig = vmcfgfn
setUpdateBCVMCfg = true
}
}
prepb, err := plug.Lookup("PreProcessBlock")
if err == nil {
prepbfn, ok := prepb.(func(*types.Block))
if !ok {
log.Warn("Could not cast plugin.PreProcessBlock to appropriate function", "file", fpath)
} else {
pl.PreProcessBlockList = append(pl.PreProcessBlockList, prepbfn)
}
}
prept, err := plug.Lookup("PreProcessTransaction")
if err == nil {
preptfn, ok := prept.(func(*types.Transaction, *types.Block, int))
if !ok {
log.Warn("Could not cast plugin.PreProcessTransaction to appropriate function", "file", fpath)
} else {
pl.PreProcessTransactionList = append(pl.PreProcessTransactionList, preptfn)
}
}
bpe, err := plug.Lookup("BlockProcessingError")
if err == nil {
bpefn, ok := bpe.(func(*types.Transaction, *types.Block, error))
if !ok {
log.Warn("Could not cast plugin.BlockProcessingError to appropriate function", "file", fpath)
} else {
pl.BlockProcessingErrorList = append(pl.BlockProcessingErrorList, bpefn)
}
}
prept, err := plug.Lookup("PostProcessTransaction")
if err == nil {
preptfn, ok := prept.(func(*types.Transaction, *types.Block, int, *types.Receipt))
if !ok {
log.Warn("Could not cast plugin.PostProcessTransaction to appropriate function", "file", fpath)
} else {
pl.PostProcessTransactionList = append(pl.PostProcessTransactionList, preptfn)
}
}
prepb, err := plug.Lookup("PostProcessBlock")
if err == nil {
prepbfn, ok := prepb.(func(*types.Block))
if !ok {
log.Warn("Could not cast plugin.PostProcessBlock to appropriate function", "file", fpath)
} else {
pl.PostProcessBlockList = append(pl.PostProcessBlockList, prepbfn)
}
}
pl.Plugins = append(pl.Plugins, plug)
}
return pl, nil
}
@@ -227,94 +141,3 @@ func ParseFlags(args []string) bool {
}
return DefaultPluginLoader.ParseFlags(args)
}
func (pl *PluginLoader) GetTracer(s string) (func(StateDB)TracerResult, bool) {
tr, ok := pl.Tracers[s]
return tr, ok
}
func GetTracer(s string) (func(StateDB)TracerResult, bool) {
if DefaultPluginLoader == nil {
log.Warn("Attempting GetTracer, but default PluginLoader has not been initialized")
return nil, false
}
return DefaultPluginLoader.GetTracer(s)
}
// func CreateConsensusEngine(stack *node.Node, chainConfig *params.ChainConfig, config *ethash.Config, notify []string, noverify bool, db ethdb.Database) consensus.Engine {
// if DefaultPluginLoader == nil {
// log.Warn("Attempting CreateConsensusEngine, but default PluginLoader has not been initialized")
// return ethconfig.CreateConsensusEngine(stack, chainConfig, config, notify, noverify, db)
// }
// return DefaultPluginLoader.CreateConsensusEngine(stack, chainConfig, config, notify, noverify, db)
// }
func UpdateBlockchainVMConfig(cfg *vm.Config) {
if DefaultPluginLoader == nil {
log.Warn("Attempting UpdateBlockchainVMConfig, but default PluginLoader has not been initialized")
return
}
DefaultPluginLoader.UpdateBlockchainVMConfig(cfg)
}
func (pl *PluginLoader) PreProcessBlock(block *types.Block) {
for _, fn := range pl.PreProcessBlockList {
fn(block)
}
}
func PreProcessBlock(block *types.Block) {
if DefaultPluginLoader == nil {
log.Warn("Attempting PreProcessBlock, but default PluginLoader has not been initialized")
return
}
DefaultPluginLoader.PreProcessBlock(block)
}
func (pl *PluginLoader) PreProcessTransaction(tx *types.Transaction, block *types.Block, i int) {
for _, fn := range pl.PreProcessTransactionList {
fn(tx, block, i)
}
}
func PreProcessTransaction(tx *types.Transaction, block *types.Block, i int) {
if DefaultPluginLoader == nil {
log.Warn("Attempting PreProcessTransaction, but default PluginLoader has not been initialized")
return
}
DefaultPluginLoader.PreProcessTransaction(tx, block, i)
}
func (pl *PluginLoader) BlockProcessingError(tx *types.Transaction, block *types.Block, err error) {
for _, fn := range pl.BlockProcessingErrorList {
fn(tx, block, err)
}
}
func BlockProcessingError(tx *types.Transaction, block *types.Block, err error) {
if DefaultPluginLoader == nil {
log.Warn("Attempting BlockProcessingError, but default PluginLoader has not been initialized")
return
}
DefaultPluginLoader.BlockProcessingError(tx, block, err)
}
func (pl *PluginLoader) PostProcessTransaction(tx *types.Transaction, block *types.Block, i int, receipt *types.Receipt) {
for _, fn := range pl.PostProcessTransactionList {
fn(tx, block, i, receipt)
}
}
func PostProcessTransaction(tx *types.Transaction, block *types.Block, i int, receipt *types.Receipt) {
if DefaultPluginLoader == nil {
log.Warn("Attempting PostProcessTransaction, but default PluginLoader has not been initialized")
return
}
DefaultPluginLoader.PostProcessTransaction(tx, block, i, receipt)
}
func (pl *PluginLoader) PostProcessBlock(block *types.Block) {
for _, fn := range pl.PostProcessBlockList {
fn(block)
}
}
func PostProcessBlock(block *types.Block) {
if DefaultPluginLoader == nil {
log.Warn("Attempting PostProcessBlock, but default PluginLoader has not been initialized")
return
}
DefaultPluginLoader.PostProcessBlock(block)
}