github.com/bloxroute-labs/bor@v0.1.4/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 "errors" 22 "fmt" 23 "math/big" 24 "runtime" 25 "sync" 26 "sync/atomic" 27 28 "github.com/maticnetwork/bor/accounts" 29 "github.com/maticnetwork/bor/accounts/abi/bind" 30 "github.com/maticnetwork/bor/common" 31 "github.com/maticnetwork/bor/common/hexutil" 32 "github.com/maticnetwork/bor/consensus" 33 "github.com/maticnetwork/bor/consensus/bor" 34 "github.com/maticnetwork/bor/consensus/clique" 35 "github.com/maticnetwork/bor/consensus/ethash" 36 "github.com/maticnetwork/bor/core" 37 "github.com/maticnetwork/bor/core/bloombits" 38 "github.com/maticnetwork/bor/core/rawdb" 39 "github.com/maticnetwork/bor/core/types" 40 "github.com/maticnetwork/bor/core/vm" 41 "github.com/maticnetwork/bor/eth/downloader" 42 "github.com/maticnetwork/bor/eth/filters" 43 "github.com/maticnetwork/bor/eth/gasprice" 44 "github.com/maticnetwork/bor/ethdb" 45 "github.com/maticnetwork/bor/event" 46 "github.com/maticnetwork/bor/internal/ethapi" 47 "github.com/maticnetwork/bor/log" 48 "github.com/maticnetwork/bor/miner" 49 "github.com/maticnetwork/bor/node" 50 "github.com/maticnetwork/bor/p2p" 51 "github.com/maticnetwork/bor/p2p/enr" 52 "github.com/maticnetwork/bor/params" 53 "github.com/maticnetwork/bor/rlp" 54 "github.com/maticnetwork/bor/rpc" 55 ) 56 57 type LesServer interface { 58 Start(srvr *p2p.Server) 59 Stop() 60 APIs() []rpc.API 61 Protocols() []p2p.Protocol 62 SetBloomBitsIndexer(bbIndexer *core.ChainIndexer) 63 SetContractBackend(bind.ContractBackend) 64 } 65 66 // Ethereum implements the Ethereum full node service. 67 type Ethereum struct { 68 config *Config 69 70 // Channel for shutting down the service 71 shutdownChan chan bool 72 73 server *p2p.Server 74 75 // Handlers 76 txPool *core.TxPool 77 blockchain *core.BlockChain 78 protocolManager *ProtocolManager 79 lesServer LesServer 80 81 // DB interfaces 82 chainDb ethdb.Database // Block chain database 83 84 eventMux *event.TypeMux 85 engine consensus.Engine 86 accountManager *accounts.Manager 87 88 bloomRequests chan chan *bloombits.Retrieval // Channel receiving bloom data retrieval requests 89 bloomIndexer *core.ChainIndexer // Bloom indexer operating during block imports 90 91 APIBackend *EthAPIBackend 92 93 miner *miner.Miner 94 gasPrice *big.Int 95 etherbase common.Address 96 97 networkID uint64 98 netRPCService *ethapi.PublicNetAPI 99 100 lock sync.RWMutex // Protects the variadic fields (e.g. gas price and etherbase) 101 } 102 103 func (s *Ethereum) AddLesServer(ls LesServer) { 104 s.lesServer = ls 105 ls.SetBloomBitsIndexer(s.bloomIndexer) 106 } 107 108 // SetClient sets a rpc client which connecting to our local node. 109 func (s *Ethereum) SetContractBackend(backend bind.ContractBackend) { 110 // Pass the rpc client to les server if it is enabled. 111 if s.lesServer != nil { 112 s.lesServer.SetContractBackend(backend) 113 } 114 } 115 116 // New creates a new Ethereum object (including the 117 // initialisation of the common Ethereum object) 118 func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { 119 // Ensure configuration values are compatible and sane 120 if config.SyncMode == downloader.LightSync { 121 return nil, errors.New("can't run eth.Ethereum in light sync mode, use les.LightEthereum") 122 } 123 if !config.SyncMode.IsValid() { 124 return nil, fmt.Errorf("invalid sync mode %d", config.SyncMode) 125 } 126 if config.Miner.GasPrice == nil || config.Miner.GasPrice.Cmp(common.Big0) <= 0 { 127 log.Warn("Sanitizing invalid miner gas price", "provided", config.Miner.GasPrice, "updated", DefaultConfig.Miner.GasPrice) 128 config.Miner.GasPrice = new(big.Int).Set(DefaultConfig.Miner.GasPrice) 129 } 130 if config.NoPruning && config.TrieDirtyCache > 0 { 131 config.TrieCleanCache += config.TrieDirtyCache 132 config.TrieDirtyCache = 0 133 } 134 log.Info("Allocated trie memory caches", "clean", common.StorageSize(config.TrieCleanCache)*1024*1024, "dirty", common.StorageSize(config.TrieDirtyCache)*1024*1024) 135 136 // Assemble the Ethereum object 137 chainDb, err := ctx.OpenDatabaseWithFreezer("chaindata", config.DatabaseCache, config.DatabaseHandles, config.DatabaseFreezer, "eth/db/chaindata/") 138 if err != nil { 139 return nil, err 140 } 141 chainConfig, genesisHash, genesisErr := core.SetupGenesisBlock(chainDb, config.Genesis) 142 if _, ok := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !ok { 143 return nil, genesisErr 144 } 145 log.Info("Initialised chain configuration", "config", chainConfig) 146 147 eth := &Ethereum{ 148 config: config, 149 chainDb: chainDb, 150 eventMux: ctx.EventMux, 151 accountManager: ctx.AccountManager, 152 engine: nil, 153 shutdownChan: make(chan bool), 154 networkID: config.NetworkId, 155 gasPrice: config.Miner.GasPrice, 156 etherbase: config.Miner.Etherbase, 157 bloomRequests: make(chan chan *bloombits.Retrieval), 158 bloomIndexer: NewBloomIndexer(chainDb, params.BloomBitsBlocks, params.BloomConfirms), 159 } 160 161 eth.APIBackend = &EthAPIBackend{ctx.ExtRPCEnabled(), eth, nil} 162 gpoParams := config.GPO 163 if gpoParams.Default == nil { 164 gpoParams.Default = config.Miner.GasPrice 165 } 166 eth.APIBackend.gpo = gasprice.NewOracle(eth.APIBackend, gpoParams) 167 ethAPI := ethapi.NewPublicBlockChainAPI(eth.APIBackend) 168 eth.engine = CreateConsensusEngine(ctx, chainConfig, &config.Ethash, config.Miner.Notify, config.Miner.Noverify, chainDb, ethAPI) 169 170 bcVersion := rawdb.ReadDatabaseVersion(chainDb) 171 var dbVer = "<nil>" 172 if bcVersion != nil { 173 dbVer = fmt.Sprintf("%d", *bcVersion) 174 } 175 log.Info("Initialising Ethereum protocol", "versions", ProtocolVersions, "network", config.NetworkId, "dbversion", dbVer) 176 177 if !config.SkipBcVersionCheck { 178 if bcVersion != nil && *bcVersion > core.BlockChainVersion { 179 return nil, fmt.Errorf("database version is v%d, Geth %s only supports v%d", *bcVersion, params.VersionWithMeta, core.BlockChainVersion) 180 } else if bcVersion == nil || *bcVersion < core.BlockChainVersion { 181 log.Warn("Upgrade blockchain database version", "from", dbVer, "to", core.BlockChainVersion) 182 rawdb.WriteDatabaseVersion(chainDb, core.BlockChainVersion) 183 } 184 } 185 var ( 186 vmConfig = vm.Config{ 187 EnablePreimageRecording: config.EnablePreimageRecording, 188 EWASMInterpreter: config.EWASMInterpreter, 189 EVMInterpreter: config.EVMInterpreter, 190 } 191 cacheConfig = &core.CacheConfig{ 192 TrieCleanLimit: config.TrieCleanCache, 193 TrieCleanNoPrefetch: config.NoPrefetch, 194 TrieDirtyLimit: config.TrieDirtyCache, 195 TrieDirtyDisabled: config.NoPruning, 196 TrieTimeLimit: config.TrieTimeout, 197 } 198 ) 199 200 eth.blockchain, err = core.NewBlockChain(chainDb, cacheConfig, chainConfig, eth.engine, vmConfig, eth.shouldPreserve) 201 eth.engine.VerifyHeader(eth.blockchain, eth.blockchain.CurrentHeader(), true) // TODO think on it 202 203 if err != nil { 204 return nil, err 205 } 206 // Rewind the chain in case of an incompatible config upgrade. 207 if compat, ok := genesisErr.(*params.ConfigCompatError); ok { 208 log.Warn("Rewinding chain to upgrade configuration", "err", compat) 209 eth.blockchain.SetHead(compat.RewindTo) 210 rawdb.WriteChainConfig(chainDb, genesisHash, chainConfig) 211 } 212 eth.bloomIndexer.Start(eth.blockchain) 213 214 if config.TxPool.Journal != "" { 215 config.TxPool.Journal = ctx.ResolvePath(config.TxPool.Journal) 216 } 217 eth.txPool = core.NewTxPool(config.TxPool, chainConfig, eth.blockchain) 218 219 // Permit the downloader to use the trie cache allowance during fast sync 220 cacheLimit := cacheConfig.TrieCleanLimit + cacheConfig.TrieDirtyLimit 221 checkpoint := config.Checkpoint 222 if checkpoint == nil { 223 checkpoint = params.TrustedCheckpoints[genesisHash] 224 } 225 if eth.protocolManager, err = NewProtocolManager(chainConfig, checkpoint, config.SyncMode, config.NetworkId, eth.eventMux, eth.txPool, eth.engine, eth.blockchain, chainDb, cacheLimit, config.Whitelist); err != nil { 226 return nil, err 227 } 228 eth.miner = miner.New(eth, &config.Miner, chainConfig, eth.EventMux(), eth.engine, eth.isLocalBlock) 229 eth.miner.SetExtra(makeExtraData(config.Miner.ExtraData)) 230 231 return eth, nil 232 } 233 234 func makeExtraData(extra []byte) []byte { 235 if len(extra) == 0 { 236 // create default extradata 237 extra, _ = rlp.EncodeToBytes([]interface{}{ 238 uint(params.VersionMajor<<16 | params.VersionMinor<<8 | params.VersionPatch), 239 "bor", 240 runtime.Version(), 241 runtime.GOOS, 242 }) 243 } 244 if uint64(len(extra)) > params.MaximumExtraDataSize { 245 log.Warn("Miner extra data exceed limit", "extra", hexutil.Bytes(extra), "limit", params.MaximumExtraDataSize) 246 extra = nil 247 } 248 return extra 249 } 250 251 // CreateConsensusEngine creates the required type of consensus engine instance for an Ethereum service 252 func CreateConsensusEngine(ctx *node.ServiceContext, chainConfig *params.ChainConfig, config *ethash.Config, notify []string, noverify bool, db ethdb.Database, ee *ethapi.PublicBlockChainAPI) consensus.Engine { 253 // If proof-of-authority is requested, set it up 254 if chainConfig.Clique != nil { 255 return clique.New(chainConfig.Clique, db) 256 } 257 258 // If Matic Bor is requested, set it up 259 if chainConfig.Bor != nil { 260 return bor.New(chainConfig, db, ee) 261 } 262 263 // Otherwise assume proof-of-work 264 switch config.PowMode { 265 case ethash.ModeFake: 266 log.Warn("Ethash used in fake mode") 267 return ethash.NewFaker() 268 case ethash.ModeTest: 269 log.Warn("Ethash used in test mode") 270 return ethash.NewTester(nil, noverify) 271 case ethash.ModeShared: 272 log.Warn("Ethash used in shared mode") 273 return ethash.NewShared() 274 default: 275 engine := ethash.New(ethash.Config{ 276 CacheDir: ctx.ResolvePath(config.CacheDir), 277 CachesInMem: config.CachesInMem, 278 CachesOnDisk: config.CachesOnDisk, 279 DatasetDir: config.DatasetDir, 280 DatasetsInMem: config.DatasetsInMem, 281 DatasetsOnDisk: config.DatasetsOnDisk, 282 }, notify, noverify) 283 engine.SetThreads(-1) // Disable CPU mining 284 return engine 285 } 286 } 287 288 // APIs return the collection of RPC services the ethereum package offers. 289 // NOTE, some of these services probably need to be moved to somewhere else. 290 func (s *Ethereum) APIs() []rpc.API { 291 apis := ethapi.GetAPIs(s.APIBackend) 292 293 // Append any APIs exposed explicitly by the les server 294 if s.lesServer != nil { 295 apis = append(apis, s.lesServer.APIs()...) 296 } 297 // Append any APIs exposed explicitly by the consensus engine 298 apis = append(apis, s.engine.APIs(s.BlockChain())...) 299 300 // Append any APIs exposed explicitly by the les server 301 if s.lesServer != nil { 302 apis = append(apis, s.lesServer.APIs()...) 303 } 304 305 // Append all the local APIs and return 306 return append(apis, []rpc.API{ 307 { 308 Namespace: "eth", 309 Version: "1.0", 310 Service: NewPublicEthereumAPI(s), 311 Public: true, 312 }, { 313 Namespace: "eth", 314 Version: "1.0", 315 Service: NewPublicMinerAPI(s), 316 Public: true, 317 }, { 318 Namespace: "eth", 319 Version: "1.0", 320 Service: downloader.NewPublicDownloaderAPI(s.protocolManager.downloader, s.eventMux), 321 Public: true, 322 }, { 323 Namespace: "miner", 324 Version: "1.0", 325 Service: NewPrivateMinerAPI(s), 326 Public: false, 327 }, { 328 Namespace: "eth", 329 Version: "1.0", 330 Service: filters.NewPublicFilterAPI(s.APIBackend, false), 331 Public: true, 332 }, { 333 Namespace: "admin", 334 Version: "1.0", 335 Service: NewPrivateAdminAPI(s), 336 }, { 337 Namespace: "debug", 338 Version: "1.0", 339 Service: NewPublicDebugAPI(s), 340 Public: true, 341 }, { 342 Namespace: "debug", 343 Version: "1.0", 344 Service: NewPrivateDebugAPI(s), 345 }, { 346 Namespace: "net", 347 Version: "1.0", 348 Service: s.netRPCService, 349 Public: true, 350 }, 351 }...) 352 } 353 354 func (s *Ethereum) ResetWithGenesisBlock(gb *types.Block) { 355 s.blockchain.ResetWithGenesisBlock(gb) 356 } 357 358 func (s *Ethereum) Etherbase() (eb common.Address, err error) { 359 s.lock.RLock() 360 etherbase := s.etherbase 361 s.lock.RUnlock() 362 363 if etherbase != (common.Address{}) { 364 return etherbase, nil 365 } 366 if wallets := s.AccountManager().Wallets(); len(wallets) > 0 { 367 if accounts := wallets[0].Accounts(); len(accounts) > 0 { 368 etherbase := accounts[0].Address 369 370 s.lock.Lock() 371 s.etherbase = etherbase 372 s.lock.Unlock() 373 374 log.Info("Etherbase automatically configured", "address", etherbase) 375 return etherbase, nil 376 } 377 } 378 return common.Address{}, fmt.Errorf("etherbase must be explicitly specified") 379 } 380 381 // isLocalBlock checks whether the specified block is mined 382 // by local miner accounts. 383 // 384 // We regard two types of accounts as local miner account: etherbase 385 // and accounts specified via `txpool.locals` flag. 386 func (s *Ethereum) isLocalBlock(block *types.Block) bool { 387 author, err := s.engine.Author(block.Header()) 388 if err != nil { 389 log.Warn("Failed to retrieve block author", "number", block.NumberU64(), "hash", block.Hash(), "err", err) 390 return false 391 } 392 // Check whether the given address is etherbase. 393 s.lock.RLock() 394 etherbase := s.etherbase 395 s.lock.RUnlock() 396 if author == etherbase { 397 return true 398 } 399 // Check whether the given address is specified by `txpool.local` 400 // CLI flag. 401 for _, account := range s.config.TxPool.Locals { 402 if account == author { 403 return true 404 } 405 } 406 return false 407 } 408 409 // shouldPreserve checks whether we should preserve the given block 410 // during the chain reorg depending on whether the author of block 411 // is a local account. 412 func (s *Ethereum) shouldPreserve(block *types.Block) bool { 413 // The reason we need to disable the self-reorg preserving for clique 414 // is it can be probable to introduce a deadlock. 415 // 416 // e.g. If there are 7 available signers 417 // 418 // r1 A 419 // r2 B 420 // r3 C 421 // r4 D 422 // r5 A [X] F G 423 // r6 [X] 424 // 425 // In the round5, the inturn signer E is offline, so the worst case 426 // is A, F and G sign the block of round5 and reject the block of opponents 427 // and in the round6, the last available signer B is offline, the whole 428 // network is stuck. 429 if _, ok := s.engine.(*clique.Clique); ok { 430 return false 431 } 432 return s.isLocalBlock(block) 433 } 434 435 // SetEtherbase sets the mining reward address. 436 func (s *Ethereum) SetEtherbase(etherbase common.Address) { 437 s.lock.Lock() 438 s.etherbase = etherbase 439 s.lock.Unlock() 440 441 s.miner.SetEtherbase(etherbase) 442 } 443 444 // StartMining starts the miner with the given number of CPU threads. If mining 445 // is already running, this method adjust the number of threads allowed to use 446 // and updates the minimum price required by the transaction pool. 447 func (s *Ethereum) StartMining(threads int) error { 448 // Update the thread count within the consensus engine 449 type threaded interface { 450 SetThreads(threads int) 451 } 452 if th, ok := s.engine.(threaded); ok { 453 log.Info("Updated mining threads", "threads", threads) 454 if threads == 0 { 455 threads = -1 // Disable the miner from within 456 } 457 th.SetThreads(threads) 458 } 459 // If the miner was not running, initialize it 460 if !s.IsMining() { 461 // Propagate the initial price point to the transaction pool 462 s.lock.RLock() 463 price := s.gasPrice 464 s.lock.RUnlock() 465 s.txPool.SetGasPrice(price) 466 467 // Configure the local mining address 468 eb, err := s.Etherbase() 469 if err != nil { 470 log.Error("Cannot start mining without etherbase", "err", err) 471 return fmt.Errorf("etherbase missing: %v", err) 472 } 473 if clique, ok := s.engine.(*clique.Clique); ok { 474 wallet, err := s.accountManager.Find(accounts.Account{Address: eb}) 475 if wallet == nil || err != nil { 476 log.Error("Etherbase account unavailable locally", "err", err) 477 return fmt.Errorf("signer missing: %v", err) 478 } 479 clique.Authorize(eb, wallet.SignData) 480 } 481 if bor, ok := s.engine.(*bor.Bor); ok { 482 wallet, err := s.accountManager.Find(accounts.Account{Address: eb}) 483 if wallet == nil || err != nil { 484 log.Error("Etherbase account unavailable locally", "err", err) 485 return fmt.Errorf("signer missing: %v", err) 486 } 487 bor.Authorize(eb, wallet.SignData) 488 } 489 // If mining is started, we can disable the transaction rejection mechanism 490 // introduced to speed sync times. 491 atomic.StoreUint32(&s.protocolManager.acceptTxs, 1) 492 493 go s.miner.Start(eb) 494 } 495 return nil 496 } 497 498 // StopMining terminates the miner, both at the consensus engine level as well as 499 // at the block creation level. 500 func (s *Ethereum) StopMining() { 501 // Update the thread count within the consensus engine 502 type threaded interface { 503 SetThreads(threads int) 504 } 505 if th, ok := s.engine.(threaded); ok { 506 th.SetThreads(-1) 507 } 508 // Stop the block creating itself 509 s.miner.Stop() 510 } 511 512 func (s *Ethereum) IsMining() bool { return s.miner.Mining() } 513 func (s *Ethereum) Miner() *miner.Miner { return s.miner } 514 515 func (s *Ethereum) AccountManager() *accounts.Manager { return s.accountManager } 516 func (s *Ethereum) BlockChain() *core.BlockChain { return s.blockchain } 517 func (s *Ethereum) TxPool() *core.TxPool { return s.txPool } 518 func (s *Ethereum) EventMux() *event.TypeMux { return s.eventMux } 519 func (s *Ethereum) Engine() consensus.Engine { return s.engine } 520 func (s *Ethereum) ChainDb() ethdb.Database { return s.chainDb } 521 func (s *Ethereum) IsListening() bool { return true } // Always listening 522 func (s *Ethereum) EthVersion() int { return int(ProtocolVersions[0]) } 523 func (s *Ethereum) NetVersion() uint64 { return s.networkID } 524 func (s *Ethereum) Downloader() *downloader.Downloader { return s.protocolManager.downloader } 525 func (s *Ethereum) Synced() bool { return atomic.LoadUint32(&s.protocolManager.acceptTxs) == 1 } 526 func (s *Ethereum) ArchiveMode() bool { return s.config.NoPruning } 527 528 // Protocols implements node.Service, returning all the currently configured 529 // network protocols to start. 530 func (s *Ethereum) Protocols() []p2p.Protocol { 531 protos := make([]p2p.Protocol, len(ProtocolVersions)) 532 for i, vsn := range ProtocolVersions { 533 protos[i] = s.protocolManager.makeProtocol(vsn) 534 protos[i].Attributes = []enr.Entry{s.currentEthEntry()} 535 } 536 if s.lesServer != nil { 537 protos = append(protos, s.lesServer.Protocols()...) 538 } 539 return protos 540 } 541 542 // Start implements node.Service, starting all internal goroutines needed by the 543 // Ethereum protocol implementation. 544 func (s *Ethereum) Start(srvr *p2p.Server) error { 545 s.startEthEntryUpdate(srvr.LocalNode()) 546 547 // Start the bloom bits servicing goroutines 548 s.startBloomHandlers(params.BloomBitsBlocks) 549 550 // Start the RPC service 551 s.netRPCService = ethapi.NewPublicNetAPI(srvr, s.NetVersion()) 552 553 // Figure out a max peers count based on the server limits 554 maxPeers := srvr.MaxPeers 555 if s.config.LightServ > 0 { 556 if s.config.LightPeers >= srvr.MaxPeers { 557 return fmt.Errorf("invalid peer config: light peer count (%d) >= total peer count (%d)", s.config.LightPeers, srvr.MaxPeers) 558 } 559 maxPeers -= s.config.LightPeers 560 } 561 // Start the networking layer and the light server if requested 562 s.protocolManager.Start(maxPeers) 563 if s.lesServer != nil { 564 s.lesServer.Start(srvr) 565 } 566 return nil 567 } 568 569 // Stop implements node.Service, terminating all internal goroutines used by the 570 // Ethereum protocol. 571 func (s *Ethereum) Stop() error { 572 s.bloomIndexer.Close() 573 s.blockchain.Stop() 574 s.engine.Close() 575 s.protocolManager.Stop() 576 if s.lesServer != nil { 577 s.lesServer.Stop() 578 } 579 s.txPool.Stop() 580 s.miner.Stop() 581 s.eventMux.Stop() 582 583 s.chainDb.Close() 584 close(s.shutdownChan) 585 return nil 586 }