github.1485827954.workers.dev/ethereum/go-ethereum@v1.14.3/eth/backend.go (about) 1 // Copyright 2014 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 // Package eth implements the Ethereum protocol. 18 package eth 19 20 import ( 21 "encoding/json" 22 "errors" 23 "fmt" 24 "math/big" 25 "runtime" 26 "sync" 27 28 "github.com/ethereum/go-ethereum/accounts" 29 "github.com/ethereum/go-ethereum/common" 30 "github.com/ethereum/go-ethereum/common/hexutil" 31 "github.com/ethereum/go-ethereum/consensus" 32 "github.com/ethereum/go-ethereum/core" 33 "github.com/ethereum/go-ethereum/core/bloombits" 34 "github.com/ethereum/go-ethereum/core/rawdb" 35 "github.com/ethereum/go-ethereum/core/state/pruner" 36 "github.com/ethereum/go-ethereum/core/txpool" 37 "github.com/ethereum/go-ethereum/core/txpool/blobpool" 38 "github.com/ethereum/go-ethereum/core/txpool/legacypool" 39 "github.com/ethereum/go-ethereum/core/types" 40 "github.com/ethereum/go-ethereum/core/vm" 41 "github.com/ethereum/go-ethereum/eth/downloader" 42 "github.com/ethereum/go-ethereum/eth/ethconfig" 43 "github.com/ethereum/go-ethereum/eth/gasprice" 44 "github.com/ethereum/go-ethereum/eth/protocols/eth" 45 "github.com/ethereum/go-ethereum/eth/protocols/snap" 46 "github.com/ethereum/go-ethereum/eth/tracers" 47 "github.com/ethereum/go-ethereum/ethdb" 48 "github.com/ethereum/go-ethereum/event" 49 "github.com/ethereum/go-ethereum/internal/ethapi" 50 "github.com/ethereum/go-ethereum/internal/shutdowncheck" 51 "github.com/ethereum/go-ethereum/log" 52 "github.com/ethereum/go-ethereum/miner" 53 "github.com/ethereum/go-ethereum/node" 54 "github.com/ethereum/go-ethereum/p2p" 55 "github.com/ethereum/go-ethereum/p2p/dnsdisc" 56 "github.com/ethereum/go-ethereum/p2p/enode" 57 "github.com/ethereum/go-ethereum/params" 58 "github.com/ethereum/go-ethereum/rlp" 59 "github.com/ethereum/go-ethereum/rpc" 60 ) 61 62 // Config contains the configuration options of the ETH protocol. 63 // Deprecated: use ethconfig.Config instead. 64 type Config = ethconfig.Config 65 66 // Ethereum implements the Ethereum full node service. 67 type Ethereum struct { 68 config *ethconfig.Config 69 70 // Handlers 71 txPool *txpool.TxPool 72 73 blockchain *core.BlockChain 74 handler *handler 75 ethDialCandidates enode.Iterator 76 snapDialCandidates enode.Iterator 77 78 // DB interfaces 79 chainDb ethdb.Database // Block chain database 80 81 eventMux *event.TypeMux 82 engine consensus.Engine 83 accountManager *accounts.Manager 84 85 bloomRequests chan chan *bloombits.Retrieval // Channel receiving bloom data retrieval requests 86 bloomIndexer *core.ChainIndexer // Bloom indexer operating during block imports 87 closeBloomHandler chan struct{} 88 89 APIBackend *EthAPIBackend 90 91 miner *miner.Miner 92 gasPrice *big.Int 93 94 networkID uint64 95 netRPCService *ethapi.NetAPI 96 97 p2pServer *p2p.Server 98 99 lock sync.RWMutex // Protects the variadic fields (e.g. gas price and etherbase) 100 101 shutdownTracker *shutdowncheck.ShutdownTracker // Tracks if and when the node has shutdown ungracefully 102 } 103 104 // New creates a new Ethereum object (including the initialisation of the common Ethereum object), 105 // whose lifecycle will be managed by the provided node. 106 func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { 107 // Ensure configuration values are compatible and sane 108 if config.SyncMode == downloader.LightSync { 109 return nil, errors.New("can't run eth.Ethereum in light sync mode, light mode has been deprecated") 110 } 111 if !config.SyncMode.IsValid() { 112 return nil, fmt.Errorf("invalid sync mode %d", config.SyncMode) 113 } 114 if config.Miner.GasPrice == nil || config.Miner.GasPrice.Sign() <= 0 { 115 log.Warn("Sanitizing invalid miner gas price", "provided", config.Miner.GasPrice, "updated", ethconfig.Defaults.Miner.GasPrice) 116 config.Miner.GasPrice = new(big.Int).Set(ethconfig.Defaults.Miner.GasPrice) 117 } 118 if config.NoPruning && config.TrieDirtyCache > 0 { 119 if config.SnapshotCache > 0 { 120 config.TrieCleanCache += config.TrieDirtyCache * 3 / 5 121 config.SnapshotCache += config.TrieDirtyCache * 2 / 5 122 } else { 123 config.TrieCleanCache += config.TrieDirtyCache 124 } 125 config.TrieDirtyCache = 0 126 } 127 log.Info("Allocated trie memory caches", "clean", common.StorageSize(config.TrieCleanCache)*1024*1024, "dirty", common.StorageSize(config.TrieDirtyCache)*1024*1024) 128 129 // Assemble the Ethereum object 130 chainDb, err := stack.OpenDatabaseWithFreezer("chaindata", config.DatabaseCache, config.DatabaseHandles, config.DatabaseFreezer, "eth/db/chaindata/", false) 131 if err != nil { 132 return nil, err 133 } 134 scheme, err := rawdb.ParseStateScheme(config.StateScheme, chainDb) 135 if err != nil { 136 return nil, err 137 } 138 // Try to recover offline state pruning only in hash-based. 139 if scheme == rawdb.HashScheme { 140 if err := pruner.RecoverPruning(stack.ResolvePath(""), chainDb); err != nil { 141 log.Error("Failed to recover state", "error", err) 142 } 143 } 144 // Transfer mining-related config to the ethash config. 145 chainConfig, err := core.LoadChainConfig(chainDb, config.Genesis) 146 if err != nil { 147 return nil, err 148 } 149 engine, err := ethconfig.CreateConsensusEngine(chainConfig, chainDb) 150 if err != nil { 151 return nil, err 152 } 153 networkID := config.NetworkId 154 if networkID == 0 { 155 networkID = chainConfig.ChainID.Uint64() 156 } 157 eth := &Ethereum{ 158 config: config, 159 chainDb: chainDb, 160 eventMux: stack.EventMux(), 161 accountManager: stack.AccountManager(), 162 engine: engine, 163 closeBloomHandler: make(chan struct{}), 164 networkID: networkID, 165 gasPrice: config.Miner.GasPrice, 166 bloomRequests: make(chan chan *bloombits.Retrieval), 167 bloomIndexer: core.NewBloomIndexer(chainDb, params.BloomBitsBlocks, params.BloomConfirms), 168 p2pServer: stack.Server(), 169 shutdownTracker: shutdowncheck.NewShutdownTracker(chainDb), 170 } 171 bcVersion := rawdb.ReadDatabaseVersion(chainDb) 172 var dbVer = "<nil>" 173 if bcVersion != nil { 174 dbVer = fmt.Sprintf("%d", *bcVersion) 175 } 176 log.Info("Initialising Ethereum protocol", "network", networkID, "dbversion", dbVer) 177 178 if !config.SkipBcVersionCheck { 179 if bcVersion != nil && *bcVersion > core.BlockChainVersion { 180 return nil, fmt.Errorf("database version is v%d, Geth %s only supports v%d", *bcVersion, params.VersionWithMeta, core.BlockChainVersion) 181 } else if bcVersion == nil || *bcVersion < core.BlockChainVersion { 182 if bcVersion != nil { // only print warning on upgrade, not on init 183 log.Warn("Upgrade blockchain database version", "from", dbVer, "to", core.BlockChainVersion) 184 } 185 rawdb.WriteDatabaseVersion(chainDb, core.BlockChainVersion) 186 } 187 } 188 var ( 189 vmConfig = vm.Config{ 190 EnablePreimageRecording: config.EnablePreimageRecording, 191 } 192 cacheConfig = &core.CacheConfig{ 193 TrieCleanLimit: config.TrieCleanCache, 194 TrieCleanNoPrefetch: config.NoPrefetch, 195 TrieDirtyLimit: config.TrieDirtyCache, 196 TrieDirtyDisabled: config.NoPruning, 197 TrieTimeLimit: config.TrieTimeout, 198 SnapshotLimit: config.SnapshotCache, 199 Preimages: config.Preimages, 200 StateHistory: config.StateHistory, 201 StateScheme: scheme, 202 } 203 ) 204 if config.VMTrace != "" { 205 var traceConfig json.RawMessage 206 if config.VMTraceJsonConfig != "" { 207 traceConfig = json.RawMessage(config.VMTraceJsonConfig) 208 } 209 t, err := tracers.LiveDirectory.New(config.VMTrace, traceConfig) 210 if err != nil { 211 return nil, fmt.Errorf("Failed to create tracer %s: %v", config.VMTrace, err) 212 } 213 vmConfig.Tracer = t 214 } 215 // Override the chain config with provided settings. 216 var overrides core.ChainOverrides 217 if config.OverrideCancun != nil { 218 overrides.OverrideCancun = config.OverrideCancun 219 } 220 if config.OverrideVerkle != nil { 221 overrides.OverrideVerkle = config.OverrideVerkle 222 } 223 // TODO (MariusVanDerWijden) get rid of shouldPreserve in a follow-up PR 224 shouldPreserve := func(header *types.Header) bool { 225 return false 226 } 227 eth.blockchain, err = core.NewBlockChain(chainDb, cacheConfig, config.Genesis, &overrides, eth.engine, vmConfig, shouldPreserve, &config.TransactionHistory) 228 if err != nil { 229 return nil, err 230 } 231 eth.bloomIndexer.Start(eth.blockchain) 232 233 if config.BlobPool.Datadir != "" { 234 config.BlobPool.Datadir = stack.ResolvePath(config.BlobPool.Datadir) 235 } 236 blobPool := blobpool.New(config.BlobPool, eth.blockchain) 237 238 if config.TxPool.Journal != "" { 239 config.TxPool.Journal = stack.ResolvePath(config.TxPool.Journal) 240 } 241 legacyPool := legacypool.New(config.TxPool, eth.blockchain) 242 243 eth.txPool, err = txpool.New(config.TxPool.PriceLimit, eth.blockchain, []txpool.SubPool{legacyPool, blobPool}) 244 if err != nil { 245 return nil, err 246 } 247 // Permit the downloader to use the trie cache allowance during fast sync 248 cacheLimit := cacheConfig.TrieCleanLimit + cacheConfig.TrieDirtyLimit + cacheConfig.SnapshotLimit 249 if eth.handler, err = newHandler(&handlerConfig{ 250 NodeID: eth.p2pServer.Self().ID(), 251 Database: chainDb, 252 Chain: eth.blockchain, 253 TxPool: eth.txPool, 254 Network: networkID, 255 Sync: config.SyncMode, 256 BloomCache: uint64(cacheLimit), 257 EventMux: eth.eventMux, 258 RequiredBlocks: config.RequiredBlocks, 259 }); err != nil { 260 return nil, err 261 } 262 263 eth.miner = miner.New(eth, config.Miner, eth.engine) 264 eth.miner.SetExtra(makeExtraData(config.Miner.ExtraData)) 265 266 eth.APIBackend = &EthAPIBackend{stack.Config().ExtRPCEnabled(), stack.Config().AllowUnprotectedTxs, eth, nil} 267 if eth.APIBackend.allowUnprotectedTxs { 268 log.Info("Unprotected transactions allowed") 269 } 270 gpoParams := config.GPO 271 if gpoParams.Default == nil { 272 gpoParams.Default = config.Miner.GasPrice 273 } 274 eth.APIBackend.gpo = gasprice.NewOracle(eth.APIBackend, gpoParams) 275 276 // Setup DNS discovery iterators. 277 dnsclient := dnsdisc.NewClient(dnsdisc.Config{}) 278 eth.ethDialCandidates, err = dnsclient.NewIterator(eth.config.EthDiscoveryURLs...) 279 if err != nil { 280 return nil, err 281 } 282 eth.snapDialCandidates, err = dnsclient.NewIterator(eth.config.SnapDiscoveryURLs...) 283 if err != nil { 284 return nil, err 285 } 286 287 // Start the RPC service 288 eth.netRPCService = ethapi.NewNetAPI(eth.p2pServer, networkID) 289 290 // Register the backend on the node 291 stack.RegisterAPIs(eth.APIs()) 292 stack.RegisterProtocols(eth.Protocols()) 293 stack.RegisterLifecycle(eth) 294 295 // Successful startup; push a marker and check previous unclean shutdowns. 296 eth.shutdownTracker.MarkStartup() 297 298 return eth, nil 299 } 300 301 func makeExtraData(extra []byte) []byte { 302 if len(extra) == 0 { 303 // create default extradata 304 extra, _ = rlp.EncodeToBytes([]interface{}{ 305 uint(params.VersionMajor<<16 | params.VersionMinor<<8 | params.VersionPatch), 306 "geth", 307 runtime.Version(), 308 runtime.GOOS, 309 }) 310 } 311 if uint64(len(extra)) > params.MaximumExtraDataSize { 312 log.Warn("Miner extra data exceed limit", "extra", hexutil.Bytes(extra), "limit", params.MaximumExtraDataSize) 313 extra = nil 314 } 315 return extra 316 } 317 318 // APIs return the collection of RPC services the ethereum package offers. 319 // NOTE, some of these services probably need to be moved to somewhere else. 320 func (s *Ethereum) APIs() []rpc.API { 321 apis := ethapi.GetAPIs(s.APIBackend) 322 323 // Append any APIs exposed explicitly by the consensus engine 324 apis = append(apis, s.engine.APIs(s.BlockChain())...) 325 326 // Append all the local APIs and return 327 return append(apis, []rpc.API{ 328 { 329 Namespace: "miner", 330 Service: NewMinerAPI(s), 331 }, { 332 Namespace: "eth", 333 Service: downloader.NewDownloaderAPI(s.handler.downloader, s.blockchain, s.eventMux), 334 }, { 335 Namespace: "admin", 336 Service: NewAdminAPI(s), 337 }, { 338 Namespace: "debug", 339 Service: NewDebugAPI(s), 340 }, { 341 Namespace: "net", 342 Service: s.netRPCService, 343 }, 344 }...) 345 } 346 347 func (s *Ethereum) ResetWithGenesisBlock(gb *types.Block) { 348 s.blockchain.ResetWithGenesisBlock(gb) 349 } 350 351 func (s *Ethereum) Miner() *miner.Miner { return s.miner } 352 353 func (s *Ethereum) AccountManager() *accounts.Manager { return s.accountManager } 354 func (s *Ethereum) BlockChain() *core.BlockChain { return s.blockchain } 355 func (s *Ethereum) TxPool() *txpool.TxPool { return s.txPool } 356 func (s *Ethereum) EventMux() *event.TypeMux { return s.eventMux } 357 func (s *Ethereum) Engine() consensus.Engine { return s.engine } 358 func (s *Ethereum) ChainDb() ethdb.Database { return s.chainDb } 359 func (s *Ethereum) IsListening() bool { return true } // Always listening 360 func (s *Ethereum) Downloader() *downloader.Downloader { return s.handler.downloader } 361 func (s *Ethereum) Synced() bool { return s.handler.synced.Load() } 362 func (s *Ethereum) SetSynced() { s.handler.enableSyncedFeatures() } 363 func (s *Ethereum) ArchiveMode() bool { return s.config.NoPruning } 364 func (s *Ethereum) BloomIndexer() *core.ChainIndexer { return s.bloomIndexer } 365 366 // Protocols returns all the currently configured 367 // network protocols to start. 368 func (s *Ethereum) Protocols() []p2p.Protocol { 369 protos := eth.MakeProtocols((*ethHandler)(s.handler), s.networkID, s.ethDialCandidates) 370 if s.config.SnapshotCache > 0 { 371 protos = append(protos, snap.MakeProtocols((*snapHandler)(s.handler), s.snapDialCandidates)...) 372 } 373 return protos 374 } 375 376 // Start implements node.Lifecycle, starting all internal goroutines needed by the 377 // Ethereum protocol implementation. 378 func (s *Ethereum) Start() error { 379 eth.StartENRUpdater(s.blockchain, s.p2pServer.LocalNode()) 380 381 // Start the bloom bits servicing goroutines 382 s.startBloomHandlers(params.BloomBitsBlocks) 383 384 // Regularly update shutdown marker 385 s.shutdownTracker.Start() 386 387 // Figure out a max peers count based on the server limits 388 maxPeers := s.p2pServer.MaxPeers 389 if s.config.LightServ > 0 { 390 if s.config.LightPeers >= s.p2pServer.MaxPeers { 391 return fmt.Errorf("invalid peer config: light peer count (%d) >= total peer count (%d)", s.config.LightPeers, s.p2pServer.MaxPeers) 392 } 393 maxPeers -= s.config.LightPeers 394 } 395 // Start the networking layer and the light server if requested 396 s.handler.Start(maxPeers) 397 return nil 398 } 399 400 // Stop implements node.Lifecycle, terminating all internal goroutines used by the 401 // Ethereum protocol. 402 func (s *Ethereum) Stop() error { 403 // Stop all the peer-related stuff first. 404 s.ethDialCandidates.Close() 405 s.snapDialCandidates.Close() 406 s.handler.Stop() 407 408 // Then stop everything else. 409 s.bloomIndexer.Close() 410 close(s.closeBloomHandler) 411 s.txPool.Close() 412 s.blockchain.Stop() 413 s.engine.Close() 414 415 // Clean shutdown marker as the last thing before closing db 416 s.shutdownTracker.Stop() 417 418 s.chainDb.Close() 419 s.eventMux.Stop() 420 421 return nil 422 } 423 424 // SyncMode retrieves the current sync mode, either explicitly set, or derived 425 // from the chain status. 426 func (s *Ethereum) SyncMode() downloader.SyncMode { 427 // If we're in snap sync mode, return that directly 428 if s.handler.snapSync.Load() { 429 return downloader.SnapSync 430 } 431 // We are probably in full sync, but we might have rewound to before the 432 // snap sync pivot, check if we should re-enable snap sync. 433 head := s.blockchain.CurrentBlock() 434 if pivot := rawdb.ReadLastPivotNumber(s.chainDb); pivot != nil { 435 if head.Number.Uint64() < *pivot { 436 return downloader.SnapSync 437 } 438 } 439 // We are in a full sync, but the associated head state is missing. To complete 440 // the head state, forcefully rerun the snap sync. Note it doesn't mean the 441 // persistent state is corrupted, just mismatch with the head block. 442 if !s.blockchain.HasState(head.Root) { 443 log.Info("Reenabled snap sync as chain is stateless") 444 return downloader.SnapSync 445 } 446 // Nope, we're really full syncing 447 return downloader.FullSync 448 }