mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-12 23:13:45 +00:00
Update backend.go
This commit is contained in:
parent
3ca2bba92e
commit
92ec1c49da
1 changed files with 358 additions and 395 deletions
753
eth/backend.go
753
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.
|
// This file is part of the go-ethereum library.
|
||||||
//
|
//
|
||||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
// 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
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
// Package eth implements the Ethereum protocol.
|
|
||||||
package eth
|
package eth
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"context"
|
||||||
"fmt"
|
"errors"
|
||||||
"math/big"
|
"math/big"
|
||||||
"runtime"
|
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum"
|
||||||
"github.com/ethereum/go-ethereum/accounts"
|
"github.com/ethereum/go-ethereum/accounts"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"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"
|
||||||
|
"github.com/ethereum/go-ethereum/consensus/misc/eip4844"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/ethereum/go-ethereum/core/bloombits"
|
"github.com/ethereum/go-ethereum/core/bloombits"
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
"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"
|
||||||
"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/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"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/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/eth/tracers"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/event"
|
"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/params"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
gethversion "github.com/ethereum/go-ethereum/version"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Config contains the configuration options of the ETH protocol.
|
// EthAPIBackend implements ethapi.Backend and tracers.Backend for full nodes
|
||||||
// Deprecated: use ethconfig.Config instead.
|
type EthAPIBackend struct {
|
||||||
type Config = ethconfig.Config
|
extRPCEnabled bool
|
||||||
|
allowUnprotectedTxs bool
|
||||||
// Ethereum implements the Ethereum full node service.
|
eth *Ethereum
|
||||||
type Ethereum struct {
|
gpo *gasprice.Oracle
|
||||||
// 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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates a new Ethereum object (including the initialisation of the common Ethereum object),
|
// ChainConfig returns the active chain configuration.
|
||||||
// whose lifecycle will be managed by the provided node.
|
func (b *EthAPIBackend) ChainConfig() *params.ChainConfig {
|
||||||
func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
|
return b.eth.blockchain.Config()
|
||||||
// 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)
|
|
||||||
|
|
||||||
// Assemble the Ethereum object
|
func (b *EthAPIBackend) CurrentBlock() *types.Header {
|
||||||
chainDb, err := stack.OpenDatabaseWithFreezer("chaindata", config.DatabaseCache, config.DatabaseHandles, config.DatabaseFreezer, "eth/db/chaindata/", false)
|
return b.eth.blockchain.CurrentBlock()
|
||||||
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 = "<nil>"
|
|
||||||
if bcVersion != nil {
|
|
||||||
dbVer = fmt.Sprintf("%d", *bcVersion)
|
|
||||||
}
|
|
||||||
log.Info("Initialising Ethereum protocol", "network", networkID, "dbversion", dbVer)
|
|
||||||
|
|
||||||
if !config.SkipBcVersionCheck {
|
func (b *EthAPIBackend) SetHead(number uint64) {
|
||||||
if bcVersion != nil && *bcVersion > core.BlockChainVersion {
|
b.eth.handler.downloader.Cancel()
|
||||||
return nil, fmt.Errorf("database version is v%d, Geth %s only supports v%d", *bcVersion, version.WithMeta, core.BlockChainVersion)
|
b.eth.blockchain.SetHead(number)
|
||||||
} 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) 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 (
|
return txs, nil
|
||||||
vmConfig = vm.Config{
|
}
|
||||||
EnablePreimageRecording: config.EnablePreimageRecording,
|
|
||||||
}
|
func (b *EthAPIBackend) GetPoolTransaction(hash common.Hash) *types.Transaction {
|
||||||
cacheConfig = &core.CacheConfig{
|
return b.eth.txPool.Get(hash)
|
||||||
TrieCleanLimit: config.TrieCleanCache,
|
}
|
||||||
TrieCleanNoPrefetch: config.NoPrefetch,
|
|
||||||
TrieDirtyLimit: config.TrieDirtyCache,
|
// GetTransaction retrieves the lookup along with the transaction itself associate
|
||||||
TrieDirtyDisabled: config.NoPruning,
|
// with the given transaction hash.
|
||||||
TrieTimeLimit: config.TrieTimeout,
|
//
|
||||||
SnapshotLimit: config.SnapshotCache,
|
// An error will be returned if the transaction is not found, and background
|
||||||
Preimages: config.Preimages,
|
// indexing for transactions is still in progress. The error is used to indicate the
|
||||||
StateHistory: config.StateHistory,
|
// scenario explicitly that the transaction might be reachable shortly.
|
||||||
StateScheme: scheme,
|
//
|
||||||
}
|
// 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
|
||||||
if config.VMTrace != "" {
|
// of node.
|
||||||
traceConfig := json.RawMessage("{}")
|
func (b *EthAPIBackend) GetTransaction(ctx context.Context, txHash common.Hash) (bool, *types.Transaction, common.Hash, uint64, uint64, error) {
|
||||||
if config.VMTraceJsonConfig != "" {
|
lookup, tx, err := b.eth.blockchain.GetTransactionLookup(txHash)
|
||||||
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)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return false, nil, common.Hash{}, 0, 0, err
|
||||||
}
|
}
|
||||||
eth.bloomIndexer.Start(eth.blockchain)
|
if lookup == nil || tx == nil {
|
||||||
|
return false, nil, common.Hash{}, 0, 0, nil
|
||||||
if config.BlobPool.Datadir != "" {
|
|
||||||
config.BlobPool.Datadir = stack.ResolvePath(config.BlobPool.Datadir)
|
|
||||||
}
|
}
|
||||||
blobPool := blobpool.New(config.BlobPool, eth.blockchain)
|
return true, tx, lookup.BlockHash, lookup.BlockIndex, lookup.Index, nil
|
||||||
|
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeExtraData(extra []byte) []byte {
|
func (b *EthAPIBackend) GetPoolNonce(ctx context.Context, addr common.Address) (uint64, error) {
|
||||||
if len(extra) == 0 {
|
return b.eth.txPool.Nonce(addr), nil
|
||||||
// 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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// APIs return the collection of RPC services the ethereum package offers.
|
func (b *EthAPIBackend) Stats() (runnable int, blocked int) {
|
||||||
// NOTE, some of these services probably need to be moved to somewhere else.
|
return b.eth.txPool.Stats()
|
||||||
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 (s *Ethereum) ResetWithGenesisBlock(gb *types.Block) {
|
func (b *EthAPIBackend) TxPoolContent() (map[common.Address][]*types.Transaction, map[common.Address][]*types.Transaction) {
|
||||||
s.blockchain.ResetWithGenesisBlock(gb)
|
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 (b *EthAPIBackend) TxPool() *txpool.TxPool {
|
||||||
func (s *Ethereum) BlockChain() *core.BlockChain { return s.blockchain }
|
return b.eth.txPool
|
||||||
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 }
|
|
||||||
|
|
||||||
// Protocols returns all the currently configured
|
func (b *EthAPIBackend) SubscribeNewTxsEvent(ch chan<- core.NewTxsEvent) event.Subscription {
|
||||||
// network protocols to start.
|
return b.eth.txPool.SubscribeTransactions(ch, true)
|
||||||
func (s *Ethereum) Protocols() []p2p.Protocol {
|
}
|
||||||
protos := eth.MakeProtocols((*ethHandler)(s.handler), s.networkID, s.discmix)
|
|
||||||
if s.config.SnapshotCache > 0 {
|
func (b *EthAPIBackend) SyncProgress() ethereum.SyncProgress {
|
||||||
protos = append(protos, snap.MakeProtocols((*snapHandler)(s.handler))...)
|
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
|
func (b *EthAPIBackend) SuggestGasTipCap(ctx context.Context) (*big.Int, error) {
|
||||||
// Ethereum protocol implementation.
|
return b.gpo.SuggestTipCap(ctx)
|
||||||
func (s *Ethereum) Start() error {
|
}
|
||||||
if err := s.setupDiscovery(); err != nil {
|
|
||||||
return err
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Ethereum) setupDiscovery() error {
|
func (b *EthAPIBackend) ChainDb() ethdb.Database {
|
||||||
eth.StartENRUpdater(s.blockchain, s.p2pServer.LocalNode())
|
return b.eth.ChainDb()
|
||||||
|
|
||||||
// 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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop implements node.Lifecycle, terminating all internal goroutines used by the
|
func (b *EthAPIBackend) EventMux() *event.TypeMux {
|
||||||
// Ethereum protocol.
|
return b.eth.EventMux()
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SyncMode retrieves the current sync mode, either explicitly set, or derived
|
func (b *EthAPIBackend) AccountManager() *accounts.Manager {
|
||||||
// from the chain status.
|
return b.eth.AccountManager()
|
||||||
func (s *Ethereum) SyncMode() ethconfig.SyncMode {
|
}
|
||||||
// If we're in snap sync mode, return that directly
|
|
||||||
if s.handler.snapSync.Load() {
|
func (b *EthAPIBackend) ExtRPCEnabled() bool {
|
||||||
return ethconfig.SnapSync
|
return b.extRPCEnabled
|
||||||
}
|
}
|
||||||
// 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.
|
func (b *EthAPIBackend) UnprotectedAllowed() bool {
|
||||||
head := s.blockchain.CurrentBlock()
|
return b.allowUnprotectedTxs
|
||||||
if pivot := rawdb.ReadLastPivotNumber(s.chainDb); pivot != nil {
|
}
|
||||||
if head.Number.Uint64() < *pivot {
|
|
||||||
return ethconfig.SnapSync
|
func (b *EthAPIBackend) RPCGasCap() uint64 {
|
||||||
}
|
return b.eth.config.RPCGasCap
|
||||||
}
|
}
|
||||||
// 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
|
func (b *EthAPIBackend) RPCEVMTimeout() time.Duration {
|
||||||
// persistent state is corrupted, just mismatch with the head block.
|
return b.eth.config.RPCEVMTimeout
|
||||||
if !s.blockchain.HasState(head.Root) {
|
}
|
||||||
log.Info("Reenabled snap sync as chain is stateless")
|
|
||||||
return ethconfig.SnapSync
|
func (b *EthAPIBackend) RPCTxFeeCap() float64 {
|
||||||
}
|
return b.eth.config.RPCTxFeeCap
|
||||||
// Nope, we're really full syncing
|
}
|
||||||
return ethconfig.FullSync
|
|
||||||
|
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)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue