github.com/n1ghtfa1l/go-vnt@v0.6.4-alpha.6/vnt/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 vnt implements the VNT protocol. 18 package vnt 19 20 import ( 21 "errors" 22 "fmt" 23 "math/big" 24 "runtime" 25 "sync" 26 "sync/atomic" 27 28 "github.com/vntchain/go-vnt/accounts" 29 "github.com/vntchain/go-vnt/common" 30 "github.com/vntchain/go-vnt/common/hexutil" 31 "github.com/vntchain/go-vnt/consensus" 32 "github.com/vntchain/go-vnt/consensus/dpos" 33 "github.com/vntchain/go-vnt/core" 34 "github.com/vntchain/go-vnt/core/bloombits" 35 "github.com/vntchain/go-vnt/core/rawdb" 36 "github.com/vntchain/go-vnt/core/types" 37 "github.com/vntchain/go-vnt/core/vm" 38 "github.com/vntchain/go-vnt/event" 39 "github.com/vntchain/go-vnt/internal/vntapi" 40 "github.com/vntchain/go-vnt/log" 41 "github.com/vntchain/go-vnt/node" 42 "github.com/vntchain/go-vnt/params" 43 "github.com/vntchain/go-vnt/producer" 44 "github.com/vntchain/go-vnt/rlp" 45 "github.com/vntchain/go-vnt/rpc" 46 "github.com/vntchain/go-vnt/vnt/downloader" 47 "github.com/vntchain/go-vnt/vnt/filters" 48 "github.com/vntchain/go-vnt/vnt/gasprice" 49 "github.com/vntchain/go-vnt/vntdb" 50 "github.com/vntchain/go-vnt/vntp2p" 51 ) 52 53 type LesServer interface { 54 Start(srvr *vntp2p.Server) 55 Stop() 56 Protocols() []vntp2p.Protocol 57 SetBloomBitsIndexer(bbIndexer *core.ChainIndexer) 58 } 59 60 // VNT implements the VNT full node service. 61 type VNT struct { 62 config *Config 63 chainConfig *params.ChainConfig 64 65 // Channel for shutting down the service 66 shutdownChan chan bool // Channel for shutting down the VNT 67 68 // Handlers 69 txPool *core.TxPool 70 blockchain *core.BlockChain 71 protocolManager *ProtocolManager 72 lesServer LesServer 73 74 // DB interfaces 75 chainDb vntdb.Database // Block chain database 76 77 eventMux *event.TypeMux 78 engine consensus.Engine 79 accountManager *accounts.Manager 80 81 bloomRequests chan chan *bloombits.Retrieval // Channel receiving bloom data retrieval requests 82 bloomIndexer *core.ChainIndexer // Bloom indexer operating during block imports 83 84 APIBackend *VntAPIBackend 85 86 producer *producer.Producer 87 gasPrice *big.Int 88 coinbase common.Address 89 90 networkId uint64 91 netRPCService *vntapi.PublicNetAPI 92 93 lock sync.RWMutex // Protects the variadic fields (e.g. gas price and coinbase) 94 } 95 96 func (s *VNT) AddLesServer(ls LesServer) { 97 s.lesServer = ls 98 ls.SetBloomBitsIndexer(s.bloomIndexer) 99 } 100 101 // New creates a new VNT object (including the 102 // initialisation of the common VNT object) 103 func New(ctx *node.ServiceContext, config *Config, node *node.Node) (*VNT, error) { 104 if config.SyncMode == downloader.LightSync { 105 return nil, errors.New("can't run vnt.VNT in light sync mode, use les.LightVnt") 106 } 107 if !config.SyncMode.IsValid() { 108 return nil, fmt.Errorf("invalid sync mode %d", config.SyncMode) 109 } 110 chainDb, err := CreateDB(ctx, config, "chaindata") 111 if err != nil { 112 return nil, err 113 } 114 chainConfig, genesisHash, genesisErr := core.SetupGenesisBlock(chainDb, config.Genesis) 115 if _, ok := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !ok { 116 return nil, genesisErr 117 } 118 log.Info("Initialised chain configuration", "config", chainConfig) 119 120 vnt := &VNT{ 121 config: config, 122 chainDb: chainDb, 123 chainConfig: chainConfig, 124 eventMux: ctx.EventMux, 125 accountManager: ctx.AccountManager, 126 engine: CreateConsensusEngine(ctx, chainConfig, chainDb), 127 shutdownChan: make(chan bool), 128 networkId: config.NetworkId, 129 gasPrice: config.GasPrice, 130 coinbase: config.Coinbase, 131 bloomRequests: make(chan chan *bloombits.Retrieval), 132 bloomIndexer: NewBloomIndexer(chainDb, params.BloomBitsBlocks), 133 } 134 135 log.Info("Initialising VNT protocol", "versions", ProtocolVersions, "network", config.NetworkId) 136 137 if !config.SkipBcVersionCheck { 138 bcVersion := rawdb.ReadDatabaseVersion(chainDb) 139 if bcVersion != core.BlockChainVersion && bcVersion != 0 { 140 return nil, fmt.Errorf("Blockchain DB version mismatch (%d / %d). Run gvnt upgradedb.\n", bcVersion, core.BlockChainVersion) 141 } 142 rawdb.WriteDatabaseVersion(chainDb, core.BlockChainVersion) 143 } 144 var ( 145 vmConfig = vm.Config{EnablePreimageRecording: config.EnablePreimageRecording} 146 cacheConfig = &core.CacheConfig{Disabled: config.NoPruning, TrieNodeLimit: config.TrieCache, TrieTimeLimit: config.TrieTimeout} 147 ) 148 vnt.blockchain, err = core.NewBlockChain(chainDb, cacheConfig, vnt.chainConfig, vnt.engine, vmConfig) 149 if err != nil { 150 return nil, err 151 } 152 // Rewind the chain in case of an incompatible config upgrade. 153 if compat, ok := genesisErr.(*params.ConfigCompatError); ok { 154 log.Warn("Rewinding chain to upgrade configuration", "err", compat) 155 vnt.blockchain.SetHead(compat.RewindTo) 156 rawdb.WriteChainConfig(chainDb, genesisHash, chainConfig) 157 } 158 vnt.bloomIndexer.Start(vnt.blockchain) 159 160 if config.TxPool.Journal != "" { 161 config.TxPool.Journal = ctx.ResolvePath(config.TxPool.Journal) 162 } 163 vnt.txPool = core.NewTxPool(config.TxPool, vnt.chainConfig, vnt.blockchain) 164 165 if vnt.protocolManager, err = NewProtocolManager(vnt.chainConfig, config.SyncMode, config.NetworkId, vnt.eventMux, vnt.txPool, vnt.engine, vnt.blockchain, chainDb, node); err != nil { 166 return nil, err 167 } 168 vnt.producer = producer.New(vnt, vnt.chainConfig, vnt.EventMux(), vnt.engine) 169 vnt.producer.SetExtra(makeExtraData(config.ExtraData)) 170 171 vnt.APIBackend = &VntAPIBackend{vnt, nil} 172 gpoParams := config.GPO 173 if gpoParams.Default == nil { 174 gpoParams.Default = config.GasPrice 175 } 176 vnt.APIBackend.gpo = gasprice.NewOracle(vnt.APIBackend, gpoParams) 177 178 return vnt, nil 179 } 180 181 func makeExtraData(extra []byte) []byte { 182 if len(extra) == 0 { 183 // create default extradata 184 extra, _ = rlp.EncodeToBytes([]interface{}{ 185 uint(params.VersionMajor<<16 | params.VersionMinor<<8 | params.VersionPatch), 186 "gvnt", 187 runtime.Version(), 188 runtime.GOOS, 189 }) 190 } 191 if uint64(len(extra)) > params.MaximumExtraDataSize { 192 log.Warn("Producer extra data exceed limit", "extra", hexutil.Bytes(extra), "limit", params.MaximumExtraDataSize) 193 extra = nil 194 } 195 return extra 196 } 197 198 // CreateDB creates the chain database. 199 func CreateDB(ctx *node.ServiceContext, config *Config, name string) (vntdb.Database, error) { 200 log.Debug("backend", "func", "CreateDB", "ctx", ctx, "config", config, "name", name) 201 db, err := ctx.OpenDatabase(name, config.DatabaseCache, config.DatabaseHandles) 202 if err != nil { 203 return nil, err 204 } 205 if db, ok := db.(*vntdb.LDBDatabase); ok { 206 db.Meter("vnt/db/chaindata/") 207 } 208 return db, nil 209 } 210 211 // CreateConsensusEngine creates the required type of consensus engine instance for an vnt service 212 func CreateConsensusEngine(ctx *node.ServiceContext, chainConfig *params.ChainConfig, db vntdb.Database) consensus.Engine { 213 cfg := chainConfig.Dpos 214 if chainConfig.Dpos == nil { 215 cfg = ¶ms.DposConfig{ 216 WitnessesNum: params.MainnetChainConfig.Dpos.WitnessesNum, 217 Period: params.MainnetChainConfig.Dpos.Period, 218 WitnessesUrl: make([]string, len(params.MainnetChainConfig.Dpos.WitnessesUrl)), 219 } 220 for i, url := range params.MainnetChainConfig.Dpos.WitnessesUrl { 221 cfg.WitnessesUrl[i] = url 222 } 223 } 224 return dpos.New(cfg, db) 225 } 226 227 // APIs return the collection of RPC services the hubble package offers. 228 // NOTE, some of these services probably need to be moved to somewhere else. 229 func (s *VNT) APIs() []rpc.API { 230 apis := vntapi.GetAPIs(s.APIBackend) 231 232 // Append any APIs exposed explicitly by the consensus engine 233 apis = append(apis, s.engine.APIs(s.BlockChain())...) 234 235 // Append all the local APIs and return 236 return append(apis, []rpc.API{ 237 { 238 Namespace: "core", 239 Version: "1.0", 240 Service: NewPublicVntAPI(s), 241 Public: true, 242 }, { 243 Namespace: "core", 244 Version: "1.0", 245 Service: NewPublicProducerAPI(s), 246 Public: true, 247 }, { 248 Namespace: "core", 249 Version: "1.0", 250 Service: downloader.NewPublicDownloaderAPI(s.protocolManager.downloader, s.eventMux), 251 Public: true, 252 }, { 253 Namespace: "bp", 254 Version: "1.0", 255 Service: NewPrivateProducerAPI(s), 256 Public: false, 257 }, { 258 Namespace: "core", 259 Version: "1.0", 260 Service: filters.NewPublicFilterAPI(s.APIBackend, false), 261 Public: true, 262 }, { 263 Namespace: "admin", 264 Version: "1.0", 265 Service: NewPrivateAdminAPI(s), 266 }, { 267 Namespace: "debug", 268 Version: "1.0", 269 Service: NewPublicDebugAPI(s), 270 Public: true, 271 }, { 272 Namespace: "debug", 273 Version: "1.0", 274 Service: NewPrivateDebugAPI(s.chainConfig, s), 275 }, { 276 Namespace: "net", 277 Version: "1.0", 278 Service: s.netRPCService, 279 Public: true, 280 }, 281 }...) 282 } 283 284 func (s *VNT) ResetWithGenesisBlock(gb *types.Block) { 285 s.blockchain.ResetWithGenesisBlock(gb) 286 } 287 288 func (s *VNT) Coinbase() (eb common.Address, err error) { 289 s.lock.RLock() 290 coinbase := s.coinbase 291 s.lock.RUnlock() 292 293 if coinbase != (common.Address{}) { 294 return coinbase, nil 295 } 296 if wallets := s.AccountManager().Wallets(); len(wallets) > 0 { 297 if accounts := wallets[0].Accounts(); len(accounts) > 0 { 298 coinbase := accounts[0].Address 299 300 s.lock.Lock() 301 s.coinbase = coinbase 302 s.lock.Unlock() 303 304 log.Info("Coinbase automatically configured", "address", coinbase) 305 return coinbase, nil 306 } 307 } 308 return common.Address{}, fmt.Errorf("coinbase must be explicitly specified") 309 } 310 311 // SetCoinbase sets the block producing reward address. 312 func (s *VNT) SetCoinbase(coinbase common.Address) { 313 s.lock.Lock() 314 s.coinbase = coinbase 315 s.lock.Unlock() 316 317 s.producer.SetCoinbase(coinbase) 318 } 319 320 func (s *VNT) StartProducing(local bool) error { 321 eb, err := s.Coinbase() 322 if err != nil { 323 log.Error("Cannot start block producing without coinbase", "err", err) 324 return fmt.Errorf("coinbase missing: %v", err) 325 } 326 327 if dpos, ok := s.engine.(*dpos.Dpos); ok { 328 wallet, err := s.accountManager.Find(accounts.Account{Address: eb}) 329 if wallet == nil || err != nil { 330 log.Error("Coinbase account unavailable locally", "err", err) 331 return fmt.Errorf("signer missing: %v", err) 332 } 333 dpos.Authorize(eb, wallet.SignHash) 334 } 335 if local { 336 // If local (CPU) block producing is started, we can disable the transaction rejection 337 // mechanism introduced to speed sync times. CPU block producing on mainnet is ludicrous 338 // so none will ever hit this path, whereas marking sync done on CPU block producing 339 // will ensure that private networks work in single producer mode too. 340 atomic.StoreUint32(&s.protocolManager.acceptTxs, 1) 341 } 342 go s.producer.Start(eb) 343 return nil 344 } 345 346 func (s *VNT) StopProducing() { s.producer.Stop() } 347 func (s *VNT) IsProducing() bool { return s.producer.Producing() } 348 func (s *VNT) Producer() *producer.Producer { return s.producer } 349 350 func (s *VNT) AccountManager() *accounts.Manager { return s.accountManager } 351 func (s *VNT) BlockChain() *core.BlockChain { return s.blockchain } 352 func (s *VNT) TxPool() *core.TxPool { return s.txPool } 353 func (s *VNT) EventMux() *event.TypeMux { return s.eventMux } 354 func (s *VNT) Engine() consensus.Engine { return s.engine } 355 func (s *VNT) ChainDb() vntdb.Database { return s.chainDb } 356 func (s *VNT) IsListening() bool { return true } // Always listening 357 func (s *VNT) VntVersion() int { return int(s.protocolManager.SubProtocols[0].Version) } 358 func (s *VNT) NetVersion() uint64 { return s.networkId } 359 func (s *VNT) Downloader() *downloader.Downloader { return s.protocolManager.downloader } 360 361 // Protocols implements node.Service, returning all the currently configured 362 // network protocols to start. 363 func (s *VNT) Protocols() []vntp2p.Protocol { 364 if s.lesServer == nil { 365 return s.protocolManager.SubProtocols 366 } 367 return append(s.protocolManager.SubProtocols, s.lesServer.Protocols()...) 368 } 369 370 // Start implements node.Service, starting all internal goroutines needed by the 371 // VNT protocol implementation. 372 func (s *VNT) Start(srvr *vntp2p.Server) error { 373 // Start the bloom bits servicing goroutines 374 s.startBloomHandlers() 375 376 // Start the RPC service 377 s.netRPCService = vntapi.NewPublicNetAPI(srvr, s.NetVersion()) 378 379 // Figure out a max peers count based on the server limits 380 maxPeers := srvr.MaxPeers 381 if s.config.LightServ > 0 { 382 if s.config.LightPeers >= srvr.MaxPeers { 383 return fmt.Errorf("invalid peer config: light peer count (%d) >= total peer count (%d)", s.config.LightPeers, srvr.MaxPeers) 384 } 385 maxPeers -= s.config.LightPeers 386 } 387 // Start the networking layer and the light server if requested 388 s.protocolManager.Start(maxPeers) 389 if s.lesServer != nil { 390 s.lesServer.Start(srvr) 391 } 392 return nil 393 } 394 395 // Stop implements node.Service, terminating all internal goroutines used by the 396 // VNT protocol. 397 func (s *VNT) Stop() error { 398 s.bloomIndexer.Close() 399 s.blockchain.Stop() 400 s.protocolManager.Stop() 401 if s.lesServer != nil { 402 s.lesServer.Stop() 403 } 404 s.txPool.Stop() 405 s.producer.Stop() 406 s.eventMux.Stop() 407 408 s.chainDb.Close() 409 close(s.shutdownChan) 410 411 return nil 412 }