github.com/klaytn/klaytn@v1.12.1/node/cn/backend.go (about) 1 // Modifications Copyright 2018 The klaytn Authors 2 // Copyright 2014 The go-ethereum Authors 3 // This file is part of go-ethereum. 4 // 5 // The go-ethereum library is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Lesser General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // The go-ethereum library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Lesser General Public License for more details. 14 // 15 // You should have received a copy of the GNU Lesser General Public License 16 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 17 // 18 // This file is derived from eth/backend.go (2018/06/04). 19 // Modified and improved for the klaytn development. 20 21 package cn 22 23 import ( 24 "errors" 25 "fmt" 26 "math/big" 27 "os/exec" 28 "runtime" 29 "sync" 30 "time" 31 32 "github.com/klaytn/klaytn" 33 "github.com/klaytn/klaytn/accounts" 34 "github.com/klaytn/klaytn/api" 35 "github.com/klaytn/klaytn/blockchain" 36 "github.com/klaytn/klaytn/blockchain/bloombits" 37 "github.com/klaytn/klaytn/blockchain/state" 38 "github.com/klaytn/klaytn/blockchain/types" 39 "github.com/klaytn/klaytn/common" 40 "github.com/klaytn/klaytn/common/hexutil" 41 "github.com/klaytn/klaytn/consensus" 42 "github.com/klaytn/klaytn/consensus/istanbul" 43 istanbulBackend "github.com/klaytn/klaytn/consensus/istanbul/backend" 44 "github.com/klaytn/klaytn/crypto" 45 "github.com/klaytn/klaytn/datasync/downloader" 46 "github.com/klaytn/klaytn/event" 47 "github.com/klaytn/klaytn/governance" 48 "github.com/klaytn/klaytn/networks/p2p" 49 "github.com/klaytn/klaytn/networks/rpc" 50 "github.com/klaytn/klaytn/node" 51 "github.com/klaytn/klaytn/node/cn/filters" 52 "github.com/klaytn/klaytn/node/cn/gasprice" 53 "github.com/klaytn/klaytn/node/cn/tracers" 54 "github.com/klaytn/klaytn/params" 55 "github.com/klaytn/klaytn/reward" 56 "github.com/klaytn/klaytn/rlp" 57 "github.com/klaytn/klaytn/storage/database" 58 "github.com/klaytn/klaytn/work" 59 ) 60 61 var errCNLightSync = errors.New("can't run cn.CN in light sync mode") 62 63 //go:generate mockgen -destination=node/cn/mocks/lesserver_mock.go -package=mocks github.com/klaytn/klaytn/node/cn LesServer 64 type LesServer interface { 65 Start(srvr p2p.Server) 66 Stop() 67 Protocols() []p2p.Protocol 68 SetBloomBitsIndexer(bbIndexer *blockchain.ChainIndexer) 69 } 70 71 // Miner is an interface of work.Miner used by ServiceChain. 72 // 73 //go:generate mockgen -destination=node/cn/mocks/miner_mock.go -package=mocks github.com/klaytn/klaytn/node/cn Miner 74 type Miner interface { 75 Start() 76 Stop() 77 Register(agent work.Agent) 78 Mining() bool 79 HashRate() (tot int64) 80 SetExtra(extra []byte) error 81 Pending() (*types.Block, *state.StateDB) 82 PendingBlock() *types.Block 83 } 84 85 // BackendProtocolManager is an interface of cn.ProtocolManager used from cn.CN and cn.ServiceChain. 86 // 87 //go:generate mockgen -destination=node/cn/protocolmanager_mock_test.go github.com/klaytn/klaytn/node/cn BackendProtocolManager 88 type BackendProtocolManager interface { 89 Downloader() ProtocolManagerDownloader 90 SetWsEndPoint(wsep string) 91 GetSubProtocols() []p2p.Protocol 92 ProtocolVersion() int 93 ReBroadcastTxs(transactions types.Transactions) 94 SetAcceptTxs() 95 NodeType() common.ConnType 96 Start(maxPeers int) 97 Stop() 98 SetSyncStop(flag bool) 99 } 100 101 // CN implements the Klaytn consensus node service. 102 type CN struct { 103 config *Config 104 chainConfig *params.ChainConfig 105 106 // Handlers 107 txPool work.TxPool 108 blockchain work.BlockChain 109 protocolManager BackendProtocolManager 110 lesServer LesServer 111 112 // DB interfaces 113 chainDB database.DBManager // Block chain database 114 115 eventMux *event.TypeMux 116 engine consensus.Engine 117 accountManager accounts.AccountManager 118 119 bloomRequests chan chan *bloombits.Retrieval // Channel receiving bloom data retrieval requests 120 bloomIndexer *blockchain.ChainIndexer // Bloom indexer operating during block imports 121 closeBloomHandler chan struct{} 122 123 APIBackend *CNAPIBackend 124 125 miner Miner 126 gasPrice *big.Int 127 128 rewardbase common.Address 129 130 networkId uint64 131 netRPCService *api.PublicNetAPI 132 133 lock sync.RWMutex // Protects the variadic fields (e.g. gas price) 134 135 components []interface{} 136 137 governance governance.Engine 138 } 139 140 func (s *CN) AddLesServer(ls LesServer) { 141 s.lesServer = ls 142 ls.SetBloomBitsIndexer(s.bloomIndexer) 143 } 144 145 // senderTxHashIndexer subscribes chainEvent and stores senderTxHash to txHash mapping information. 146 func senderTxHashIndexer(db database.DBManager, chainEvent <-chan blockchain.ChainEvent, subscription event.Subscription) { 147 defer subscription.Unsubscribe() 148 149 for { 150 select { 151 case event := <-chainEvent: 152 var err error 153 batch := db.NewSenderTxHashToTxHashBatch() 154 for _, tx := range event.Block.Transactions() { 155 senderTxHash, ok := tx.SenderTxHash() 156 157 // senderTxHash and txHash are the same if tx is not a fee-delegated tx. 158 // Do not store mapping between senderTxHash and txHash in this case. 159 if !ok { 160 continue 161 } 162 163 txHash := tx.Hash() 164 165 if err = db.PutSenderTxHashToTxHashToBatch(batch, senderTxHash, txHash); err != nil { 166 logger.Error("Failed to store senderTxHash to txHash mapping to database", 167 "blockNum", event.Block.Number(), "senderTxHash", senderTxHash, "txHash", txHash, "err", err) 168 break 169 } 170 } 171 172 if err == nil { 173 batch.Write() 174 batch.Release() 175 } 176 177 case <-subscription.Err(): 178 return 179 } 180 } 181 } 182 183 func checkSyncMode(config *Config) error { 184 if !config.SyncMode.IsValid() { 185 return fmt.Errorf("invalid sync mode %d", config.SyncMode) 186 } 187 if config.SyncMode == downloader.LightSync { 188 return errCNLightSync 189 } 190 return nil 191 } 192 193 func setEngineType(chainConfig *params.ChainConfig) { 194 if chainConfig.Clique != nil { 195 types.EngineType = types.Engine_Clique 196 } 197 if chainConfig.Istanbul != nil { 198 types.EngineType = types.Engine_IBFT 199 } 200 } 201 202 // New creates a new CN object (including the 203 // initialisation of the common CN object) 204 func New(ctx *node.ServiceContext, config *Config) (*CN, error) { 205 if err := checkSyncMode(config); err != nil { 206 return nil, err 207 } 208 209 chainDB := CreateDB(ctx, config, "chaindata") 210 211 chainConfig, genesisHash, genesisErr := blockchain.SetupGenesisBlock(chainDB, config.Genesis, config.NetworkId, config.IsPrivate, false) 212 if _, ok := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !ok { 213 return nil, genesisErr 214 } 215 216 setEngineType(chainConfig) 217 218 // load governance state 219 chainConfig.SetDefaults() 220 // latest values will be applied to chainConfig after NewMixedEngine call 221 governance := governance.NewMixedEngine(chainConfig, chainDB) 222 logger.Info("Initialised chain configuration", "config", chainConfig) 223 224 config.GasPrice = new(big.Int).SetUint64(chainConfig.UnitPrice) 225 226 cn := &CN{ 227 config: config, 228 chainDB: chainDB, 229 chainConfig: chainConfig, 230 eventMux: ctx.EventMux, 231 accountManager: ctx.AccountManager, 232 engine: CreateConsensusEngine(ctx, config, chainConfig, chainDB, governance, ctx.NodeType()), 233 networkId: config.NetworkId, 234 gasPrice: config.GasPrice, 235 rewardbase: config.Rewardbase, 236 bloomRequests: make(chan chan *bloombits.Retrieval), 237 bloomIndexer: NewBloomIndexer(chainDB, params.BloomBitsBlocks), 238 closeBloomHandler: make(chan struct{}), 239 governance: governance, 240 } 241 242 // istanbul BFT. Derive and set node's address using nodekey 243 if cn.chainConfig.Istanbul != nil { 244 governance.SetNodeAddress(crypto.PubkeyToAddress(ctx.NodeKey().PublicKey)) 245 } 246 247 logger.Info("Initialising Klaytn protocol", "versions", cn.engine.Protocol().Versions, "network", config.NetworkId) 248 249 if !config.SkipBcVersionCheck { 250 if err := blockchain.CheckBlockChainVersion(chainDB); err != nil { 251 return nil, err 252 } 253 } 254 var ( 255 vmConfig = config.getVMConfig() 256 cacheConfig = &blockchain.CacheConfig{ 257 ArchiveMode: config.NoPruning, 258 CacheSize: config.TrieCacheSize, 259 BlockInterval: config.TrieBlockInterval, 260 TriesInMemory: config.TriesInMemory, 261 LivePruningRetention: config.LivePruningRetention, 262 TrieNodeCacheConfig: &config.TrieNodeCacheConfig, 263 SenderTxHashIndexing: config.SenderTxHashIndexing, 264 SnapshotCacheSize: config.SnapshotCacheSize, 265 SnapshotAsyncGen: config.SnapshotAsyncGen, 266 } 267 ) 268 269 bc, err := blockchain.NewBlockChain(chainDB, cacheConfig, cn.chainConfig, cn.engine, vmConfig) 270 if err != nil { 271 return nil, err 272 } 273 bc.SetCanonicalBlock(config.StartBlockNumber) 274 275 // Write the live pruning flag to database if the node is started for the first time 276 if config.LivePruning && !chainDB.ReadPruningEnabled() { 277 if bc.CurrentBlock().NumberU64() > 0 { 278 return nil, errors.New("cannot enable live pruning after chain has advanced") 279 } 280 logger.Info("Writing live pruning flag to database") 281 chainDB.WritePruningEnabled() 282 } 283 284 // Live pruning is enabled according to the flag in database 285 // regardless of the command line flag --state.live-pruning 286 // But live pruning is disabled when --state.live-pruning-retention=0 287 if chainDB.ReadPruningEnabled() && config.LivePruningRetention != 0 { 288 logger.Info("Live pruning is enabled", "retention", config.LivePruningRetention) 289 } else if !chainDB.ReadPruningEnabled() { 290 logger.Info("Live pruning is disabled because flag not stored in database") 291 } else if config.LivePruningRetention == 0 { 292 logger.Info("Live pruning is disabled because retention is set to zero") 293 } 294 295 cn.blockchain = bc 296 governance.SetBlockchain(cn.blockchain) 297 if err := governance.UpdateParams(cn.blockchain.CurrentBlock().NumberU64()); err != nil { 298 return nil, err 299 } 300 blockchain.InitDeriveShaWithGov(cn.chainConfig, governance) 301 302 // Synchronize proposerpolicy & useGiniCoeff 303 pset, err := governance.EffectiveParams(bc.CurrentBlock().NumberU64() + 1) 304 if err != nil { 305 return nil, err 306 } 307 if cn.blockchain.Config().Istanbul != nil { 308 cn.blockchain.Config().Istanbul.ProposerPolicy = pset.Policy() 309 } 310 if cn.blockchain.Config().Governance.Reward != nil { 311 cn.blockchain.Config().Governance.Reward.UseGiniCoeff = pset.UseGiniCoeff() 312 } 313 314 if config.SenderTxHashIndexing { 315 ch := make(chan blockchain.ChainEvent, 255) 316 chainEventSubscription := cn.blockchain.SubscribeChainEvent(ch) 317 go senderTxHashIndexer(chainDB, ch, chainEventSubscription) 318 } 319 320 // Rewind the chain in case of an incompatible config upgrade. 321 if compat, ok := genesisErr.(*params.ConfigCompatError); ok { 322 logger.Error("Rewinding chain to upgrade configuration", "err", compat) 323 cn.blockchain.SetHead(compat.RewindTo) 324 chainDB.WriteChainConfig(genesisHash, cn.chainConfig) 325 } 326 cn.bloomIndexer.Start(cn.blockchain) 327 328 if config.TxPool.Journal != "" { 329 config.TxPool.Journal = ctx.ResolvePath(config.TxPool.Journal) 330 } 331 // TODO-Klaytn-ServiceChain: add account creation prevention in the txPool if TxTypeAccountCreation is supported. 332 config.TxPool.NoAccountCreation = config.NoAccountCreation 333 cn.txPool = blockchain.NewTxPool(config.TxPool, cn.chainConfig, bc) 334 governance.SetTxPool(cn.txPool) 335 336 // Permit the downloader to use the trie cache allowance during fast sync 337 cacheLimit := cacheConfig.TrieNodeCacheConfig.LocalCacheSizeMiB 338 if cn.protocolManager, err = NewProtocolManager(cn.chainConfig, config.SyncMode, config.NetworkId, cn.eventMux, cn.txPool, cn.engine, cn.blockchain, chainDB, cacheLimit, ctx.NodeType(), config); err != nil { 339 return nil, err 340 } 341 342 if err := cn.setAcceptTxs(); err != nil { 343 logger.Error("Failed to decode IstanbulExtra", "err", err) 344 } 345 346 cn.protocolManager.SetWsEndPoint(config.WsEndpoint) 347 348 if ctx.NodeType() == common.CONSENSUSNODE { 349 logger.Info("Loaded node keys", 350 "nodeAddress", crypto.PubkeyToAddress(ctx.NodeKey().PublicKey), 351 "nodePublicKey", hexutil.Encode(crypto.FromECDSAPub(&ctx.NodeKey().PublicKey)), 352 "blsPublicKey", hexutil.Encode(ctx.BlsNodeKey().PublicKey().Marshal())) 353 354 if _, err := cn.Rewardbase(); err != nil { 355 logger.Error("Cannot determine the rewardbase address", "err", err) 356 } 357 } 358 359 if pset.Policy() == uint64(istanbul.WeightedRandom) { 360 // NewStakingManager is called with proper non-nil parameters 361 reward.NewStakingManager(cn.blockchain, governance, cn.chainDB) 362 } 363 364 // Governance states which are not yet applied to the db remains at in-memory storage 365 // It disappears during the node restart, so restoration is needed before the sync starts 366 // By calling CreateSnapshot, it restores the gov state snapshots and apply the votes in it 367 // Particularly, the gov.changeSet is also restored here. 368 if err := cn.Engine().CreateSnapshot(cn.blockchain, cn.blockchain.CurrentBlock().NumberU64(), cn.blockchain.CurrentBlock().Hash(), nil); err != nil { 369 logger.Error("CreateSnapshot failed", "err", err) 370 } 371 372 // set worker 373 if config.WorkerDisable { 374 cn.miner = work.NewFakeWorker() 375 // Istanbul backend can be accessed by APIs to call its methods even though the core of the 376 // consensus engine doesn't run. 377 istBackend, ok := cn.engine.(consensus.Istanbul) 378 if ok { 379 istBackend.SetChain(cn.blockchain) 380 } 381 } else { 382 // TODO-Klaytn improve to handle drop transaction on network traffic in PN and EN 383 cn.miner = work.New(cn, cn.chainConfig, cn.EventMux(), cn.engine, ctx.NodeType(), crypto.PubkeyToAddress(ctx.NodeKey().PublicKey), cn.config.TxResendUseLegacy) 384 } 385 386 // istanbul BFT 387 cn.miner.SetExtra(makeExtraData(config.ExtraData)) 388 389 cn.APIBackend = &CNAPIBackend{cn, nil} 390 391 gpoParams := config.GPO 392 393 // NOTE-Klaytn Now we use latest unitPrice 394 // So let's override gpoParams.Default with config.GasPrice 395 gpoParams.Default = config.GasPrice 396 397 cn.APIBackend.gpo = gasprice.NewOracle(cn.APIBackend, gpoParams, cn.txPool) 398 //@TODO Klaytn add core component 399 cn.addComponent(cn.blockchain) 400 cn.addComponent(cn.txPool) 401 cn.addComponent(cn.APIs()) 402 cn.addComponent(cn.ChainDB()) 403 cn.addComponent(cn.engine) 404 405 if config.AutoRestartFlag { 406 daemonPath := config.DaemonPathFlag 407 restartInterval := config.RestartTimeOutFlag 408 if restartInterval <= time.Second { 409 logger.Crit("Invalid auto-restart timeout", "timeout", restartInterval) 410 } 411 412 // Restarts the node with the same configuration if blockNumber is not changed for a specific time. 413 restartTimer := time.AfterFunc(restartInterval, func() { 414 logger.Warn("Restart node", "command", daemonPath+" restart") 415 cmd := exec.Command(daemonPath, "restart") 416 cmd.Run() 417 }) 418 logger.Info("Initialize auto-restart feature", "timeout", restartInterval, "daemonPath", daemonPath) 419 420 go func() { 421 blockChecker := time.NewTicker(time.Second) 422 prevBlockNum := cn.blockchain.CurrentBlock().NumberU64() 423 424 for range blockChecker.C { 425 currentBlockNum := cn.blockchain.CurrentBlock().NumberU64() 426 427 if prevBlockNum != currentBlockNum { 428 prevBlockNum = currentBlockNum 429 restartTimer.Reset(restartInterval) 430 } 431 } 432 }() 433 } 434 435 // Only for KES nodes 436 if config.TrieNodeCacheConfig.RedisSubscribeBlockEnable { 437 go cn.blockchain.BlockSubscriptionLoop(cn.txPool.(*blockchain.TxPool)) 438 } 439 440 if config.DBType == database.RocksDB && config.RocksDBConfig.Secondary { 441 go cn.blockchain.CurrentBlockUpdateLoop(cn.txPool.(*blockchain.TxPool)) 442 } 443 444 return cn, nil 445 } 446 447 // setAcceptTxs sets AcceptTxs flag in 1CN case to receive tx propagation. 448 func (s *CN) setAcceptTxs() error { 449 if s.chainConfig.Istanbul != nil { 450 istanbulExtra, err := types.ExtractIstanbulExtra(s.blockchain.Genesis().Header()) 451 if err != nil { 452 return err 453 } else { 454 if len(istanbulExtra.Validators) == 1 { 455 s.protocolManager.SetAcceptTxs() 456 } 457 } 458 } 459 return nil 460 } 461 462 // add component which may be used in another service component 463 func (s *CN) addComponent(component interface{}) { 464 s.components = append(s.components, component) 465 } 466 467 func (s *CN) Components() []interface{} { 468 return s.components 469 } 470 471 func (s *CN) SetComponents(component []interface{}) { 472 // do nothing 473 } 474 475 // istanbul BFT 476 func makeExtraData(extra []byte) []byte { 477 if len(extra) == 0 { 478 // create default extradata 479 extra, _ = rlp.EncodeToBytes([]interface{}{ 480 uint(params.VersionMajor<<16 | params.VersionMinor<<8 | params.VersionPatch), 481 "klay", 482 runtime.Version(), 483 runtime.GOOS, 484 }) 485 } 486 if uint64(len(extra)) > params.GetMaximumExtraDataSize() { 487 logger.Warn("Miner extra data exceed limit", "extra", hexutil.Bytes(extra), "limit", params.GetMaximumExtraDataSize()) 488 extra = nil 489 } 490 return extra 491 } 492 493 // CreateDB creates the chain database. 494 func CreateDB(ctx *node.ServiceContext, config *Config, name string) database.DBManager { 495 dbc := &database.DBConfig{ 496 Dir: name, DBType: config.DBType, ParallelDBWrite: config.ParallelDBWrite, SingleDB: config.SingleDB, NumStateTrieShards: config.NumStateTrieShards, 497 LevelDBCacheSize: config.LevelDBCacheSize, OpenFilesLimit: database.GetOpenFilesLimit(), LevelDBCompression: config.LevelDBCompression, 498 LevelDBBufferPool: config.LevelDBBufferPool, EnableDBPerfMetrics: config.EnableDBPerfMetrics, RocksDBConfig: &config.RocksDBConfig, DynamoDBConfig: &config.DynamoDBConfig, 499 } 500 return ctx.OpenDatabase(dbc) 501 } 502 503 // CreateConsensusEngine creates the required type of consensus engine instance for a Klaytn service 504 func CreateConsensusEngine(ctx *node.ServiceContext, config *Config, chainConfig *params.ChainConfig, db database.DBManager, gov governance.Engine, nodetype common.ConnType) consensus.Engine { 505 // Only istanbul BFT is allowed in the main net. PoA is supported by service chain 506 if chainConfig.Governance == nil { 507 chainConfig.Governance = params.GetDefaultGovernanceConfig() 508 } 509 return istanbulBackend.New(&istanbulBackend.BackendOpts{ 510 IstanbulConfig: &config.Istanbul, 511 Rewardbase: config.Rewardbase, 512 PrivateKey: ctx.NodeKey(), 513 BlsSecretKey: ctx.BlsNodeKey(), 514 DB: db, 515 Governance: gov, 516 NodeType: nodetype, 517 }) 518 } 519 520 // APIs returns the collection of RPC services the ethereum package offers. 521 // NOTE, some of these services probably need to be moved to somewhere else. 522 func (s *CN) APIs() []rpc.API { 523 apis, ethAPI := api.GetAPIs(s.APIBackend, s.config.DisableUnsafeDebug) 524 525 // Append any APIs exposed explicitly by the consensus engine 526 apis = append(apis, s.engine.APIs(s.BlockChain())...) 527 528 publicFilterAPI := filters.NewPublicFilterAPI(s.APIBackend, false) 529 governanceKlayAPI := governance.NewGovernanceKlayAPI(s.governance, s.blockchain) 530 governanceAPI := governance.NewGovernanceAPI(s.governance) 531 publicDownloaderAPI := downloader.NewPublicDownloaderAPI(s.protocolManager.Downloader(), s.eventMux) 532 privateDownloaderAPI := downloader.NewPrivateDownloaderAPI(s.protocolManager.Downloader()) 533 534 ethAPI.SetPublicFilterAPI(publicFilterAPI) 535 ethAPI.SetGovernanceKlayAPI(governanceKlayAPI) 536 ethAPI.SetGovernanceAPI(governanceAPI) 537 538 // Append all the local APIs and return 539 apis = append(apis, []rpc.API{ 540 { 541 Namespace: "klay", 542 Version: "1.0", 543 Service: NewPublicKlayAPI(s), 544 Public: true, 545 }, { 546 Namespace: "klay", 547 Version: "1.0", 548 Service: publicDownloaderAPI, 549 Public: true, 550 }, { 551 Namespace: "klay", 552 Version: "1.0", 553 Service: publicFilterAPI, 554 Public: true, 555 }, { 556 Namespace: "eth", 557 Version: "1.0", 558 Service: publicDownloaderAPI, 559 Public: true, 560 }, { 561 Namespace: "admin", 562 Version: "1.0", 563 Service: privateDownloaderAPI, 564 }, { 565 Namespace: "admin", 566 Version: "1.0", 567 Service: NewPrivateAdminAPI(s), 568 }, { 569 Namespace: "debug", 570 Version: "1.0", 571 Service: NewPublicDebugAPI(s), 572 Public: false, 573 }, { 574 Namespace: "debug", 575 Version: "1.0", 576 Service: tracers.NewAPI(s.APIBackend), 577 Public: false, 578 }, { 579 Namespace: "debug", 580 Version: "1.0", 581 Service: tracers.NewUnsafeAPI(s.APIBackend), 582 Public: false, 583 IPCOnly: s.config.DisableUnsafeDebug, 584 }, { 585 Namespace: "net", 586 Version: "1.0", 587 Service: s.netRPCService, 588 Public: true, 589 }, { 590 Namespace: "governance", 591 Version: "1.0", 592 Service: governanceAPI, 593 Public: true, 594 }, { 595 Namespace: "klay", 596 Version: "1.0", 597 Service: governanceKlayAPI, 598 Public: true, 599 }, { 600 Namespace: "eth", 601 Version: "1.0", 602 Service: ethAPI, 603 Public: true, 604 }, { 605 Namespace: "debug", 606 Version: "1.0", 607 Service: NewPrivateDebugAPI(s.chainConfig, s), 608 Public: false, 609 IPCOnly: s.config.DisableUnsafeDebug, 610 }, 611 }...) 612 613 return apis 614 } 615 616 func (s *CN) ResetWithGenesisBlock(gb *types.Block) { 617 s.blockchain.ResetWithGenesisBlock(gb) 618 } 619 620 func (s *CN) Rewardbase() (eb common.Address, err error) { 621 s.lock.RLock() 622 rewardbase := s.rewardbase 623 s.lock.RUnlock() 624 625 if rewardbase != (common.Address{}) { 626 return rewardbase, nil 627 } 628 if wallets := s.AccountManager().Wallets(); len(wallets) > 0 { 629 if accounts := wallets[0].Accounts(); len(accounts) > 0 { 630 rewardbase := accounts[0].Address 631 632 s.lock.Lock() 633 s.rewardbase = rewardbase 634 s.lock.Unlock() 635 636 logger.Info("Rewardbase automatically configured", "address", rewardbase) 637 return rewardbase, nil 638 } 639 } 640 641 return common.Address{}, fmt.Errorf("rewardbase must be explicitly specified") 642 } 643 644 func (s *CN) StartMining(local bool) error { 645 if local { 646 // If local (CPU) mining is started, we can disable the transaction rejection 647 // mechanism introduced to speed sync times. CPU mining on mainnet is ludicrous 648 // so none will ever hit this path, whereas marking sync done on CPU mining 649 // will ensure that private networks work in single miner mode too. 650 s.protocolManager.SetAcceptTxs() 651 } 652 go s.miner.Start() 653 return nil 654 } 655 656 func (s *CN) StopMining() { s.miner.Stop() } 657 func (s *CN) IsMining() bool { return s.miner.Mining() } 658 func (s *CN) Miner() Miner { return s.miner } 659 660 func (s *CN) AccountManager() accounts.AccountManager { return s.accountManager } 661 func (s *CN) BlockChain() work.BlockChain { return s.blockchain } 662 func (s *CN) TxPool() work.TxPool { return s.txPool } 663 func (s *CN) EventMux() *event.TypeMux { return s.eventMux } 664 func (s *CN) Engine() consensus.Engine { return s.engine } 665 func (s *CN) ChainDB() database.DBManager { return s.chainDB } 666 func (s *CN) IsListening() bool { return true } // Always listening 667 func (s *CN) ProtocolVersion() int { return s.protocolManager.ProtocolVersion() } 668 func (s *CN) NetVersion() uint64 { return s.networkId } 669 func (s *CN) Progress() klaytn.SyncProgress { return s.protocolManager.Downloader().Progress() } 670 func (s *CN) Governance() governance.Engine { return s.governance } 671 672 func (s *CN) ReBroadcastTxs(transactions types.Transactions) { 673 s.protocolManager.ReBroadcastTxs(transactions) 674 } 675 676 // Protocols implements node.Service, returning all the currently configured 677 // network protocols to start. 678 func (s *CN) Protocols() []p2p.Protocol { 679 if s.lesServer == nil { 680 return s.protocolManager.GetSubProtocols() 681 } 682 return append(s.protocolManager.GetSubProtocols(), s.lesServer.Protocols()...) 683 } 684 685 // Start implements node.Service, starting all internal goroutines needed by the 686 // Klaytn protocol implementation. 687 func (s *CN) Start(srvr p2p.Server) error { 688 // Start the bloom bits servicing goroutines 689 s.startBloomHandlers() 690 691 // Start the RPC service 692 s.netRPCService = api.NewPublicNetAPI(srvr, s.NetVersion()) 693 694 // Figure out a max peers count based on the server limits 695 maxPeers := srvr.MaxPeers() 696 // Start the networking layer and the light server if requested 697 s.protocolManager.Start(maxPeers) 698 if s.lesServer != nil { 699 s.lesServer.Start(srvr) 700 } 701 702 reward.StakingManagerSubscribe() 703 704 return nil 705 } 706 707 // Stop implements node.Service, terminating all internal goroutines used by the 708 // Klaytn protocol. 709 func (s *CN) Stop() error { 710 // Stop all the peer-related stuff first. 711 s.protocolManager.Stop() 712 if s.lesServer != nil { 713 s.lesServer.Stop() 714 } 715 716 // Then stop everything else. 717 s.bloomIndexer.Close() 718 close(s.closeBloomHandler) 719 s.txPool.Stop() 720 s.miner.Stop() 721 reward.StakingManagerUnsubscribe() 722 s.blockchain.Stop() 723 s.chainDB.Close() 724 s.eventMux.Stop() 725 726 return nil 727 }