From 091a2f488490b7099e1e22fa59a38df43f7cf7f1 Mon Sep 17 00:00:00 2001 From: Austin Roberts Date: Fri, 25 Jun 2021 17:05:17 -0500 Subject: [PATCH] Checkpoint Things are currently broken because of import cycles. I'm going to need to revisit how the plugin loader works, but I wanted to make a checkpoint before I start breaking things again. --- core/state_processor.go | 8 +- eth/backend.go | 4 +- plugins/interface.go | 87 ++++-------- plugins/plugin_loader.go | 235 ++++++++++++++++++++++++++------ plugins/rpcloader/interface.go | 74 ++++++++++ plugins/rpcloader/rpc_loader.go | 47 +++++++ 6 files changed, 346 insertions(+), 109 deletions(-) create mode 100644 plugins/rpcloader/interface.go create mode 100644 plugins/rpcloader/rpc_loader.go diff --git a/core/state_processor.go b/core/state_processor.go index 6f6bc1879..4f0b79fe1 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -27,6 +27,7 @@ import ( "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/plugins" ) // StateProcessor is a basic Processor, which takes care of transitioning @@ -70,22 +71,27 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg blockContext := NewEVMBlockContext(header, p.bc, nil) vmenv := vm.NewEVM(blockContext, vm.TxContext{}, statedb, p.config, cfg) // Iterate over and process the individual transactions + plugins.PreProcessBlock(block) for i, tx := range block.Transactions() { msg, err := tx.AsMessage(types.MakeSigner(p.config, header.Number), header.BaseFee) if err != nil { + plugins.BlockProcessingError(tx, block, 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) + plugins.PreProcessTransaction(tx, block, i) receipt, err := applyTransaction(msg, p.config, p.bc, nil, gp, statedb, header, tx, usedGas, vmenv) if err != nil { + plugins.BlockProcessingError(tx, block, 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) receipts = append(receipts, receipt) allLogs = append(allLogs, receipt.Logs...) } // Finalize the block, applying any consensus engine specific extras (e.g. block rewards) p.engine.Finalize(p.bc, header, statedb, block.Transactions(), block.Uncles()) - + plugins.PostProcessBlock(block) return receipts, allLogs, *usedGas, nil } diff --git a/eth/backend.go b/eth/backend.go index 3e770fe83..3ef6baa5c 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -53,6 +53,7 @@ import ( "github.com/ethereum/go-ethereum/p2p/dnsdisc" "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/plugins" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rpc" ) @@ -145,7 +146,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { chainDb: chainDb, eventMux: stack.EventMux(), accountManager: stack.AccountManager(), - engine: ethconfig.CreateConsensusEngine(stack, chainConfig, ðashConfig, config.Miner.Notify, config.Miner.Noverify, chainDb), + engine: plugins.CreateConsensusEngine(stack, chainConfig, ðashConfig, config.Miner.Notify, config.Miner.Noverify, chainDb), closeBloomHandler: make(chan struct{}), networkID: config.NetworkId, gasPrice: config.Miner.GasPrice, @@ -190,6 +191,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { Preimages: config.Preimages, } ) + plugins.UpdateBlockchainVMConfig(&vmConfig) eth.blockchain, err = core.NewBlockChain(chainDb, cacheConfig, chainConfig, eth.engine, vmConfig, eth.shouldPreserve, &config.TxLookupLimit) if err != nil { return nil, err diff --git a/plugins/interface.go b/plugins/interface.go index 13279b809..2c84f5d1f 100644 --- a/plugins/interface.go +++ b/plugins/interface.go @@ -4,71 +4,34 @@ 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/rpc" ) -// 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 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) } diff --git a/plugins/plugin_loader.go b/plugins/plugin_loader.go index e4a9d695a..4f3450193 100644 --- a/plugins/plugin_loader.go +++ b/plugins/plugin_loader.go @@ -2,11 +2,15 @@ package plugins import ( "plugin" - "github.com/ethereum/go-ethereum/rpc" "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/state" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/params" "gopkg.in/urfave/cli.v1" "flag" "io/ioutil" @@ -17,7 +21,6 @@ import ( ) -type APILoader func(*node.Node, Backend) []rpc.API type Subcommand func(*cli.Context, []string) error type TracerResult interface { vm.Tracer @@ -26,29 +29,42 @@ type TracerResult interface { type PluginLoader struct{ - Tracers map[string]func(*state.StateDB)TracerResult + Plugins []plugin.Plugin + Tracers map[string]func(StateDB)TracerResult StateHooks []interface{} // TODO: Set interface - ChainEventHooks []interface{} // TODO: Set interface - RPCPlugins []APILoader + // RPCPlugins []APILoader 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) } -var defaultPluginLoader *PluginLoader + +var DefaultPluginLoader *PluginLoader func NewPluginLoader(target string) (*PluginLoader, error) { pl := &PluginLoader{ - RPCPlugins: []APILoader{}, + Plugins: []plugin.Plugin, + // RPCPlugins: []APILoader{}, Subcommands: make(map[string]Subcommand), - Tracers: make(map[string]func(*state.StateDB)TracerResult), + Tracers: make(map[string]func(StateDB)TracerResult), Flags: []*flag.FlagSet{}, + // CreateConsensusEngine: ethconfig.CreateConsensusEngine, + 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") { @@ -70,16 +86,6 @@ func NewPluginLoader(target string) (*PluginLoader, error) { pl.Flags = append(pl.Flags, flagset) } } - fn, err := plug.Lookup("GetAPIs") - if err == nil { - apiLoader, ok := fn.(func(*node.Node, Backend) []rpc.API) - if !ok { - log.Warn("Could not cast plugin.GetAPIs to APILoader", "file", fpath) - } else { - pl.RPCPlugins = append(pl.RPCPlugins, APILoader(apiLoader)) - } - } else { log.Debug("Error retrieving GetAPIs for plugin", "file", fpath, "error", err.Error()) } - sb, err := plug.Lookup("Subcommands") if err == nil { subcommands, ok := sb.(*map[string]func(*cli.Context, []string) error) @@ -96,7 +102,7 @@ func NewPluginLoader(target string) (*PluginLoader, error) { } tr, err := plug.Lookup("Tracers") if err == nil { - tracers, ok := tr.(*map[string]func(*state.StateDB)TracerResult) + 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 { @@ -108,12 +114,89 @@ func NewPluginLoader(target string) (*PluginLoader, error) { } } } + 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 } func Initialize(target string) (err error) { - defaultPluginLoader, err = NewPluginLoader(target) + DefaultPluginLoader, err = NewPluginLoader(target) return err } @@ -126,8 +209,8 @@ func (pl *PluginLoader) RunSubcommand(ctx *cli.Context) (bool, error) { } func RunSubcommand(ctx *cli.Context) (bool, error) { - if defaultPluginLoader == nil { return false, fmt.Errorf("Plugin loader not initialized") } - return defaultPluginLoader.RunSubcommand(ctx) + if DefaultPluginLoader == nil { return false, fmt.Errorf("Plugin loader not initialized") } + return DefaultPluginLoader.RunSubcommand(ctx) } func (pl *PluginLoader) ParseFlags(args []string) bool { @@ -138,38 +221,100 @@ func (pl *PluginLoader) ParseFlags(args []string) bool { } func ParseFlags(args []string) bool { - if defaultPluginLoader == nil { + if DefaultPluginLoader == nil { log.Warn("Attempting to parse flags, but default PluginLoader has not been initialized") return false } - return defaultPluginLoader.ParseFlags(args) + return DefaultPluginLoader.ParseFlags(args) } -func (pl *PluginLoader) GetAPIs(stack *node.Node, backend Backend) []rpc.API { - apis := []rpc.API{} - for _, apiLoader := range pl.RPCPlugins { - apis = append(apis, apiLoader(stack, backend)...) - } - return apis -} - -func GetAPIs(stack *node.Node, backend Backend) []rpc.API { - if defaultPluginLoader == nil { - log.Warn("Attempting GetAPIs, but default PluginLoader has not been initialized") - return []rpc.API{} - } - return defaultPluginLoader.GetAPIs(stack, backend) -} - -func (pl *PluginLoader) GetTracer(s string) (func(*state.StateDB)TracerResult, bool) { +func (pl *PluginLoader) GetTracer(s string) (func(StateDB)TracerResult, bool) { tr, ok := pl.Tracers[s] return tr, ok } -func GetTracer(s string) (func(*state.StateDB)TracerResult, bool) { - if defaultPluginLoader == nil { +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) + 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) } diff --git a/plugins/rpcloader/interface.go b/plugins/rpcloader/interface.go new file mode 100644 index 000000000..13279b809 --- /dev/null +++ b/plugins/rpcloader/interface.go @@ -0,0 +1,74 @@ +package plugins + +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/rpc" +) + +// 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 +} diff --git a/plugins/rpcloader/rpc_loader.go b/plugins/rpcloader/rpc_loader.go new file mode 100644 index 000000000..3e86b1da3 --- /dev/null +++ b/plugins/rpcloader/rpc_loader.go @@ -0,0 +1,47 @@ +package rpcloader + +import ( + "github.com/ethereum/go-ethereum/node" + "github.com/ethereum/go-ethereum/plugins" +) + +type APILoader func(*node.Node, Backend) []rpc.API + +func GetRPCPluginsFromLoader(pl *plugins.PluginLoader) []APILoader { + result := []APILoader{} + for _, plug := range pl.Plugins { + fn, err := plug.Lookup("GetAPIs") + if err == nil { + apiLoader, ok := fn.(func(*node.Node, Backend) []rpc.API) + if !ok { + log.Warn("Could not cast plugin.GetAPIs to APILoader", "file", fpath) + } else { + result = append(result, APILoader(apiLoader)) + } + } else { log.Debug("Error retrieving GetAPIs for plugin", "file", fpath, "error", err.Error()) } + } +} + +func GetRPCPlugins() []APILoader { + if plugins.DefaultPluginLoader == nil { + log.Warn("Attempting GetRPCPlugins, but default PluginLoader has not been initialized") + return []APILoader{} + } + return GetRPCPluginsFromLoader(plugins.DefaultPluginLoader) + +} +func GetAPIsFromLoader(pl *plugins.PluginLoader, stack *node.Node, backend Backend) []rpc.API { + apis := []rpc.API{} + for _, apiLoader := range pl.RPCPlugins { + apis = append(apis, apiLoader(stack, backend)...) + } + return apis +} + +func GetAPIs(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) +}