github.com/Gessiux/neatchain@v1.3.1/neatptc/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 neatptc implements the Ethereum protocol. 18 package neatptc 19 20 import ( 21 "errors" 22 "fmt" 23 "math/big" 24 "runtime" 25 "sync" 26 "sync/atomic" 27 28 "github.com/Gessiux/neatchain/chain/accounts" 29 "github.com/Gessiux/neatchain/chain/consensus" 30 "github.com/Gessiux/neatchain/chain/consensus/neatcon" 31 ntcBackend "github.com/Gessiux/neatchain/chain/consensus/neatcon" 32 "github.com/Gessiux/neatchain/chain/core" 33 "github.com/Gessiux/neatchain/chain/core/bloombits" 34 "github.com/Gessiux/neatchain/chain/core/datareduction" 35 "github.com/Gessiux/neatchain/chain/core/rawdb" 36 "github.com/Gessiux/neatchain/chain/core/types" 37 "github.com/Gessiux/neatchain/chain/core/vm" 38 "github.com/Gessiux/neatchain/chain/log" 39 "github.com/Gessiux/neatchain/internal/neatapi" 40 "github.com/Gessiux/neatchain/neatdb" 41 "github.com/Gessiux/neatchain/neatptc/downloader" 42 "github.com/Gessiux/neatchain/neatptc/filters" 43 "github.com/Gessiux/neatchain/neatptc/gasprice" 44 "github.com/Gessiux/neatchain/network/node" 45 "github.com/Gessiux/neatchain/network/p2p" 46 "github.com/Gessiux/neatchain/network/rpc" 47 "github.com/Gessiux/neatchain/params" 48 "github.com/Gessiux/neatchain/utilities/common" 49 "github.com/Gessiux/neatchain/utilities/common/hexutil" 50 "github.com/Gessiux/neatchain/utilities/event" 51 "github.com/Gessiux/neatchain/utilities/miner" 52 "github.com/Gessiux/neatchain/utilities/rlp" 53 "gopkg.in/urfave/cli.v1" 54 ) 55 56 type LesServer interface { 57 Start(srvr *p2p.Server) 58 Stop() 59 Protocols() []p2p.Protocol 60 SetBloomBitsIndexer(bbIndexer *core.ChainIndexer) 61 } 62 63 // NeatChain implements the NEAT Chain full node service. 64 type NeatChain struct { 65 config *Config 66 chainConfig *params.ChainConfig 67 68 // Channel for shutting down the service 69 shutdownChan chan bool // Channel for shutting down the neatChain 70 71 // Handlers 72 txPool *core.TxPool 73 blockchain *core.BlockChain 74 protocolManager *ProtocolManager 75 76 // DB interfaces 77 chainDb neatdb.Database // Block chain database 78 pruneDb neatdb.Database // Prune data database 79 80 eventMux *event.TypeMux 81 engine consensus.NeatCon 82 accountManager *accounts.Manager 83 84 bloomRequests chan chan *bloombits.Retrieval // Channel receiving bloom data retrieval requests 85 bloomIndexer *core.ChainIndexer // Bloom indexer operating during block imports 86 87 ApiBackend *EthApiBackend 88 89 miner *miner.Miner 90 gasPrice *big.Int 91 coinbase common.Address 92 solcPath string 93 94 networkId uint64 95 netRPCService *neatapi.PublicNetAPI 96 97 lock sync.RWMutex // Protects the variadic fields (e.g. gas price and etherbase) 98 } 99 100 // New creates a new NEAT Chain object (including the 101 // initialisation of the common NEAT Chain object) 102 func New(ctx *node.ServiceContext, config *Config, cliCtx *cli.Context, 103 cch core.CrossChainHelper, logger log.Logger, isTestnet bool) (*NeatChain, error) { 104 105 if !config.SyncMode.IsValid() { 106 return nil, fmt.Errorf("invalid sync mode %d", config.SyncMode) 107 } 108 chainDb, err := ctx.OpenDatabase("chaindata", config.DatabaseCache, config.DatabaseHandles, "neatchain/db/chaindata/") 109 if err != nil { 110 return nil, err 111 } 112 pruneDb, err := ctx.OpenDatabase("prunedata", config.DatabaseCache, config.DatabaseHandles, "neatchain/db/prune/") 113 if err != nil { 114 return nil, err 115 } 116 117 isMainChain := params.IsMainChain(ctx.ChainId()) 118 119 chainConfig, genesisHash, genesisErr := core.SetupGenesisBlockWithDefault(chainDb, config.Genesis, isMainChain, isTestnet) 120 if _, ok := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !ok { 121 return nil, genesisErr 122 } 123 chainConfig.ChainLogger = logger 124 //logger.Info("Initialised chain configuration", "config", chainConfig) 125 126 neatChain := &NeatChain{ 127 config: config, 128 chainDb: chainDb, 129 pruneDb: pruneDb, 130 chainConfig: chainConfig, 131 eventMux: ctx.EventMux, 132 accountManager: ctx.AccountManager, 133 engine: CreateConsensusEngine(ctx, config, chainConfig, chainDb, cliCtx, cch), 134 shutdownChan: make(chan bool), 135 networkId: config.NetworkId, 136 gasPrice: config.MinerGasPrice, 137 coinbase: config.Coinbase, 138 solcPath: config.SolcPath, 139 bloomRequests: make(chan chan *bloombits.Retrieval), 140 bloomIndexer: NewBloomIndexer(chainDb, params.BloomBitsBlocks), 141 } 142 143 bcVersion := rawdb.ReadDatabaseVersion(chainDb) 144 var dbVer = "<nil>" 145 if bcVersion != nil { 146 dbVer = fmt.Sprintf("%d", *bcVersion) 147 } 148 logger.Info("Initialising Neatio protocol", "Network", chainConfig.NeatChainId) 149 150 if !config.SkipBcVersionCheck { 151 if bcVersion != nil && *bcVersion > core.BlockChainVersion { 152 return nil, fmt.Errorf("database version is v%d, Neatio %s only supports v%d", *bcVersion, params.VersionWithMeta, core.BlockChainVersion) 153 } else if bcVersion == nil || *bcVersion < core.BlockChainVersion { 154 logger.Warn("Upgrade blockchain database version", "from", dbVer, "to", core.BlockChainVersion) 155 rawdb.WriteDatabaseVersion(chainDb, core.BlockChainVersion) 156 } 157 } 158 var ( 159 vmConfig = vm.Config{EnablePreimageRecording: config.EnablePreimageRecording} 160 cacheConfig = &core.CacheConfig{ 161 TrieCleanLimit: config.TrieCleanCache, 162 163 TrieDirtyLimit: config.TrieDirtyCache, 164 TrieDirtyDisabled: config.NoPruning, 165 TrieTimeLimit: config.TrieTimeout, 166 } 167 ) 168 169 neatChain.blockchain, err = core.NewBlockChain(chainDb, cacheConfig, neatChain.chainConfig, neatChain.engine, vmConfig, cch) 170 if err != nil { 171 return nil, err 172 } 173 174 // Rewind the chain in case of an incompatible config upgrade. 175 if compat, ok := genesisErr.(*params.ConfigCompatError); ok { 176 logger.Warn("Rewinding chain to upgrade configuration", "err", compat) 177 neatChain.blockchain.SetHead(compat.RewindTo) 178 rawdb.WriteChainConfig(chainDb, genesisHash, chainConfig) 179 } 180 neatChain.bloomIndexer.Start(neatChain.blockchain) 181 182 if config.TxPool.Journal != "" { 183 config.TxPool.Journal = ctx.ResolvePath(config.TxPool.Journal) 184 } 185 neatChain.txPool = core.NewTxPool(config.TxPool, neatChain.chainConfig, neatChain.blockchain, cch) 186 187 if neatChain.protocolManager, err = NewProtocolManager(neatChain.chainConfig, config.SyncMode, config.NetworkId, neatChain.eventMux, neatChain.txPool, neatChain.engine, neatChain.blockchain, chainDb, cch); err != nil { 188 return nil, err 189 } 190 neatChain.miner = miner.New(neatChain, neatChain.chainConfig, neatChain.EventMux(), neatChain.engine, config.MinerGasFloor, config.MinerGasCeil, cch) 191 neatChain.miner.SetExtra(makeExtraData(config.ExtraData)) 192 193 neatChain.ApiBackend = &EthApiBackend{neatChain, nil, cch} 194 gpoParams := config.GPO 195 if gpoParams.Default == nil { 196 gpoParams.Default = config.MinerGasPrice 197 } 198 neatChain.ApiBackend.gpo = gasprice.NewOracle(neatChain.ApiBackend, gpoParams) 199 200 return neatChain, nil 201 } 202 203 func makeExtraData(extra []byte) []byte { 204 if len(extra) == 0 { 205 // create default extradata 206 extra, _ = rlp.EncodeToBytes([]interface{}{ 207 uint(params.VersionMajor<<16 | params.VersionMinor<<8 | params.VersionPatch), 208 "neatchain", 209 runtime.Version(), 210 runtime.GOOS, 211 }) 212 } 213 if uint64(len(extra)) > params.MaximumExtraDataSize { 214 log.Warn("Miner extra data exceed limit", "extra", hexutil.Bytes(extra), "limit", params.MaximumExtraDataSize) 215 extra = nil 216 } 217 return extra 218 } 219 220 // CreateConsensusEngine creates the required type of consensus engine instance for an NeatChain service 221 func CreateConsensusEngine(ctx *node.ServiceContext, config *Config, chainConfig *params.ChainConfig, db neatdb.Database, 222 cliCtx *cli.Context, cch core.CrossChainHelper) consensus.NeatCon { 223 // If NeatCon is requested, set it up 224 if chainConfig.NeatCon.Epoch != 0 { 225 config.NeatCon.Epoch = chainConfig.NeatCon.Epoch 226 } 227 config.NeatCon.ProposerPolicy = neatcon.ProposerPolicy(chainConfig.NeatCon.ProposerPolicy) 228 return ntcBackend.New(chainConfig, cliCtx, ctx.NodeKey(), cch) 229 } 230 231 // APIs returns the collection of RPC services the NeatChain package offers. 232 // NOTE, some of these services probably need to be moved to somewhere else. 233 func (s *NeatChain) APIs() []rpc.API { 234 235 apis := neatapi.GetAPIs(s.ApiBackend, s.solcPath) 236 // Append any APIs exposed explicitly by the consensus engine 237 apis = append(apis, s.engine.APIs(s.BlockChain())...) 238 // Append all the local APIs and return 239 apis = append(apis, []rpc.API{ 240 { 241 Namespace: "eth", 242 Version: "1.0", 243 Service: NewPublicEthereumAPI(s), 244 Public: true, 245 }, { 246 Namespace: "eth", 247 Version: "1.0", 248 Service: NewPublicMinerAPI(s), 249 Public: true, 250 }, { 251 Namespace: "eth", 252 Version: "1.0", 253 Service: downloader.NewPublicDownloaderAPI(s.protocolManager.downloader, s.eventMux), 254 Public: true, 255 }, { 256 Namespace: "neat", 257 Version: "1.0", 258 Service: NewPublicEthereumAPI(s), 259 Public: true, 260 }, { 261 Namespace: "neat", 262 Version: "1.0", 263 Service: NewPublicMinerAPI(s), 264 Public: true, 265 }, { 266 Namespace: "neat", 267 Version: "1.0", 268 Service: downloader.NewPublicDownloaderAPI(s.protocolManager.downloader, s.eventMux), 269 Public: true, 270 }, { 271 Namespace: "miner", 272 Version: "1.0", 273 Service: NewPrivateMinerAPI(s), 274 Public: false, 275 }, { 276 Namespace: "eth", 277 Version: "1.0", 278 Service: filters.NewPublicFilterAPI(s.ApiBackend, false), 279 Public: true, 280 }, { 281 Namespace: "neat", 282 Version: "1.0", 283 Service: filters.NewPublicFilterAPI(s.ApiBackend, false), 284 Public: true, 285 }, { 286 Namespace: "admin", 287 Version: "1.0", 288 Service: NewPrivateAdminAPI(s), 289 }, { 290 Namespace: "debug", 291 Version: "1.0", 292 Service: NewPublicDebugAPI(s), 293 Public: true, 294 }, { 295 Namespace: "debug", 296 Version: "1.0", 297 Service: NewPrivateDebugAPI(s.chainConfig, s), 298 }, { 299 Namespace: "net", 300 Version: "1.0", 301 Service: s.netRPCService, 302 Public: true, 303 }, 304 }...) 305 return apis 306 } 307 308 func (s *NeatChain) ResetWithGenesisBlock(gb *types.Block) { 309 s.blockchain.ResetWithGenesisBlock(gb) 310 } 311 312 func (s *NeatChain) Coinbase() (eb common.Address, err error) { 313 if neatcon, ok := s.engine.(consensus.NeatCon); ok { 314 eb = neatcon.PrivateValidator() 315 if eb != (common.Address{}) { 316 return eb, nil 317 } else { 318 return eb, errors.New("private validator missing") 319 } 320 } else { 321 s.lock.RLock() 322 coinbase := s.coinbase 323 s.lock.RUnlock() 324 325 if coinbase != (common.Address{}) { 326 return coinbase, nil 327 } 328 if wallets := s.AccountManager().Wallets(); len(wallets) > 0 { 329 if accounts := wallets[0].Accounts(); len(accounts) > 0 { 330 coinbase := accounts[0].Address 331 332 s.lock.Lock() 333 s.coinbase = coinbase 334 s.lock.Unlock() 335 336 log.Info("Coinbase automatically configured", "address", coinbase) 337 return coinbase, nil 338 } 339 } 340 } 341 return common.Address{}, fmt.Errorf("Base address must be explicitly specified") 342 } 343 344 // set in js console via admin interface or wrapper from cli flags 345 func (self *NeatChain) SetCoinbase(coinbase common.Address) { 346 347 self.lock.Lock() 348 self.coinbase = coinbase 349 self.lock.Unlock() 350 351 self.miner.SetCoinbase(coinbase) 352 } 353 354 func (s *NeatChain) StartMining(local bool) error { 355 var eb common.Address 356 if neatcon, ok := s.engine.(consensus.NeatCon); ok { 357 eb = neatcon.PrivateValidator() 358 if (eb == common.Address{}) { 359 log.Error("Cannot start minting without private validator") 360 return errors.New("private validator file missing") 361 } 362 } else { 363 _, err := s.Coinbase() 364 if err != nil { 365 log.Error("Cannot start mining without base address", "err", err) 366 return fmt.Errorf("base address missing: %v", err) 367 } 368 } 369 370 if local { 371 // If local (CPU) mining is started, we can disable the transaction rejection 372 // mechanism introduced to speed sync times. CPU mining on mainnet is ludicrous 373 // so noone will ever hit this path, whereas marking sync done on CPU mining 374 // will ensure that private networks work in single miner mode too. 375 atomic.StoreUint32(&s.protocolManager.acceptTxs, 1) 376 } 377 go s.miner.Start(eb) 378 return nil 379 } 380 381 func (s *NeatChain) StopMining() { s.miner.Stop() } 382 func (s *NeatChain) IsMining() bool { return s.miner.Mining() } 383 func (s *NeatChain) Miner() *miner.Miner { return s.miner } 384 385 func (s *NeatChain) ChainConfig() *params.ChainConfig { return s.chainConfig } 386 func (s *NeatChain) AccountManager() *accounts.Manager { return s.accountManager } 387 func (s *NeatChain) BlockChain() *core.BlockChain { return s.blockchain } 388 func (s *NeatChain) TxPool() *core.TxPool { return s.txPool } 389 func (s *NeatChain) EventMux() *event.TypeMux { return s.eventMux } 390 func (s *NeatChain) Engine() consensus.NeatCon { return s.engine } 391 func (s *NeatChain) ChainDb() neatdb.Database { return s.chainDb } 392 func (s *NeatChain) IsListening() bool { return true } // Always listening 393 func (s *NeatChain) EthVersion() int { return int(s.protocolManager.SubProtocols[0].Version) } 394 func (s *NeatChain) NetVersion() uint64 { return s.networkId } 395 func (s *NeatChain) Downloader() *downloader.Downloader { return s.protocolManager.downloader } 396 397 // Protocols implements node.Service, returning all the currently configured 398 // network protocols to start. 399 func (s *NeatChain) Protocols() []p2p.Protocol { 400 return s.protocolManager.SubProtocols 401 } 402 403 // Start implements node.Service, starting all internal goroutines needed by the 404 // NeatChain protocol implementation. 405 func (s *NeatChain) Start(srvr *p2p.Server) error { 406 // Start the bloom bits servicing goroutines 407 s.startBloomHandlers() 408 409 // Start the RPC service 410 s.netRPCService = neatapi.NewPublicNetAPI(srvr, s.NetVersion()) 411 412 // Figure out a max peers count based on the server limits 413 maxPeers := srvr.MaxPeers 414 415 // Start the networking layer and the light server if requested 416 s.protocolManager.Start(maxPeers) 417 418 // Start the Auto Mining Loop 419 go s.loopForMiningEvent() 420 421 // Start the Data Reduction 422 if s.config.PruneStateData && s.chainConfig.NeatChainId == "side_0" { 423 go s.StartScanAndPrune(0) 424 } 425 426 return nil 427 } 428 429 // Stop implements node.Service, terminating all internal goroutines used by the 430 // NeatChain protocol. 431 func (s *NeatChain) Stop() error { 432 s.bloomIndexer.Close() 433 s.blockchain.Stop() 434 s.protocolManager.Stop() 435 s.txPool.Stop() 436 s.miner.Stop() 437 s.engine.Close() 438 s.miner.Close() 439 s.eventMux.Stop() 440 441 s.chainDb.Close() 442 s.pruneDb.Close() 443 close(s.shutdownChan) 444 445 return nil 446 } 447 448 func (s *NeatChain) loopForMiningEvent() { 449 // Start/Stop mining Feed 450 startMiningCh := make(chan core.StartMiningEvent, 1) 451 startMiningSub := s.blockchain.SubscribeStartMiningEvent(startMiningCh) 452 453 stopMiningCh := make(chan core.StopMiningEvent, 1) 454 stopMiningSub := s.blockchain.SubscribeStopMiningEvent(stopMiningCh) 455 456 defer startMiningSub.Unsubscribe() 457 defer stopMiningSub.Unsubscribe() 458 459 for { 460 select { 461 case <-startMiningCh: 462 if !s.IsMining() { 463 s.lock.RLock() 464 price := s.gasPrice 465 s.lock.RUnlock() 466 s.txPool.SetGasPrice(price) 467 s.chainConfig.ChainLogger.Info("NeatCon Consensus Engine will start shortly") 468 s.engine.(consensus.NeatCon).ForceStart() 469 s.StartMining(true) 470 } else { 471 s.chainConfig.ChainLogger.Info("NeatCon Consensus Engine already started") 472 } 473 case <-stopMiningCh: 474 if s.IsMining() { 475 s.chainConfig.ChainLogger.Info("NeatCon Consensus Engine will stop shortly") 476 s.StopMining() 477 } else { 478 s.chainConfig.ChainLogger.Info("NeatCon Consensus Engine already stopped") 479 } 480 case <-startMiningSub.Err(): 481 return 482 case <-stopMiningSub.Err(): 483 return 484 } 485 } 486 } 487 488 func (s *NeatChain) StartScanAndPrune(blockNumber uint64) { 489 490 if datareduction.StartPruning() { 491 log.Info("Data Reduction - Start") 492 } else { 493 log.Info("Data Reduction - Pruning is already running") 494 return 495 } 496 497 latestBlockNumber := s.blockchain.CurrentHeader().Number.Uint64() 498 if blockNumber == 0 || blockNumber >= latestBlockNumber { 499 blockNumber = latestBlockNumber 500 log.Infof("Data Reduction - Last block number %v", blockNumber) 501 } else { 502 log.Infof("Data Reduction - User defined Last block number %v", blockNumber) 503 } 504 505 ps := rawdb.ReadHeadScanNumber(s.pruneDb) 506 var scanNumber uint64 507 if ps != nil { 508 scanNumber = *ps 509 } 510 511 pp := rawdb.ReadHeadPruneNumber(s.pruneDb) 512 var pruneNumber uint64 513 if pp != nil { 514 pruneNumber = *pp 515 } 516 log.Infof("Data Reduction - Last scan number %v, prune number %v", scanNumber, pruneNumber) 517 518 pruneProcessor := datareduction.NewPruneProcessor(s.chainDb, s.pruneDb, s.blockchain, s.config.PruneBlockData) 519 520 lastScanNumber, lastPruneNumber := pruneProcessor.Process(blockNumber, scanNumber, pruneNumber) 521 log.Infof("Data Reduction - After prune, last number scan %v, prune number %v", lastScanNumber, lastPruneNumber) 522 if s.config.PruneBlockData { 523 for i := uint64(1); i < lastPruneNumber; i++ { 524 rawdb.DeleteBody(s.chainDb, rawdb.ReadCanonicalHash(s.chainDb, i), i) 525 } 526 log.Infof("deleted block from 1 to %v", lastPruneNumber) 527 } 528 log.Info("Data Reduction - Completed") 529 530 datareduction.StopPruning() 531 }