From 92ec1c49daebc522a20dcc1e19e24cb8532347e6 Mon Sep 17 00:00:00 2001 From: Ragnar Date: Thu, 27 Feb 2025 01:42:12 +0100 Subject: [PATCH] Update backend.go --- eth/backend.go | 753 +++++++++++++++++++++++-------------------------- 1 file changed, 358 insertions(+), 395 deletions(-) diff --git a/eth/backend.go b/eth/backend.go index f3a8bf3078..2b2680baf7 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -1,4 +1,4 @@ -// Copyright 2014 The go-ethereum Authors +// Copyright 2015 The go-ethereum Authors // This file is part of the go-ethereum library. // // The go-ethereum library is free software: you can redistribute it and/or modify @@ -14,452 +14,415 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -// Package eth implements the Ethereum protocol. package eth import ( - "encoding/json" - "fmt" + "context" + "errors" "math/big" - "runtime" - "sync" "time" + "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/consensus" + "github.com/ethereum/go-ethereum/consensus/misc/eip4844" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/bloombits" "github.com/ethereum/go-ethereum/core/rawdb" - "github.com/ethereum/go-ethereum/core/state/pruner" + "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/txpool" - "github.com/ethereum/go-ethereum/core/txpool/blobpool" - "github.com/ethereum/go-ethereum/core/txpool/legacypool" - "github.com/ethereum/go-ethereum/core/txpool/locals" "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/eth/ethconfig" "github.com/ethereum/go-ethereum/eth/gasprice" - "github.com/ethereum/go-ethereum/eth/protocols/eth" - "github.com/ethereum/go-ethereum/eth/protocols/snap" "github.com/ethereum/go-ethereum/eth/tracers" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" - "github.com/ethereum/go-ethereum/internal/ethapi" - "github.com/ethereum/go-ethereum/internal/shutdowncheck" - "github.com/ethereum/go-ethereum/internal/version" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/miner" - "github.com/ethereum/go-ethereum/node" - "github.com/ethereum/go-ethereum/p2p" - "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/rlp" "github.com/ethereum/go-ethereum/rpc" - gethversion "github.com/ethereum/go-ethereum/version" ) -// Config contains the configuration options of the ETH protocol. -// Deprecated: use ethconfig.Config instead. -type Config = ethconfig.Config - -// Ethereum implements the Ethereum full node service. -type Ethereum struct { - // core protocol objects - config *ethconfig.Config - txPool *txpool.TxPool - localTxTracker *locals.TxTracker - blockchain *core.BlockChain - - handler *handler - discmix *enode.FairMix - - // DB interfaces - chainDb ethdb.Database // Block chain database - - eventMux *event.TypeMux - engine consensus.Engine - accountManager *accounts.Manager - - bloomRequests chan chan *bloombits.Retrieval // Channel receiving bloom data retrieval requests - bloomIndexer *core.ChainIndexer // Bloom indexer operating during block imports - closeBloomHandler chan struct{} - - APIBackend *EthAPIBackend - - miner *miner.Miner - gasPrice *big.Int - - networkID uint64 - netRPCService *ethapi.NetAPI - - p2pServer *p2p.Server - - lock sync.RWMutex // Protects the variadic fields (e.g. gas price and etherbase) - - shutdownTracker *shutdowncheck.ShutdownTracker // Tracks if and when the node has shutdown ungracefully +// EthAPIBackend implements ethapi.Backend and tracers.Backend for full nodes +type EthAPIBackend struct { + extRPCEnabled bool + allowUnprotectedTxs bool + eth *Ethereum + gpo *gasprice.Oracle } -// New creates a new Ethereum object (including the initialisation of the common Ethereum object), -// whose lifecycle will be managed by the provided node. -func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { - // Ensure configuration values are compatible and sane - if !config.SyncMode.IsValid() { - return nil, fmt.Errorf("invalid sync mode %d", config.SyncMode) - } - if config.Miner.GasPrice == nil || config.Miner.GasPrice.Sign() <= 0 { - log.Warn("Sanitizing invalid miner gas price", "provided", config.Miner.GasPrice, "updated", ethconfig.Defaults.Miner.GasPrice) - config.Miner.GasPrice = new(big.Int).Set(ethconfig.Defaults.Miner.GasPrice) - } - if config.NoPruning && config.TrieDirtyCache > 0 { - if config.SnapshotCache > 0 { - config.TrieCleanCache += config.TrieDirtyCache * 3 / 5 - config.SnapshotCache += config.TrieDirtyCache * 2 / 5 - } else { - config.TrieCleanCache += config.TrieDirtyCache - } - config.TrieDirtyCache = 0 - } - log.Info("Allocated trie memory caches", "clean", common.StorageSize(config.TrieCleanCache)*1024*1024, "dirty", common.StorageSize(config.TrieDirtyCache)*1024*1024) +// ChainConfig returns the active chain configuration. +func (b *EthAPIBackend) ChainConfig() *params.ChainConfig { + return b.eth.blockchain.Config() +} - // Assemble the Ethereum object - chainDb, err := stack.OpenDatabaseWithFreezer("chaindata", config.DatabaseCache, config.DatabaseHandles, config.DatabaseFreezer, "eth/db/chaindata/", false) - if err != nil { - return nil, err - } - scheme, err := rawdb.ParseStateScheme(config.StateScheme, chainDb) - if err != nil { - return nil, err - } - // Try to recover offline state pruning only in hash-based. - if scheme == rawdb.HashScheme { - if err := pruner.RecoverPruning(stack.ResolvePath(""), chainDb); err != nil { - log.Error("Failed to recover state", "error", err) - } - } - // Transfer mining-related config to the ethash config. - chainConfig, err := core.LoadChainConfig(chainDb, config.Genesis) - if err != nil { - return nil, err - } - engine, err := ethconfig.CreateConsensusEngine(chainConfig, chainDb) - if err != nil { - return nil, err - } - networkID := config.NetworkId - if networkID == 0 { - networkID = chainConfig.ChainID.Uint64() - } - eth := &Ethereum{ - config: config, - chainDb: chainDb, - eventMux: stack.EventMux(), - accountManager: stack.AccountManager(), - engine: engine, - closeBloomHandler: make(chan struct{}), - networkID: networkID, - gasPrice: config.Miner.GasPrice, - bloomRequests: make(chan chan *bloombits.Retrieval), - bloomIndexer: core.NewBloomIndexer(chainDb, params.BloomBitsBlocks, params.BloomConfirms), - p2pServer: stack.Server(), - discmix: enode.NewFairMix(0), - shutdownTracker: shutdowncheck.NewShutdownTracker(chainDb), - } - bcVersion := rawdb.ReadDatabaseVersion(chainDb) - var dbVer = "" - if bcVersion != nil { - dbVer = fmt.Sprintf("%d", *bcVersion) - } - log.Info("Initialising Ethereum protocol", "network", networkID, "dbversion", dbVer) +func (b *EthAPIBackend) CurrentBlock() *types.Header { + return b.eth.blockchain.CurrentBlock() +} - if !config.SkipBcVersionCheck { - if bcVersion != nil && *bcVersion > core.BlockChainVersion { - return nil, fmt.Errorf("database version is v%d, Geth %s only supports v%d", *bcVersion, version.WithMeta, core.BlockChainVersion) - } else if bcVersion == nil || *bcVersion < core.BlockChainVersion { - if bcVersion != nil { // only print warning on upgrade, not on init - log.Warn("Upgrade blockchain database version", "from", dbVer, "to", core.BlockChainVersion) +func (b *EthAPIBackend) SetHead(number uint64) { + b.eth.handler.downloader.Cancel() + b.eth.blockchain.SetHead(number) +} + +func (b *EthAPIBackend) HeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Header, error) { + // Pending block is only known by the miner + if number == rpc.PendingBlockNumber { + block, _, _ := b.eth.miner.Pending() + if block == nil { + return nil, errors.New("pending block is not available") + } + return block.Header(), nil + } + // Otherwise resolve and return the block + if number == rpc.LatestBlockNumber { + return b.eth.blockchain.CurrentBlock(), nil + } + if number == rpc.FinalizedBlockNumber { + block := b.eth.blockchain.CurrentFinalBlock() + if block == nil { + return nil, errors.New("finalized block not found") + } + return block, nil + } + if number == rpc.SafeBlockNumber { + block := b.eth.blockchain.CurrentSafeBlock() + if block == nil { + return nil, errors.New("safe block not found") + } + return block, nil + } + return b.eth.blockchain.GetHeaderByNumber(uint64(number)), nil +} + +func (b *EthAPIBackend) HeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*types.Header, error) { + if blockNr, ok := blockNrOrHash.Number(); ok { + return b.HeaderByNumber(ctx, blockNr) + } + if hash, ok := blockNrOrHash.Hash(); ok { + header := b.eth.blockchain.GetHeaderByHash(hash) + if header == nil { + return nil, errors.New("header for hash not found") + } + if blockNrOrHash.RequireCanonical && b.eth.blockchain.GetCanonicalHash(header.Number.Uint64()) != hash { + return nil, errors.New("hash is not currently canonical") + } + return header, nil + } + return nil, errors.New("invalid arguments; neither block nor hash specified") +} + +func (b *EthAPIBackend) HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error) { + return b.eth.blockchain.GetHeaderByHash(hash), nil +} + +func (b *EthAPIBackend) BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error) { + // Pending block is only known by the miner + if number == rpc.PendingBlockNumber { + block, _, _ := b.eth.miner.Pending() + if block == nil { + return nil, errors.New("pending block is not available") + } + return block, nil + } + // Otherwise resolve and return the block + if number == rpc.LatestBlockNumber { + header := b.eth.blockchain.CurrentBlock() + return b.eth.blockchain.GetBlock(header.Hash(), header.Number.Uint64()), nil + } + if number == rpc.FinalizedBlockNumber { + header := b.eth.blockchain.CurrentFinalBlock() + if header == nil { + return nil, errors.New("finalized block not found") + } + return b.eth.blockchain.GetBlock(header.Hash(), header.Number.Uint64()), nil + } + if number == rpc.SafeBlockNumber { + header := b.eth.blockchain.CurrentSafeBlock() + if header == nil { + return nil, errors.New("safe block not found") + } + return b.eth.blockchain.GetBlock(header.Hash(), header.Number.Uint64()), nil + } + return b.eth.blockchain.GetBlockByNumber(uint64(number)), nil +} + +func (b *EthAPIBackend) BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) { + return b.eth.blockchain.GetBlockByHash(hash), nil +} + +// GetBody returns body of a block. It does not resolve special block numbers. +func (b *EthAPIBackend) GetBody(ctx context.Context, hash common.Hash, number rpc.BlockNumber) (*types.Body, error) { + if number < 0 || hash == (common.Hash{}) { + return nil, errors.New("invalid arguments; expect hash and no special block numbers") + } + if body := b.eth.blockchain.GetBody(hash); body != nil { + return body, nil + } + return nil, errors.New("block body not found") +} + +func (b *EthAPIBackend) BlockByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*types.Block, error) { + if blockNr, ok := blockNrOrHash.Number(); ok { + return b.BlockByNumber(ctx, blockNr) + } + if hash, ok := blockNrOrHash.Hash(); ok { + header := b.eth.blockchain.GetHeaderByHash(hash) + if header == nil { + return nil, errors.New("header for hash not found") + } + if blockNrOrHash.RequireCanonical && b.eth.blockchain.GetCanonicalHash(header.Number.Uint64()) != hash { + return nil, errors.New("hash is not currently canonical") + } + block := b.eth.blockchain.GetBlock(hash, header.Number.Uint64()) + if block == nil { + return nil, errors.New("header found, but block body is missing") + } + return block, nil + } + return nil, errors.New("invalid arguments; neither block nor hash specified") +} + +func (b *EthAPIBackend) Pending() (*types.Block, types.Receipts, *state.StateDB) { + return b.eth.miner.Pending() +} + +func (b *EthAPIBackend) StateAndHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*state.StateDB, *types.Header, error) { + // Pending state is only known by the miner + if number == rpc.PendingBlockNumber { + block, _, state := b.eth.miner.Pending() + if block == nil || state == nil { + return nil, nil, errors.New("pending state is not available") + } + return state, block.Header(), nil + } + // Otherwise resolve the block number and return its state + header, err := b.HeaderByNumber(ctx, number) + if err != nil { + return nil, nil, err + } + if header == nil { + return nil, nil, errors.New("header not found") + } + stateDb, err := b.eth.BlockChain().StateAt(header.Root) + if err != nil { + return nil, nil, err + } + return stateDb, header, nil +} + +func (b *EthAPIBackend) StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*state.StateDB, *types.Header, error) { + if blockNr, ok := blockNrOrHash.Number(); ok { + return b.StateAndHeaderByNumber(ctx, blockNr) + } + if hash, ok := blockNrOrHash.Hash(); ok { + header, err := b.HeaderByHash(ctx, hash) + if err != nil { + return nil, nil, err + } + if header == nil { + return nil, nil, errors.New("header for hash not found") + } + if blockNrOrHash.RequireCanonical && b.eth.blockchain.GetCanonicalHash(header.Number.Uint64()) != hash { + return nil, nil, errors.New("hash is not currently canonical") + } + stateDb, err := b.eth.BlockChain().StateAt(header.Root) + if err != nil { + return nil, nil, err + } + return stateDb, header, nil + } + return nil, nil, errors.New("invalid arguments; neither block nor hash specified") +} + +func (b *EthAPIBackend) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) { + return b.eth.blockchain.GetReceiptsByHash(hash), nil +} + +func (b *EthAPIBackend) GetLogs(ctx context.Context, hash common.Hash, number uint64) ([][]*types.Log, error) { + return rawdb.ReadLogs(b.eth.chainDb, hash, number), nil +} + +func (b *EthAPIBackend) GetEVM(ctx context.Context, state *state.StateDB, header *types.Header, vmConfig *vm.Config, blockCtx *vm.BlockContext) *vm.EVM { + if vmConfig == nil { + vmConfig = b.eth.blockchain.GetVMConfig() + } + var context vm.BlockContext + if blockCtx != nil { + context = *blockCtx + } else { + context = core.NewEVMBlockContext(header, b.eth.BlockChain(), nil) + } + return vm.NewEVM(context, state, b.ChainConfig(), *vmConfig) +} + +func (b *EthAPIBackend) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription { + return b.eth.BlockChain().SubscribeRemovedLogsEvent(ch) +} + +func (b *EthAPIBackend) SubscribeRemovedLogsReverseEvent(ch chan<- core.RemovedLogsEvent) event.Subscription { + return b.eth.BlockChain().SubscribeRemovedLogsReverseEvent(ch) +} + +func (b *EthAPIBackend) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription { + return b.eth.BlockChain().SubscribeChainEvent(ch) +} + +func (b *EthAPIBackend) SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription { + return b.eth.BlockChain().SubscribeChainHeadEvent(ch) +} + +func (b *EthAPIBackend) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription { + return b.eth.BlockChain().SubscribeLogsEvent(ch) +} + +func (b *EthAPIBackend) SendTx(ctx context.Context, signedTx *types.Transaction) error { + if locals := b.eth.localTxTracker; locals != nil { + locals.Track(signedTx) + } + return b.eth.txPool.Add([]*types.Transaction{signedTx}, false)[0] +} + +func (b *EthAPIBackend) GetPoolTransactions() (types.Transactions, error) { + pending := b.eth.txPool.Pending(txpool.PendingFilter{}) + var txs types.Transactions + for _, batch := range pending { + for _, lazy := range batch { + if tx := lazy.Resolve(); tx != nil { + txs = append(txs, tx) } - rawdb.WriteDatabaseVersion(chainDb, core.BlockChainVersion) } } - var ( - vmConfig = vm.Config{ - EnablePreimageRecording: config.EnablePreimageRecording, - } - cacheConfig = &core.CacheConfig{ - TrieCleanLimit: config.TrieCleanCache, - TrieCleanNoPrefetch: config.NoPrefetch, - TrieDirtyLimit: config.TrieDirtyCache, - TrieDirtyDisabled: config.NoPruning, - TrieTimeLimit: config.TrieTimeout, - SnapshotLimit: config.SnapshotCache, - Preimages: config.Preimages, - StateHistory: config.StateHistory, - StateScheme: scheme, - } - ) - if config.VMTrace != "" { - traceConfig := json.RawMessage("{}") - if config.VMTraceJsonConfig != "" { - traceConfig = json.RawMessage(config.VMTraceJsonConfig) - } - t, err := tracers.LiveDirectory.New(config.VMTrace, traceConfig) - if err != nil { - return nil, fmt.Errorf("failed to create tracer %s: %v", config.VMTrace, err) - } - vmConfig.Tracer = t - } - // Override the chain config with provided settings. - var overrides core.ChainOverrides - if config.OverrideCancun != nil { - overrides.OverrideCancun = config.OverrideCancun - } - if config.OverrideVerkle != nil { - overrides.OverrideVerkle = config.OverrideVerkle - } - eth.blockchain, err = core.NewBlockChain(chainDb, cacheConfig, config.Genesis, &overrides, eth.engine, vmConfig, &config.TransactionHistory) + return txs, nil +} + +func (b *EthAPIBackend) GetPoolTransaction(hash common.Hash) *types.Transaction { + return b.eth.txPool.Get(hash) +} + +// GetTransaction retrieves the lookup along with the transaction itself associate +// with the given transaction hash. +// +// An error will be returned if the transaction is not found, and background +// indexing for transactions is still in progress. The error is used to indicate the +// scenario explicitly that the transaction might be reachable shortly. +// +// A null will be returned in the transaction is not found and background transaction +// indexing is already finished. The transaction is not existent from the perspective +// of node. +func (b *EthAPIBackend) GetTransaction(ctx context.Context, txHash common.Hash) (bool, *types.Transaction, common.Hash, uint64, uint64, error) { + lookup, tx, err := b.eth.blockchain.GetTransactionLookup(txHash) if err != nil { - return nil, err + return false, nil, common.Hash{}, 0, 0, err } - eth.bloomIndexer.Start(eth.blockchain) - - if config.BlobPool.Datadir != "" { - config.BlobPool.Datadir = stack.ResolvePath(config.BlobPool.Datadir) + if lookup == nil || tx == nil { + return false, nil, common.Hash{}, 0, 0, nil } - blobPool := blobpool.New(config.BlobPool, eth.blockchain) - - if config.TxPool.Journal != "" { - config.TxPool.Journal = stack.ResolvePath(config.TxPool.Journal) - } - legacyPool := legacypool.New(config.TxPool, eth.blockchain) - - eth.txPool, err = txpool.New(config.TxPool.PriceLimit, eth.blockchain, []txpool.SubPool{legacyPool, blobPool}) - if err != nil { - return nil, err - } - - if !config.TxPool.NoLocals { - rejournal := config.TxPool.Rejournal - if rejournal < time.Second { - log.Warn("Sanitizing invalid txpool journal time", "provided", rejournal, "updated", time.Second) - rejournal = time.Second - } - eth.localTxTracker = locals.New(config.TxPool.Journal, rejournal, eth.blockchain.Config(), eth.txPool) - stack.RegisterLifecycle(eth.localTxTracker) - } - // Permit the downloader to use the trie cache allowance during fast sync - cacheLimit := cacheConfig.TrieCleanLimit + cacheConfig.TrieDirtyLimit + cacheConfig.SnapshotLimit - if eth.handler, err = newHandler(&handlerConfig{ - NodeID: eth.p2pServer.Self().ID(), - Database: chainDb, - Chain: eth.blockchain, - TxPool: eth.txPool, - Network: networkID, - Sync: config.SyncMode, - BloomCache: uint64(cacheLimit), - EventMux: eth.eventMux, - RequiredBlocks: config.RequiredBlocks, - }); err != nil { - return nil, err - } - - eth.miner = miner.New(eth, config.Miner, eth.engine) - eth.miner.SetExtra(makeExtraData(config.Miner.ExtraData)) - eth.miner.SetPrioAddresses(config.TxPool.Locals) - - eth.APIBackend = &EthAPIBackend{stack.Config().ExtRPCEnabled(), stack.Config().AllowUnprotectedTxs, eth, nil} - if eth.APIBackend.allowUnprotectedTxs { - log.Info("Unprotected transactions allowed") - } - eth.APIBackend.gpo = gasprice.NewOracle(eth.APIBackend, config.GPO, config.Miner.GasPrice) - - // Start the RPC service - eth.netRPCService = ethapi.NewNetAPI(eth.p2pServer, networkID) - - // Register the backend on the node - stack.RegisterAPIs(eth.APIs()) - stack.RegisterProtocols(eth.Protocols()) - stack.RegisterLifecycle(eth) - - // Successful startup; push a marker and check previous unclean shutdowns. - eth.shutdownTracker.MarkStartup() - - return eth, nil + return true, tx, lookup.BlockHash, lookup.BlockIndex, lookup.Index, nil } -func makeExtraData(extra []byte) []byte { - if len(extra) == 0 { - // create default extradata - extra, _ = rlp.EncodeToBytes([]interface{}{ - uint(gethversion.Major<<16 | gethversion.Minor<<8 | gethversion.Patch), - "geth", - runtime.Version(), - runtime.GOOS, - }) - } - if uint64(len(extra)) > params.MaximumExtraDataSize { - log.Warn("Miner extra data exceed limit", "extra", hexutil.Bytes(extra), "limit", params.MaximumExtraDataSize) - extra = nil - } - return extra +func (b *EthAPIBackend) GetPoolNonce(ctx context.Context, addr common.Address) (uint64, error) { + return b.eth.txPool.Nonce(addr), nil } -// APIs return the collection of RPC services the ethereum package offers. -// NOTE, some of these services probably need to be moved to somewhere else. -func (s *Ethereum) APIs() []rpc.API { - apis := ethapi.GetAPIs(s.APIBackend) - - // Append any APIs exposed explicitly by the consensus engine - apis = append(apis, s.engine.APIs(s.BlockChain())...) - - // Append all the local APIs and return - return append(apis, []rpc.API{ - { - Namespace: "miner", - Service: NewMinerAPI(s), - }, { - Namespace: "eth", - Service: downloader.NewDownloaderAPI(s.handler.downloader, s.blockchain, s.eventMux), - }, { - Namespace: "admin", - Service: NewAdminAPI(s), - }, { - Namespace: "debug", - Service: NewDebugAPI(s), - }, { - Namespace: "net", - Service: s.netRPCService, - }, - }...) +func (b *EthAPIBackend) Stats() (runnable int, blocked int) { + return b.eth.txPool.Stats() } -func (s *Ethereum) ResetWithGenesisBlock(gb *types.Block) { - s.blockchain.ResetWithGenesisBlock(gb) +func (b *EthAPIBackend) TxPoolContent() (map[common.Address][]*types.Transaction, map[common.Address][]*types.Transaction) { + return b.eth.txPool.Content() } -func (s *Ethereum) Miner() *miner.Miner { return s.miner } +func (b *EthAPIBackend) TxPoolContentFrom(addr common.Address) ([]*types.Transaction, []*types.Transaction) { + return b.eth.txPool.ContentFrom(addr) +} -func (s *Ethereum) AccountManager() *accounts.Manager { return s.accountManager } -func (s *Ethereum) BlockChain() *core.BlockChain { return s.blockchain } -func (s *Ethereum) TxPool() *txpool.TxPool { return s.txPool } -func (s *Ethereum) EventMux() *event.TypeMux { return s.eventMux } -func (s *Ethereum) Engine() consensus.Engine { return s.engine } -func (s *Ethereum) ChainDb() ethdb.Database { return s.chainDb } -func (s *Ethereum) IsListening() bool { return true } // Always listening -func (s *Ethereum) Downloader() *downloader.Downloader { return s.handler.downloader } -func (s *Ethereum) Synced() bool { return s.handler.synced.Load() } -func (s *Ethereum) SetSynced() { s.handler.enableSyncedFeatures() } -func (s *Ethereum) ArchiveMode() bool { return s.config.NoPruning } -func (s *Ethereum) BloomIndexer() *core.ChainIndexer { return s.bloomIndexer } +func (b *EthAPIBackend) TxPool() *txpool.TxPool { + return b.eth.txPool +} -// Protocols returns all the currently configured -// network protocols to start. -func (s *Ethereum) Protocols() []p2p.Protocol { - protos := eth.MakeProtocols((*ethHandler)(s.handler), s.networkID, s.discmix) - if s.config.SnapshotCache > 0 { - protos = append(protos, snap.MakeProtocols((*snapHandler)(s.handler))...) +func (b *EthAPIBackend) SubscribeNewTxsEvent(ch chan<- core.NewTxsEvent) event.Subscription { + return b.eth.txPool.SubscribeTransactions(ch, true) +} + +func (b *EthAPIBackend) SyncProgress() ethereum.SyncProgress { + prog := b.eth.Downloader().Progress() + if txProg, err := b.eth.blockchain.TxIndexProgress(); err == nil { + prog.TxIndexFinishedBlocks = txProg.Indexed + prog.TxIndexRemainingBlocks = txProg.Remaining } - return protos + return prog } -// Start implements node.Lifecycle, starting all internal goroutines needed by the -// Ethereum protocol implementation. -func (s *Ethereum) Start() error { - if err := s.setupDiscovery(); err != nil { - return err +func (b *EthAPIBackend) SuggestGasTipCap(ctx context.Context) (*big.Int, error) { + return b.gpo.SuggestTipCap(ctx) +} + +func (b *EthAPIBackend) FeeHistory(ctx context.Context, blockCount uint64, lastBlock rpc.BlockNumber, rewardPercentiles []float64) (firstBlock *big.Int, reward [][]*big.Int, baseFee []*big.Int, gasUsedRatio []float64, baseFeePerBlobGas []*big.Int, blobGasUsedRatio []float64, err error) { + return b.gpo.FeeHistory(ctx, blockCount, lastBlock, rewardPercentiles) +} + +func (b *EthAPIBackend) BlobBaseFee(ctx context.Context) *big.Int { + if excess := b.CurrentHeader().ExcessBlobGas; excess != nil { + return eip4844.CalcBlobFee(b.ChainConfig(), b.CurrentHeader()) } - - // Start the bloom bits servicing goroutines - s.startBloomHandlers(params.BloomBitsBlocks) - - // Regularly update shutdown marker - s.shutdownTracker.Start() - - // Start the networking layer - s.handler.Start(s.p2pServer.MaxPeers) return nil } -func (s *Ethereum) setupDiscovery() error { - eth.StartENRUpdater(s.blockchain, s.p2pServer.LocalNode()) - - // Add eth nodes from DNS. - dnsclient := dnsdisc.NewClient(dnsdisc.Config{}) - if len(s.config.EthDiscoveryURLs) > 0 { - iter, err := dnsclient.NewIterator(s.config.EthDiscoveryURLs...) - if err != nil { - return err - } - s.discmix.AddSource(iter) - } - - // Add snap nodes from DNS. - if len(s.config.SnapDiscoveryURLs) > 0 { - iter, err := dnsclient.NewIterator(s.config.SnapDiscoveryURLs...) - if err != nil { - return err - } - s.discmix.AddSource(iter) - } - - // Add DHT nodes from discv5. - if s.p2pServer.DiscoveryV5() != nil { - filter := eth.NewNodeFilter(s.blockchain) - iter := enode.Filter(s.p2pServer.DiscoveryV5().RandomNodes(), filter) - s.discmix.AddSource(iter) - } - - return nil +func (b *EthAPIBackend) ChainDb() ethdb.Database { + return b.eth.ChainDb() } -// Stop implements node.Lifecycle, terminating all internal goroutines used by the -// Ethereum protocol. -func (s *Ethereum) Stop() error { - // Stop all the peer-related stuff first. - s.discmix.Close() - s.handler.Stop() - - // Then stop everything else. - s.bloomIndexer.Close() - close(s.closeBloomHandler) - s.txPool.Close() - s.blockchain.Stop() - s.engine.Close() - - // Clean shutdown marker as the last thing before closing db - s.shutdownTracker.Stop() - - s.chainDb.Close() - s.eventMux.Stop() - - return nil +func (b *EthAPIBackend) EventMux() *event.TypeMux { + return b.eth.EventMux() } -// SyncMode retrieves the current sync mode, either explicitly set, or derived -// from the chain status. -func (s *Ethereum) SyncMode() ethconfig.SyncMode { - // If we're in snap sync mode, return that directly - if s.handler.snapSync.Load() { - return ethconfig.SnapSync - } - // We are probably in full sync, but we might have rewound to before the - // snap sync pivot, check if we should re-enable snap sync. - head := s.blockchain.CurrentBlock() - if pivot := rawdb.ReadLastPivotNumber(s.chainDb); pivot != nil { - if head.Number.Uint64() < *pivot { - return ethconfig.SnapSync - } - } - // We are in a full sync, but the associated head state is missing. To complete - // the head state, forcefully rerun the snap sync. Note it doesn't mean the - // persistent state is corrupted, just mismatch with the head block. - if !s.blockchain.HasState(head.Root) { - log.Info("Reenabled snap sync as chain is stateless") - return ethconfig.SnapSync - } - // Nope, we're really full syncing - return ethconfig.FullSync +func (b *EthAPIBackend) AccountManager() *accounts.Manager { + return b.eth.AccountManager() +} + +func (b *EthAPIBackend) ExtRPCEnabled() bool { + return b.extRPCEnabled +} + +func (b *EthAPIBackend) UnprotectedAllowed() bool { + return b.allowUnprotectedTxs +} + +func (b *EthAPIBackend) RPCGasCap() uint64 { + return b.eth.config.RPCGasCap +} + +func (b *EthAPIBackend) RPCEVMTimeout() time.Duration { + return b.eth.config.RPCEVMTimeout +} + +func (b *EthAPIBackend) RPCTxFeeCap() float64 { + return b.eth.config.RPCTxFeeCap +} + +func (b *EthAPIBackend) BloomStatus() (uint64, uint64) { + sections, _, _ := b.eth.bloomIndexer.Sections() + return params.BloomBitsBlocks, sections +} + +func (b *EthAPIBackend) ServiceFilter(ctx context.Context, session *bloombits.MatcherSession) { + for i := 0; i < bloomFilterThreads; i++ { + go session.Multiplex(bloomRetrievalBatch, bloomRetrievalWait, b.eth.bloomRequests) + } +} + +func (b *EthAPIBackend) Engine() consensus.Engine { + return b.eth.engine +} + +func (b *EthAPIBackend) CurrentHeader() *types.Header { + return b.eth.blockchain.CurrentHeader() +} + +func (b *EthAPIBackend) StateAtBlock(ctx context.Context, block *types.Block, reexec uint64, base *state.StateDB, readOnly bool, preferDisk bool) (*state.StateDB, tracers.StateReleaseFunc, error) { + return b.eth.stateAtBlock(ctx, block, reexec, base, readOnly, preferDisk) +} + +func (b *EthAPIBackend) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*types.Transaction, vm.BlockContext, *state.StateDB, tracers.StateReleaseFunc, error) { + return b.eth.stateAtTransaction(ctx, block, txIndex, reexec) }