gitlab.com/aquachain/aquachain@v1.17.16-rc3.0.20221018032414-e3ddf1e1c055/aqua/backend.go (about) 1 // Copyright 2018 The aquachain Authors 2 // This file is part of the aquachain library. 3 // 4 // The aquachain 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 aquachain 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 aquachain library. If not, see <http://www.gnu.org/licenses/>. 16 17 // Package aqua implements the Aquachain protocol. 18 package aqua 19 20 import ( 21 "encoding/hex" 22 "fmt" 23 "math/big" 24 "runtime" 25 "sync" 26 "sync/atomic" 27 28 "gitlab.com/aquachain/aquachain/aqua/accounts" 29 "gitlab.com/aquachain/aquachain/aqua/downloader" 30 "gitlab.com/aquachain/aquachain/aqua/event" 31 "gitlab.com/aquachain/aquachain/aqua/filters" 32 "gitlab.com/aquachain/aquachain/aqua/gasprice" 33 "gitlab.com/aquachain/aquachain/aquadb" 34 "gitlab.com/aquachain/aquachain/common" 35 "gitlab.com/aquachain/aquachain/common/hexutil" 36 "gitlab.com/aquachain/aquachain/common/log" 37 "gitlab.com/aquachain/aquachain/consensus" 38 "gitlab.com/aquachain/aquachain/consensus/aquahash" 39 "gitlab.com/aquachain/aquachain/core" 40 "gitlab.com/aquachain/aquachain/core/bloombits" 41 "gitlab.com/aquachain/aquachain/core/types" 42 "gitlab.com/aquachain/aquachain/core/vm" 43 "gitlab.com/aquachain/aquachain/internal/aquaapi" 44 "gitlab.com/aquachain/aquachain/node" 45 "gitlab.com/aquachain/aquachain/opt/miner" 46 "gitlab.com/aquachain/aquachain/p2p" 47 "gitlab.com/aquachain/aquachain/params" 48 "gitlab.com/aquachain/aquachain/rlp" 49 "gitlab.com/aquachain/aquachain/rpc" 50 ) 51 52 // Aquachain implements the Aquachain full node service. 53 type Aquachain struct { 54 config *Config 55 chainConfig *params.ChainConfig 56 57 // Channel for shutting down the service 58 shutdownChan chan bool // Channel for shutting down the aquachain 59 stopDbUpgrade func() error // stop chain db sequential key upgrade 60 61 // Handlers 62 txPool *core.TxPool 63 blockchain *core.BlockChain 64 protocolManager *ProtocolManager 65 66 // DB interfaces 67 chainDb aquadb.Database // Block chain database 68 69 eventMux *event.TypeMux 70 engine consensus.Engine 71 accountManager *accounts.Manager 72 73 bloomRequests chan chan *bloombits.Retrieval // Channel receiving bloom data retrieval requests 74 bloomIndexer *core.ChainIndexer // Bloom indexer operating during block imports 75 76 ApiBackend *AquaApiBackend 77 78 miner *miner.Miner 79 gasPrice *big.Int 80 aquabase common.Address 81 82 networkId uint64 83 netRPCService *aquaapi.PublicNetAPI 84 85 lock sync.RWMutex // Protects the variadic fields (e.g. gas price and aquabase) 86 } 87 88 // New creates a new Aquachain object (including the 89 // initialisation of the common Aquachain object) 90 func New(ctx *node.ServiceContext, config *Config) (*Aquachain, error) { 91 if !config.SyncMode.IsValid() { 92 return nil, fmt.Errorf("invalid sync mode %d", config.SyncMode) 93 } 94 chainDb, err := CreateDB(ctx, config, "chaindata") 95 if err != nil { 96 return nil, err 97 } 98 stopDbUpgrade := upgradeDeduplicateData(chainDb) 99 chainConfig, genesisHash, genesisErr := core.SetupGenesisBlock(chainDb, config.Genesis) 100 if _, ok := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !ok { 101 return nil, genesisErr 102 } 103 log.Info("Initialised chain configuration", "HF-Ready", chainConfig.HF, "config", chainConfig) 104 105 aqua := &Aquachain{ 106 config: config, 107 chainDb: chainDb, 108 chainConfig: chainConfig, 109 eventMux: ctx.EventMux, 110 accountManager: ctx.AccountManager, 111 engine: CreateConsensusEngine(ctx, &config.Aquahash, chainConfig, chainDb), 112 shutdownChan: make(chan bool), 113 stopDbUpgrade: stopDbUpgrade, 114 networkId: config.NetworkId, 115 gasPrice: config.GasPrice, 116 aquabase: config.Aquabase, 117 bloomRequests: make(chan chan *bloombits.Retrieval), 118 bloomIndexer: NewBloomIndexer(chainConfig, chainDb, params.BloomBitsBlocks), 119 } 120 121 if chainConfig == params.EthnetChainConfig { 122 ProtocolName = "eth" 123 ProtocolVersions = []uint{63, 62} 124 ProtocolLengths = []uint64{17, 8} 125 } 126 127 log.Info("Initialising Aquachain protocol", "versions", ProtocolVersions, "network", config.NetworkId) 128 129 //if !config.SkipBcVersionCheck { 130 bcVersion := core.GetBlockChainVersion(chainDb) 131 if bcVersion != core.BlockChainVersion && bcVersion != 0 { 132 return nil, fmt.Errorf("Blockchain DB version mismatch (%d / %d). Run aquachain upgradedb.\n", bcVersion, core.BlockChainVersion) 133 } 134 core.WriteBlockChainVersion(chainDb, core.BlockChainVersion) 135 //} 136 var ( 137 vmConfig = vm.Config{EnablePreimageRecording: config.EnablePreimageRecording} 138 cacheConfig = &core.CacheConfig{Disabled: config.NoPruning, TrieNodeLimit: config.TrieCache, TrieTimeLimit: config.TrieTimeout} 139 ) 140 aqua.blockchain, err = core.NewBlockChain(chainDb, cacheConfig, aqua.chainConfig, aqua.engine, vmConfig) 141 if err != nil { 142 return nil, err 143 } 144 // Rewind the chain in case of an incompatible config upgrade. 145 if compat, ok := genesisErr.(*params.ConfigCompatError); ok { 146 log.Warn("Rewinding chain to upgrade configuration", "err", compat) 147 aqua.blockchain.SetHead(compat.RewindTo) 148 core.WriteChainConfig(chainDb, genesisHash, chainConfig) 149 } 150 aqua.bloomIndexer.Start(aqua.blockchain) 151 152 if config.TxPool.Journal != "" { 153 config.TxPool.Journal = ctx.ResolvePath(config.TxPool.Journal) 154 } 155 aqua.txPool = core.NewTxPool(config.TxPool, aqua.chainConfig, aqua.blockchain) 156 157 if aqua.protocolManager, err = NewProtocolManager(aqua.chainConfig, config.SyncMode, config.NetworkId, aqua.eventMux, aqua.txPool, aqua.engine, aqua.blockchain, chainDb); err != nil { 158 return nil, err 159 } 160 aqua.miner = miner.New(aqua, aqua.chainConfig, aqua.EventMux(), aqua.engine) 161 aqua.miner.SetExtra(makeExtraData(config.ExtraData)) 162 163 aqua.ApiBackend = &AquaApiBackend{aqua, nil} 164 gpoParams := config.GPO 165 if gpoParams.Default == nil { 166 gpoParams.Default = config.GasPrice 167 } 168 aqua.ApiBackend.gpo = gasprice.NewOracle(aqua.ApiBackend, gpoParams) 169 170 return aqua, nil 171 } 172 173 func makeExtraData(extra []byte) []byte { 174 // create default extradata 175 176 thing := []interface{}{ 177 uint(params.VersionMajor<<16 | params.VersionMinor<<8 | params.VersionPatch), 178 "aqua", 179 runtime.GOOS, 180 common.ShortGoVersion(), 181 } 182 defaultExtra, _ := rlp.EncodeToBytes(thing) 183 if len(extra) == 0 { 184 extra = defaultExtra 185 } else if len(extra) > 1 { 186 if extra[0] == '0' && extra[1] == 'x' { 187 b, err := hex.DecodeString(string(extra[2:])) 188 if err != nil { 189 log.Warn("Ignoring custom extradata", "error", err) 190 extra = defaultExtra 191 } else if len(b) > 32 { 192 log.Warn("Ignoring too-big extradata", "len", len(b)) 193 extra = defaultExtra 194 } else { 195 extra = b 196 } 197 } 198 } 199 200 if uint64(len(extra)) > params.MaximumExtraDataSize { 201 log.Warn("Extra invalid:", "extra", thing[1], "name", thing[2], "version", thing[3]) 202 extra = extra[:params.MaximumExtraDataSize-1] 203 log.Warn("Miner extra data exceed limit, truncating!", "extra", hexutil.Bytes(extra).String(), "limit", params.MaximumExtraDataSize) 204 } 205 return extra 206 } 207 208 func DecodeExtraData(extra []byte) (version [3]uint8, osname string, extradata []byte, err error) { 209 var ( 210 v []interface{} 211 major, minor, patch uint8 212 ) 213 214 err = rlp.DecodeBytes(extra, &v) 215 if err != nil { 216 return version, osname, extra, err 217 } 218 219 // extract version 220 vr, ok := v[0].([]uint8) 221 if !ok || len(vr) != 3 { 222 fmt.Printf("%T type, len %v\n", v[0], len(vr)) 223 err = fmt.Errorf("could not decode version") 224 return version, osname, extra, err 225 } 226 major, minor, patch = vr[0], vr[1], vr[2] 227 228 // check "aquachain" 229 if aq, ok := v[1].([]byte); !ok { 230 return version, osname, extra, nil 231 } else if string(aq) != "aquachain" && string(aq) != "aqua" { 232 return version, osname, extra, nil 233 } 234 235 // get OS 236 if osnameBytes, ok := v[2].([]byte); !ok { 237 fmt.Printf("%T type\n", v[2]) 238 return version, osname, extra, fmt.Errorf("osname") 239 } else { 240 osname = string(osnameBytes) 241 } 242 243 return [3]uint8{major, minor, patch}, osname, extra, nil 244 } 245 246 // CreateDB creates the chain database. 247 func CreateDB(ctx *node.ServiceContext, config *Config, name string) (aquadb.Database, error) { 248 db, err := ctx.OpenDatabase(name, config.DatabaseCache, config.DatabaseHandles) 249 if err != nil { 250 return nil, err 251 } 252 if db, ok := db.(*aquadb.LDBDatabase); ok { 253 db.Meter("aqua/db/chaindata/") 254 } 255 return db, nil 256 } 257 258 // CreateConsensusEngine creates the required type of consensus engine instance for an Aquachain service 259 func CreateConsensusEngine(ctx *node.ServiceContext, config *aquahash.Config, chainConfig *params.ChainConfig, db aquadb.Database) consensus.Engine { 260 startVersion := func() byte { 261 big0 := big.NewInt(0) 262 if chainConfig == nil { 263 return 0 264 } 265 if chainConfig.IsHF(8, big0) { 266 return 3 267 } 268 if chainConfig.IsHF(5, big0) { 269 return 2 270 } 271 return 0 272 }() 273 switch { 274 case config.PowMode == aquahash.ModeFake: 275 log.Warn("Aquahash used in fake mode") 276 return aquahash.NewFaker() 277 case config.PowMode == aquahash.ModeTest: 278 log.Warn("Aquahash used in test mode") 279 return aquahash.NewTester() 280 case config.PowMode == aquahash.ModeShared: 281 log.Warn("Aquahash used in shared mode") 282 return aquahash.NewShared() 283 default: 284 log.Info("Starting aquahash", "version", startVersion) 285 if startVersion > 1 { 286 engine := aquahash.New(aquahash.Config{StartVersion: startVersion}) 287 engine.SetThreads(-1) 288 return engine 289 } 290 engine := aquahash.New(aquahash.Config{ 291 CacheDir: ctx.ResolvePath(config.CacheDir), 292 CachesInMem: config.CachesInMem, 293 CachesOnDisk: config.CachesOnDisk, 294 DatasetDir: config.DatasetDir, 295 DatasetsInMem: config.DatasetsInMem, 296 DatasetsOnDisk: config.DatasetsOnDisk, 297 StartVersion: startVersion, 298 }) 299 engine.SetThreads(-1) // Disable CPU mining 300 return engine 301 } 302 } 303 304 // APIs returns the collection of RPC services the aquachain package offers. 305 // NOTE, some of these services probably need to be moved to somewhere else. 306 func (s *Aquachain) APIs() []rpc.API { 307 apis := aquaapi.GetAPIs(s.ApiBackend) 308 309 // Append any APIs exposed explicitly by the consensus engine 310 apis = append(apis, s.engine.APIs(s.BlockChain())...) 311 if s.protocolManager != nil { 312 apis = append(apis, rpc.API{ 313 Namespace: "aqua", 314 Version: "1.0", 315 Service: downloader.NewPublicDownloaderAPI(s.protocolManager.downloader, s.eventMux), 316 Public: true, 317 }) 318 } 319 320 // Append all the local APIs and return 321 return append(apis, []rpc.API{ 322 { 323 Namespace: "aqua", 324 Version: "1.0", 325 Service: NewPublicAquachainAPI(s), 326 Public: true, 327 }, { 328 Namespace: "aqua", 329 Version: "1.0", 330 Service: NewPublicMinerAPI(s), 331 Public: true, 332 }, { 333 Namespace: "miner", 334 Version: "1.0", 335 Service: NewPrivateMinerAPI(s), 336 Public: false, 337 }, { 338 Namespace: "aqua", 339 Version: "1.0", 340 Service: filters.NewPublicFilterAPI(s.ApiBackend, false), 341 Public: true, 342 }, { 343 Namespace: "admin", 344 Version: "1.0", 345 Service: NewPrivateAdminAPI(s), 346 }, { 347 Namespace: "debug", 348 Version: "1.0", 349 Service: NewPublicDebugAPI(s), 350 Public: true, 351 }, { 352 Namespace: "debug", 353 Version: "1.0", 354 Service: NewPrivateDebugAPI(s.chainConfig, s), 355 }, { 356 Namespace: "testing", 357 Version: "1.0", 358 Service: NewPublicTestingAPI(s.chainConfig, s), 359 }, { 360 Namespace: "net", 361 Version: "1.0", 362 Service: s.netRPCService, 363 Public: true, 364 }, 365 }...) 366 } 367 368 func (s *Aquachain) ResetWithGenesisBlock(gb *types.Block) { 369 s.blockchain.ResetWithGenesisBlock(gb) 370 } 371 372 func (s *Aquachain) Aquabase() (eb common.Address, err error) { 373 s.lock.RLock() 374 aquabase := s.aquabase 375 s.lock.RUnlock() 376 377 if aquabase != (common.Address{}) { 378 return aquabase, nil 379 } 380 am := s.AccountManager() 381 if am == nil { 382 return common.Address{}, fmt.Errorf("aquabase must be explicitly specified (no-keybase mode)") 383 } 384 if wallets := am.Wallets(); len(wallets) > 0 { 385 if accounts := wallets[0].Accounts(); len(accounts) > 0 { 386 aquabase := accounts[0].Address 387 388 s.lock.Lock() 389 s.aquabase = aquabase 390 s.lock.Unlock() 391 392 log.Info("Aquabase automatically configured", "address", aquabase) 393 return aquabase, nil 394 } 395 } 396 return common.Address{}, fmt.Errorf("aquabase must be explicitly specified") 397 } 398 399 // set in js console via admin interface or wrapper from cli flags 400 func (self *Aquachain) SetAquabase(aquabase common.Address) { 401 self.lock.Lock() 402 self.aquabase = aquabase 403 self.lock.Unlock() 404 405 self.miner.SetAquabase(aquabase) 406 } 407 408 func (s *Aquachain) StartMining(local bool) error { 409 eb, err := s.Aquabase() 410 if err != nil { 411 log.Error("Cannot start mining without aquabase", "err", err) 412 return fmt.Errorf("aquabase missing: %v", err) 413 } 414 if local { 415 // If local (CPU) mining is started, we can disable the transaction rejection 416 // mechanism introduced to speed sync times. CPU mining on mainnet is ludicrous 417 // so noone will ever hit this path, whereas marking sync done on CPU mining 418 // will ensure that private networks work in single miner mode too. 419 420 if s.protocolManager != nil { // offline mode 421 atomic.StoreUint32(&s.protocolManager.acceptTxs, 1) 422 } 423 } 424 go s.miner.Start(eb) 425 return nil 426 } 427 428 func (s *Aquachain) StopMining() { s.miner.Stop() } 429 func (s *Aquachain) IsMining() bool { return s.miner.Mining() } 430 func (s *Aquachain) Miner() *miner.Miner { return s.miner } 431 432 func (s *Aquachain) AccountManager() *accounts.Manager { return s.accountManager } 433 func (s *Aquachain) BlockChain() *core.BlockChain { return s.blockchain } 434 func (s *Aquachain) TxPool() *core.TxPool { return s.txPool } 435 func (s *Aquachain) EventMux() *event.TypeMux { return s.eventMux } 436 func (s *Aquachain) Engine() consensus.Engine { return s.engine } 437 func (s *Aquachain) ChainDb() aquadb.Database { return s.chainDb } 438 func (s *Aquachain) IsListening() bool { return true } // Always listening 439 func (s *Aquachain) AquaVersion() int { 440 if s.protocolManager != nil { 441 return int(s.protocolManager.SubProtocols[0].Version) 442 } 443 return 0 444 } 445 func (s *Aquachain) NetVersion() uint64 { return s.networkId } 446 func (s *Aquachain) Downloader() *downloader.Downloader { return s.protocolManager.downloader } 447 448 // Protocols implements node.Service, returning all the currently configured 449 // network protocols to start. 450 func (s *Aquachain) Protocols() []p2p.Protocol { 451 if s.protocolManager == nil { 452 return nil 453 } 454 return s.protocolManager.SubProtocols 455 } 456 457 // Start implements node.Service, starting all internal goroutines needed by the 458 // Aquachain protocol implementation. 459 func (s *Aquachain) Start(srvr *p2p.Server) error { 460 // Start the bloom bits servicing goroutines 461 s.startBloomHandlers() 462 463 // Start the RPC service 464 s.netRPCService = aquaapi.NewPublicNetAPI(srvr, s.NetVersion()) 465 466 // Figure out a max peers count based on the server limits 467 maxPeers := srvr.MaxPeers 468 // Start the networking layer 469 if s.protocolManager != nil { 470 s.protocolManager.Start(maxPeers) 471 } 472 return nil 473 } 474 475 // Stop implements node.Service, terminating all internal goroutines used by the 476 // Aquachain protocol. 477 func (s *Aquachain) Stop() error { 478 if s.stopDbUpgrade != nil { 479 s.stopDbUpgrade() 480 } 481 s.bloomIndexer.Close() 482 s.blockchain.Stop() 483 if s.protocolManager != nil { 484 s.protocolManager.Stop() 485 } 486 s.txPool.Stop() 487 s.miner.Stop() 488 s.eventMux.Stop() 489 490 s.chainDb.Close() 491 close(s.shutdownChan) 492 493 return nil 494 }