forked from cerc-io/plugeth
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:
parent
091a2f4884
commit
03808de29a
@ -324,7 +324,7 @@ func geth(ctx *cli.Context) error {
|
|||||||
prepare(ctx)
|
prepare(ctx)
|
||||||
stack, backend := makeFullNode(ctx)
|
stack, backend := makeFullNode(ctx)
|
||||||
defer stack.Close()
|
defer stack.Close()
|
||||||
stack.RegisterAPIs(plugins.GetAPIs(stack, backend))
|
stack.RegisterAPIs(pluginGetAPIs(stack, backend))
|
||||||
|
|
||||||
startNode(ctx, stack, backend)
|
startNode(ctx, stack, backend)
|
||||||
stack.Wait()
|
stack.Wait()
|
||||||
|
102
cmd/geth/plugin_hooks.go
Normal file
102
cmd/geth/plugin_hooks.go
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"math/big"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/accounts"
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/consensus"
|
||||||
|
"github.com/ethereum/go-ethereum/core"
|
||||||
|
"github.com/ethereum/go-ethereum/core/bloombits"
|
||||||
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
|
"github.com/ethereum/go-ethereum/eth/downloader"
|
||||||
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
|
"github.com/ethereum/go-ethereum/event"
|
||||||
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
"github.com/ethereum/go-ethereum/node"
|
||||||
|
"github.com/ethereum/go-ethereum/plugins"
|
||||||
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Backend interface provides the common API services (that are provided by
|
||||||
|
// both full and light clients) with access to necessary functions.
|
||||||
|
type Backend interface {
|
||||||
|
// General Ethereum API
|
||||||
|
Downloader() *downloader.Downloader
|
||||||
|
SuggestGasTipCap(ctx context.Context) (*big.Int, error)
|
||||||
|
ChainDb() ethdb.Database
|
||||||
|
AccountManager() *accounts.Manager
|
||||||
|
ExtRPCEnabled() bool
|
||||||
|
RPCGasCap() uint64 // global gas cap for eth_call over rpc: DoS protection
|
||||||
|
RPCTxFeeCap() float64 // global tx fee cap for all transaction related APIs
|
||||||
|
UnprotectedAllowed() bool // allows only for EIP155 transactions.
|
||||||
|
|
||||||
|
// Blockchain API
|
||||||
|
SetHead(number uint64)
|
||||||
|
HeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Header, error)
|
||||||
|
HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error)
|
||||||
|
HeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*types.Header, error)
|
||||||
|
CurrentHeader() *types.Header
|
||||||
|
CurrentBlock() *types.Block
|
||||||
|
BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error)
|
||||||
|
BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error)
|
||||||
|
BlockByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*types.Block, error)
|
||||||
|
StateAndHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*state.StateDB, *types.Header, error)
|
||||||
|
StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*state.StateDB, *types.Header, error)
|
||||||
|
GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error)
|
||||||
|
GetTd(ctx context.Context, hash common.Hash) *big.Int
|
||||||
|
GetEVM(ctx context.Context, msg core.Message, state *state.StateDB, header *types.Header, cfg *vm.Config) (*vm.EVM, func() error, error)
|
||||||
|
SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription
|
||||||
|
SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription
|
||||||
|
SubscribeChainSideEvent(ch chan<- core.ChainSideEvent) event.Subscription
|
||||||
|
|
||||||
|
// Transaction pool API
|
||||||
|
SendTx(ctx context.Context, signedTx *types.Transaction) error
|
||||||
|
GetTransaction(ctx context.Context, txHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error)
|
||||||
|
GetPoolTransactions() (types.Transactions, error)
|
||||||
|
GetPoolTransaction(txHash common.Hash) *types.Transaction
|
||||||
|
GetPoolNonce(ctx context.Context, addr common.Address) (uint64, error)
|
||||||
|
Stats() (pending int, queued int)
|
||||||
|
TxPoolContent() (map[common.Address]types.Transactions, map[common.Address]types.Transactions)
|
||||||
|
SubscribeNewTxsEvent(chan<- core.NewTxsEvent) event.Subscription
|
||||||
|
|
||||||
|
// Filter API
|
||||||
|
BloomStatus() (uint64, uint64)
|
||||||
|
GetLogs(ctx context.Context, blockHash common.Hash) ([][]*types.Log, error)
|
||||||
|
ServiceFilter(ctx context.Context, session *bloombits.MatcherSession)
|
||||||
|
SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription
|
||||||
|
SubscribePendingLogsEvent(ch chan<- []*types.Log) event.Subscription
|
||||||
|
SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription
|
||||||
|
|
||||||
|
ChainConfig() *params.ChainConfig
|
||||||
|
Engine() consensus.Engine
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type APILoader func(*node.Node, Backend) []rpc.API
|
||||||
|
|
||||||
|
func GetAPIsFromLoader(pl *plugins.PluginLoader, stack *node.Node, backend Backend) []rpc.API {
|
||||||
|
result := []rpc.API{}
|
||||||
|
fnList := pl.Lookup("GetAPIs", func(item interface{}) bool {
|
||||||
|
_, ok := item.(func(*node.Node, Backend) []rpc.API)
|
||||||
|
return ok
|
||||||
|
})
|
||||||
|
for _, fni := range fnList {
|
||||||
|
if fn, ok := fni.(func(*node.Node, Backend) []rpc.API); ok {
|
||||||
|
result = append(result, fn(stack, backend)...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func pluginGetAPIs(stack *node.Node, backend Backend) []rpc.API {
|
||||||
|
if plugins.DefaultPluginLoader == nil {
|
||||||
|
log.Warn("Attempting GetAPIs, but default PluginLoader has not been initialized")
|
||||||
|
return []rpc.API{}
|
||||||
|
}
|
||||||
|
return GetAPIsFromLoader(plugins.DefaultPluginLoader, stack, backend)
|
||||||
|
}
|
62
core/plugin_hooks.go
Normal file
62
core/plugin_hooks.go
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
package core
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/plugins"
|
||||||
|
)
|
||||||
|
|
||||||
|
func pluginPreProcessBlock(block *types.Block) {
|
||||||
|
fnList := plugins.Lookup("ProcessBlock", func(item interface{}) bool {
|
||||||
|
_, ok := item.(func(*types.Block))
|
||||||
|
return ok
|
||||||
|
})
|
||||||
|
for _, fni := range fnList {
|
||||||
|
if fn, ok := fni.(func(*types.Block)); ok {
|
||||||
|
fn(block)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func pluginPreProcessTransaction(tx *types.Transaction, block *types.Block, i int) {
|
||||||
|
fnList := plugins.Lookup("ProcessTransaction", func(item interface{}) bool {
|
||||||
|
_, ok := item.(func(*types.Transaction, *types.Block, int))
|
||||||
|
return ok
|
||||||
|
})
|
||||||
|
for _, fni := range fnList {
|
||||||
|
if fn, ok := fni.(func(*types.Transaction, *types.Block, int)); ok {
|
||||||
|
fn(tx, block, i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func pluginBlockProcessingError(tx *types.Transaction, block *types.Block, err error) {
|
||||||
|
fnList := plugins.Lookup("ProcessingError", func(item interface{}) bool {
|
||||||
|
_, ok := item.(func(*types.Transaction, *types.Block, error))
|
||||||
|
return ok
|
||||||
|
})
|
||||||
|
for _, fni := range fnList {
|
||||||
|
if fn, ok := fni.(func(*types.Transaction, *types.Block, error)); ok {
|
||||||
|
fn(tx, block, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func pluginPostProcessTransaction(tx *types.Transaction, block *types.Block, i int, receipt *types.Receipt) {
|
||||||
|
fnList := plugins.Lookup("ProcessTransaction", func(item interface{}) bool {
|
||||||
|
_, ok := item.(func(*types.Transaction, *types.Block, int, *types.Receipt))
|
||||||
|
return ok
|
||||||
|
})
|
||||||
|
for _, fni := range fnList {
|
||||||
|
if fn, ok := fni.(func(*types.Transaction, *types.Block, int, *types.Receipt)); ok {
|
||||||
|
fn(tx, block, i, receipt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func pluginPostProcessBlock(block *types.Block) {
|
||||||
|
fnList := plugins.Lookup("ProcessBlock", func(item interface{}) bool {
|
||||||
|
_, ok := item.(func(*types.Block))
|
||||||
|
return ok
|
||||||
|
})
|
||||||
|
for _, fni := range fnList {
|
||||||
|
if fn, ok := fni.(func(*types.Block)); ok {
|
||||||
|
fn(block)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -27,7 +27,6 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/plugins"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// StateProcessor is a basic Processor, which takes care of transitioning
|
// StateProcessor is a basic Processor, which takes care of transitioning
|
||||||
@ -71,27 +70,27 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
|
|||||||
blockContext := NewEVMBlockContext(header, p.bc, nil)
|
blockContext := NewEVMBlockContext(header, p.bc, nil)
|
||||||
vmenv := vm.NewEVM(blockContext, vm.TxContext{}, statedb, p.config, cfg)
|
vmenv := vm.NewEVM(blockContext, vm.TxContext{}, statedb, p.config, cfg)
|
||||||
// Iterate over and process the individual transactions
|
// Iterate over and process the individual transactions
|
||||||
plugins.PreProcessBlock(block)
|
pluginPreProcessBlock(block)
|
||||||
for i, tx := range block.Transactions() {
|
for i, tx := range block.Transactions() {
|
||||||
msg, err := tx.AsMessage(types.MakeSigner(p.config, header.Number), header.BaseFee)
|
msg, err := tx.AsMessage(types.MakeSigner(p.config, header.Number), header.BaseFee)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
plugins.BlockProcessingError(tx, block, err)
|
pluginBlockProcessingError(tx, block, err)
|
||||||
return nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err)
|
return nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err)
|
||||||
}
|
}
|
||||||
statedb.Prepare(tx.Hash(), block.Hash(), i)
|
statedb.Prepare(tx.Hash(), block.Hash(), i)
|
||||||
plugins.PreProcessTransaction(tx, block, i)
|
pluginPreProcessTransaction(tx, block, i)
|
||||||
receipt, err := applyTransaction(msg, p.config, p.bc, nil, gp, statedb, header, tx, usedGas, vmenv)
|
receipt, err := applyTransaction(msg, p.config, p.bc, nil, gp, statedb, header, tx, usedGas, vmenv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
plugins.BlockProcessingError(tx, block, err)
|
pluginBlockProcessingError(tx, block, err)
|
||||||
return nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err)
|
return nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err)
|
||||||
}
|
}
|
||||||
plugins.PostProcessTransaction(tx, block, i, receipt)
|
pluginPostProcessTransaction(tx, block, i, receipt)
|
||||||
receipts = append(receipts, receipt)
|
receipts = append(receipts, receipt)
|
||||||
allLogs = append(allLogs, receipt.Logs...)
|
allLogs = append(allLogs, receipt.Logs...)
|
||||||
}
|
}
|
||||||
// Finalize the block, applying any consensus engine specific extras (e.g. block rewards)
|
// Finalize the block, applying any consensus engine specific extras (e.g. block rewards)
|
||||||
p.engine.Finalize(p.bc, header, statedb, block.Transactions(), block.Uncles())
|
p.engine.Finalize(p.bc, header, statedb, block.Transactions(), block.Uncles())
|
||||||
plugins.PostProcessBlock(block)
|
pluginPostProcessBlock(block)
|
||||||
return receipts, allLogs, *usedGas, nil
|
return receipts, allLogs, *usedGas, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,7 +53,6 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/p2p/dnsdisc"
|
"github.com/ethereum/go-ethereum/p2p/dnsdisc"
|
||||||
"github.com/ethereum/go-ethereum/p2p/enode"
|
"github.com/ethereum/go-ethereum/p2p/enode"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/plugins"
|
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
)
|
)
|
||||||
@ -146,7 +145,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
|
|||||||
chainDb: chainDb,
|
chainDb: chainDb,
|
||||||
eventMux: stack.EventMux(),
|
eventMux: stack.EventMux(),
|
||||||
accountManager: stack.AccountManager(),
|
accountManager: stack.AccountManager(),
|
||||||
engine: plugins.CreateConsensusEngine(stack, chainConfig, ðashConfig, config.Miner.Notify, config.Miner.Noverify, chainDb),
|
engine: pluginCreateConsensusEngine(stack, chainConfig, ðashConfig, config.Miner.Notify, config.Miner.Noverify, chainDb),
|
||||||
closeBloomHandler: make(chan struct{}),
|
closeBloomHandler: make(chan struct{}),
|
||||||
networkID: config.NetworkId,
|
networkID: config.NetworkId,
|
||||||
gasPrice: config.Miner.GasPrice,
|
gasPrice: config.Miner.GasPrice,
|
||||||
@ -191,7 +190,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
|
|||||||
Preimages: config.Preimages,
|
Preimages: config.Preimages,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
plugins.UpdateBlockchainVMConfig(&vmConfig)
|
pluginUpdateBlockchainVMConfig(&vmConfig)
|
||||||
eth.blockchain, err = core.NewBlockChain(chainDb, cacheConfig, chainConfig, eth.engine, vmConfig, eth.shouldPreserve, &config.TxLookupLimit)
|
eth.blockchain, err = core.NewBlockChain(chainDb, cacheConfig, chainConfig, eth.engine, vmConfig, eth.shouldPreserve, &config.TxLookupLimit)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
52
eth/plugin_hooks.go
Normal file
52
eth/plugin_hooks.go
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
package eth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/ethereum/go-ethereum/plugins"
|
||||||
|
"github.com/ethereum/go-ethereum/node"
|
||||||
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
|
"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"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
func pluginCreateConsensusEngine(stack *node.Node, chainConfig *params.ChainConfig, config *ethash.Config, notify []string, noverify bool, db ethdb.Database) consensus.Engine {
|
||||||
|
fnList := plugins.Lookup("CreateConsensusEngine", func(item interface{}) bool {
|
||||||
|
_, ok := item.(func(*node.Node, *params.ChainConfig, *ethash.Config, []string, bool, ethdb.Database) consensus.Engine)
|
||||||
|
return ok
|
||||||
|
})
|
||||||
|
for _, fni := range fnList {
|
||||||
|
if fn, ok := fni.(func(*node.Node, *params.ChainConfig, *ethash.Config, []string, bool, ethdb.Database) consensus.Engine); ok {
|
||||||
|
return fn(stack, chainConfig, config, notify, noverify, db)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ethconfig.CreateConsensusEngine(stack, chainConfig, config, notify, noverify, db)
|
||||||
|
}
|
||||||
|
func pluginUpdateBlockchainVMConfig(cfg *vm.Config) {
|
||||||
|
fnList := plugins.Lookup("UpdateBlockchainVMConfig", func(item interface{}) bool {
|
||||||
|
_, ok := item.(func(*vm.Config))
|
||||||
|
return ok
|
||||||
|
})
|
||||||
|
for _, fni := range fnList {
|
||||||
|
if fn, ok := fni.(func(*vm.Config)); ok {
|
||||||
|
fn(cfg)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
// }
|
||||||
|
// }
|
@ -40,7 +40,6 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/internal/ethapi"
|
"github.com/ethereum/go-ethereum/internal/ethapi"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/plugins"
|
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
)
|
)
|
||||||
@ -801,7 +800,7 @@ func (api *API) traceTx(ctx context.Context, message core.Message, txctx *txTrac
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Get the tracer from the plugin loader
|
// Get the tracer from the plugin loader
|
||||||
if tr, ok := plugins.GetTracer(*config.Tracer); ok {
|
if tr, ok := getPluginTracer(*config.Tracer); ok {
|
||||||
tracer = tr(statedb)
|
tracer = tr(statedb)
|
||||||
} else {
|
} else {
|
||||||
// Constuct the JavaScript tracer to execute with
|
// Constuct the JavaScript tracer to execute with
|
||||||
@ -851,7 +850,7 @@ func (api *API) traceTx(ctx context.Context, message core.Message, txctx *txTrac
|
|||||||
StructLogs: ethapi.FormatLogs(tracer.StructLogs()),
|
StructLogs: ethapi.FormatLogs(tracer.StructLogs()),
|
||||||
}, nil
|
}, nil
|
||||||
|
|
||||||
case plugins.TracerResult:
|
case TracerResult:
|
||||||
return tracer.GetResult()
|
return tracer.GetResult()
|
||||||
|
|
||||||
case *Tracer:
|
case *Tracer:
|
||||||
|
28
eth/tracers/plugin_hooks.go
Normal file
28
eth/tracers/plugin_hooks.go
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
package tracers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/ethereum/go-ethereum/plugins"
|
||||||
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
type TracerResult interface {
|
||||||
|
vm.Tracer
|
||||||
|
GetResult() (interface{}, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getPluginTracer(name string) (func(*state.StateDB)TracerResult, bool) {
|
||||||
|
tracers := plugins.Lookup("Tracers", func(item interface{}) bool {
|
||||||
|
_, ok := item.(map[string]func(*state.StateDB)TracerResult)
|
||||||
|
return ok
|
||||||
|
})
|
||||||
|
for _, tmap := range tracers {
|
||||||
|
if tracerMap, ok := tmap.(map[string]func(*state.StateDB)TracerResult); ok {
|
||||||
|
if tracer, ok := tracerMap[name]; ok {
|
||||||
|
return tracer, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, false
|
||||||
|
}
|
@ -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)
|
|
||||||
}
|
|
@ -2,15 +2,8 @@ package plugins
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"plugin"
|
"plugin"
|
||||||
"github.com/ethereum/go-ethereum/node"
|
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"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/vm"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
|
||||||
"github.com/ethereum/go-ethereum/params"
|
|
||||||
"gopkg.in/urfave/cli.v1"
|
"gopkg.in/urfave/cli.v1"
|
||||||
"flag"
|
"flag"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
@ -29,19 +22,32 @@ type TracerResult interface {
|
|||||||
|
|
||||||
|
|
||||||
type PluginLoader struct{
|
type PluginLoader struct{
|
||||||
Plugins []plugin.Plugin
|
Plugins []*plugin.Plugin
|
||||||
Tracers map[string]func(StateDB)TracerResult
|
|
||||||
StateHooks []interface{} // TODO: Set interface
|
|
||||||
// RPCPlugins []APILoader
|
|
||||||
Subcommands map[string]Subcommand
|
Subcommands map[string]Subcommand
|
||||||
Flags []*flag.FlagSet
|
Flags []*flag.FlagSet
|
||||||
CreateConsensusEngine func(stack *node.Node, chainConfig *params.ChainConfig, config *ethash.Config, notify []string, noverify bool, db ethdb.Database) consensus.Engine
|
LookupCache map[string][]interface{}
|
||||||
UpdateBlockchainVMConfig func(*vm.Config)
|
}
|
||||||
PreProcessBlockList []func(*types.Block)
|
|
||||||
PreProcessTransactionList []func(*types.Transaction, *types.Block, int)
|
func (pl *PluginLoader) Lookup(name string, validate func(interface{}) bool) []interface{} {
|
||||||
BlockProcessingErrorList []func(*types.Transaction, *types.Block, error)
|
if v, ok := pl.LookupCache[name]; ok { return v }
|
||||||
PostProcessTransactionList []func(*types.Transaction, *types.Block, int, *types.Receipt)
|
results := []interface{}{}
|
||||||
PostProcessBlockList []func(*types.Block)
|
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) {
|
func NewPluginLoader(target string) (*PluginLoader, error) {
|
||||||
pl := &PluginLoader{
|
pl := &PluginLoader{
|
||||||
Plugins: []plugin.Plugin,
|
Plugins: []*plugin.Plugin{},
|
||||||
// RPCPlugins: []APILoader{},
|
// RPCPlugins: []APILoader{},
|
||||||
Subcommands: make(map[string]Subcommand),
|
Subcommands: make(map[string]Subcommand),
|
||||||
Tracers: make(map[string]func(StateDB)TracerResult),
|
|
||||||
Flags: []*flag.FlagSet{},
|
Flags: []*flag.FlagSet{},
|
||||||
|
LookupCache: make(map[string][]interface{}),
|
||||||
// CreateConsensusEngine: ethconfig.CreateConsensusEngine,
|
// CreateConsensusEngine: ethconfig.CreateConsensusEngine,
|
||||||
UpdateBlockchainVMConfig: func(cfg *vm.Config) {},
|
// UpdateBlockchainVMConfig: func(cfg *vm.Config) {},
|
||||||
}
|
}
|
||||||
files, err := ioutil.ReadDir(target)
|
files, err := ioutil.ReadDir(target)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warn("Could not load plugins directory. Skipping.", "path", target)
|
log.Warn("Could not load plugins directory. Skipping.", "path", target)
|
||||||
return pl, nil
|
return pl, nil
|
||||||
}
|
}
|
||||||
setConsensus := false
|
|
||||||
setUpdateBCVMCfg := false
|
|
||||||
for _, file := range files {
|
for _, file := range files {
|
||||||
fpath := path.Join(target, file.Name())
|
fpath := path.Join(target, file.Name())
|
||||||
if !strings.HasSuffix(file.Name(), ".so") {
|
if !strings.HasSuffix(file.Name(), ".so") {
|
||||||
@ -100,97 +104,7 @@ func NewPluginLoader(target string) (*PluginLoader, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tr, err := plug.Lookup("Tracers")
|
pl.Plugins = append(pl.Plugins, plug)
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
return pl, nil
|
return pl, nil
|
||||||
}
|
}
|
||||||
@ -227,94 +141,3 @@ func ParseFlags(args []string) bool {
|
|||||||
}
|
}
|
||||||
return DefaultPluginLoader.ParseFlags(args)
|
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)
|
|
||||||
}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user