github.com/m3shine/gochain@v2.2.26+incompatible/les/backend.go (about) 1 // Copyright 2016 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 les implements the Light GoChain Subprotocol. 18 package les 19 20 import ( 21 "context" 22 "fmt" 23 "sync" 24 "time" 25 26 "github.com/gochain-io/gochain/accounts" 27 "github.com/gochain-io/gochain/common" 28 "github.com/gochain-io/gochain/common/hexutil" 29 "github.com/gochain-io/gochain/consensus" 30 "github.com/gochain-io/gochain/consensus/clique" 31 "github.com/gochain-io/gochain/core" 32 "github.com/gochain-io/gochain/core/bloombits" 33 "github.com/gochain-io/gochain/core/rawdb" 34 "github.com/gochain-io/gochain/core/types" 35 "github.com/gochain-io/gochain/eth" 36 "github.com/gochain-io/gochain/eth/downloader" 37 "github.com/gochain-io/gochain/eth/filters" 38 "github.com/gochain-io/gochain/eth/gasprice" 39 "github.com/gochain-io/gochain/event" 40 "github.com/gochain-io/gochain/internal/ethapi" 41 "github.com/gochain-io/gochain/light" 42 "github.com/gochain-io/gochain/log" 43 "github.com/gochain-io/gochain/node" 44 "github.com/gochain-io/gochain/p2p" 45 "github.com/gochain-io/gochain/p2p/discv5" 46 "github.com/gochain-io/gochain/params" 47 rpc "github.com/gochain-io/gochain/rpc" 48 ) 49 50 type LightGoChain struct { 51 config *eth.Config 52 53 odr *LesOdr 54 relay *LesTxRelay 55 chainConfig *params.ChainConfig 56 // Channel for shutting down the service 57 shutdownChan chan bool 58 // Handlers 59 peers *peerSet 60 txPool *light.TxPool 61 blockchain *light.LightChain 62 protocolManager *ProtocolManager 63 serverPool *serverPool 64 reqDist *requestDistributor 65 retriever *retrieveManager 66 // DB interfaces 67 chainDb common.Database // Block chain database 68 69 bloomRequests chan chan *bloombits.Retrieval // Channel receiving bloom data retrieval requests 70 bloomIndexer, chtIndexer, bloomTrieIndexer *core.ChainIndexer 71 72 ApiBackend *LesApiBackend 73 74 eventMux *event.TypeMux 75 engine consensus.Engine 76 accountManager *accounts.Manager 77 78 networkId uint64 79 netRPCService *ethapi.PublicNetAPI 80 81 wg sync.WaitGroup 82 } 83 84 func New(ctx context.Context, sctx *node.ServiceContext, config *eth.Config) (*LightGoChain, error) { 85 chainDb, err := eth.CreateDB(sctx, config, "lightchaindata") 86 if err != nil { 87 return nil, err 88 } 89 if config.Genesis == nil { 90 config.Genesis = core.DefaultGenesisBlock() 91 } 92 chainConfig, genesisHash, genesisErr := core.SetupGenesisBlock(chainDb, config.Genesis) 93 if _, isCompat := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !isCompat { 94 return nil, genesisErr 95 } 96 if config.Genesis == nil { 97 if genesisHash == params.MainnetGenesisHash { 98 config.Genesis = core.DefaultGenesisBlock() 99 } 100 } 101 log.Info("Initialised chain configuration", "config", chainConfig) 102 103 peers := newPeerSet() 104 quitSync := make(chan struct{}) 105 106 if chainConfig.Clique == nil { 107 return nil, fmt.Errorf("invalid configuration, clique is nil: %v", chainConfig) 108 } 109 leth := &LightGoChain{ 110 config: config, 111 chainConfig: chainConfig, 112 chainDb: chainDb, 113 eventMux: sctx.EventMux, 114 peers: peers, 115 reqDist: newRequestDistributor(peers, quitSync), 116 accountManager: sctx.AccountManager, 117 engine: clique.New(chainConfig.Clique, chainDb), 118 shutdownChan: make(chan bool), 119 networkId: config.NetworkId, 120 bloomRequests: make(chan chan *bloombits.Retrieval), 121 bloomIndexer: eth.NewBloomIndexer(chainDb, light.BloomTrieFrequency), 122 chtIndexer: light.NewChtIndexer(chainDb, true), 123 bloomTrieIndexer: light.NewBloomTrieIndexer(chainDb, true), 124 } 125 126 leth.relay = NewLesTxRelay(peers, leth.reqDist) 127 leth.serverPool = newServerPool(chainDb, quitSync, &leth.wg) 128 leth.retriever = newRetrieveManager(peers, leth.reqDist, leth.serverPool) 129 leth.odr = NewLesOdr(chainDb, leth.chtIndexer, leth.bloomTrieIndexer, leth.bloomIndexer, leth.retriever) 130 if leth.blockchain, err = light.NewLightChain(leth.odr, leth.chainConfig, leth.engine); err != nil { 131 return nil, err 132 } 133 leth.bloomIndexer.Start(leth.blockchain) 134 // Rewind the chain in case of an incompatible config upgrade. 135 if compat, ok := genesisErr.(*params.ConfigCompatError); ok { 136 log.Warn("Rewinding chain to upgrade configuration", "err", compat) 137 leth.blockchain.SetHead(compat.RewindTo) 138 rawdb.WriteChainConfig(chainDb.GlobalTable(), genesisHash, chainConfig) 139 } 140 141 leth.txPool = light.NewTxPool(leth.chainConfig, leth.blockchain, leth.relay) 142 if leth.protocolManager, err = NewProtocolManager(ctx, leth.chainConfig, true, ClientProtocolVersions, config.NetworkId, leth.eventMux, leth.peers, leth.blockchain, nil, chainDb, leth.odr, leth.relay, quitSync, &leth.wg); err != nil { 143 return nil, err 144 } 145 leth.ApiBackend = &LesApiBackend{ 146 eth: leth, 147 gpo: nil, 148 } 149 if g := leth.config.Genesis; g != nil { 150 leth.ApiBackend.initialSupply = g.Alloc.Total() 151 } 152 gpoParams := config.GPO 153 if gpoParams.Default == nil { 154 gpoParams.Default = config.MinerGasPrice 155 } 156 leth.ApiBackend.gpo = gasprice.NewOracle(leth.ApiBackend, gpoParams) 157 return leth, nil 158 } 159 160 func lesTopic(genesisHash common.Hash, protocolVersion uint) discv5.Topic { 161 var name string 162 switch protocolVersion { 163 case lpv1: 164 name = "LES" 165 case lpv2: 166 name = "LES2" 167 default: 168 panic(nil) 169 } 170 return discv5.Topic(name + "@" + common.Bytes2Hex(genesisHash.Bytes()[0:8])) 171 } 172 173 type LightDummyAPI struct{} 174 175 // Etherbase is the address that mining rewards will be send to 176 func (s *LightDummyAPI) Etherbase() (common.Address, error) { 177 return common.Address{}, fmt.Errorf("not supported") 178 } 179 180 // Coinbase is the address that mining rewards will be send to (alias for Etherbase) 181 func (s *LightDummyAPI) Coinbase() (common.Address, error) { 182 return common.Address{}, fmt.Errorf("not supported") 183 } 184 185 // Hashrate returns the POW hashrate 186 func (s *LightDummyAPI) Hashrate() hexutil.Uint { 187 return 0 188 } 189 190 // Mining returns an indication if this node is currently mining. 191 func (s *LightDummyAPI) Mining() bool { 192 return false 193 } 194 195 // APIs returns the collection of RPC services the ethereum package offers. 196 // NOTE, some of these services probably need to be moved to somewhere else. 197 func (s *LightGoChain) APIs() []rpc.API { 198 return append(ethapi.GetAPIs(s.ApiBackend), []rpc.API{ 199 { 200 Namespace: "eth", 201 Version: "1.0", 202 Service: &LightDummyAPI{}, 203 Public: true, 204 }, { 205 Namespace: "eth", 206 Version: "1.0", 207 Service: downloader.NewPublicDownloaderAPI(s.protocolManager.downloader, s.eventMux), 208 Public: true, 209 }, { 210 Namespace: "eth", 211 Version: "1.0", 212 Service: filters.NewPublicFilterAPI(s.ApiBackend, true), 213 Public: true, 214 }, { 215 Namespace: "net", 216 Version: "1.0", 217 Service: s.netRPCService, 218 Public: true, 219 }, 220 }...) 221 } 222 223 func (s *LightGoChain) ResetWithGenesisBlock(gb *types.Block) { 224 s.blockchain.ResetWithGenesisBlock(gb) 225 } 226 227 func (s *LightGoChain) BlockChain() *light.LightChain { return s.blockchain } 228 func (s *LightGoChain) TxPool() *light.TxPool { return s.txPool } 229 func (s *LightGoChain) Engine() consensus.Engine { return s.engine } 230 func (s *LightGoChain) LesVersion() int { return int(s.protocolManager.SubProtocols[0].Version) } 231 func (s *LightGoChain) Downloader() *downloader.Downloader { return s.protocolManager.downloader } 232 func (s *LightGoChain) EventMux() *event.TypeMux { return s.eventMux } 233 234 // Protocols implements node.Service, returning all the currently configured 235 // network protocols to start. 236 func (s *LightGoChain) Protocols() []p2p.Protocol { 237 return s.protocolManager.SubProtocols 238 } 239 240 // Start implements node.Service, starting all internal goroutines needed by the 241 // GoChain protocol implementation. 242 func (s *LightGoChain) Start(srvr *p2p.Server) error { 243 s.startBloomHandlers() 244 log.Warn("Light client mode is an experimental feature") 245 s.netRPCService = ethapi.NewPublicNetAPI(srvr, s.networkId) 246 // clients are searching for the first advertised protocol in the list 247 protocolVersion := AdvertiseProtocolVersions[0] 248 s.serverPool.start(srvr, lesTopic(s.blockchain.Genesis().Hash(), protocolVersion)) 249 s.protocolManager.Start(s.config.LightPeers) 250 return nil 251 } 252 253 // Stop implements node.Service, terminating all internal goroutines used by the 254 // GoChain protocol. 255 func (s *LightGoChain) Stop() error { 256 s.odr.Stop() 257 if s.bloomIndexer != nil { 258 if err := s.bloomIndexer.Close(); err != nil { 259 log.Error("cannot close bloom indexer", "err", err) 260 } 261 } 262 if s.chtIndexer != nil { 263 if err := s.chtIndexer.Close(); err != nil { 264 log.Error("cannot close chain indexer", "err", err) 265 } 266 } 267 if s.bloomTrieIndexer != nil { 268 if err := s.bloomTrieIndexer.Close(); err != nil { 269 log.Error("cannot close bloom trie indexer", "err", err) 270 } 271 } 272 s.blockchain.Stop() 273 s.protocolManager.Stop() 274 s.txPool.Stop() 275 276 s.eventMux.Stop() 277 278 time.Sleep(time.Millisecond * 200) 279 s.chainDb.Close() 280 close(s.shutdownChan) 281 282 return nil 283 }