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)
}