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