github.com/bigzoro/my_simplechain@v0.0.0-20240315012955-8ad0a2a29bb9/les/server.go (about) 1 // Copyright 2016 The go-simplechain Authors 2 // This file is part of the go-simplechain library. 3 // 4 // The go-simplechain 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-simplechain 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-simplechain library. If not, see <http://www.gnu.org/licenses/>. 16 17 package les 18 19 import ( 20 "crypto/ecdsa" 21 "github.com/bigzoro/my_simplechain/consensus" 22 "github.com/bigzoro/my_simplechain/ethdb" 23 "github.com/bigzoro/my_simplechain/event" 24 "time" 25 26 "github.com/bigzoro/my_simplechain/accounts/abi/bind" 27 "github.com/bigzoro/my_simplechain/common/mclock" 28 "github.com/bigzoro/my_simplechain/core" 29 "github.com/bigzoro/my_simplechain/eth" 30 "github.com/bigzoro/my_simplechain/les/flowcontrol" 31 "github.com/bigzoro/my_simplechain/light" 32 "github.com/bigzoro/my_simplechain/log" 33 "github.com/bigzoro/my_simplechain/p2p" 34 "github.com/bigzoro/my_simplechain/p2p/discv5" 35 "github.com/bigzoro/my_simplechain/p2p/enode" 36 "github.com/bigzoro/my_simplechain/p2p/enr" 37 "github.com/bigzoro/my_simplechain/params" 38 "github.com/bigzoro/my_simplechain/rpc" 39 ) 40 41 type LesServer struct { 42 lesCommons 43 44 archiveMode bool // Flag whether the ethereum node runs in archive mode. 45 handler *serverHandler 46 lesTopics []discv5.Topic 47 privateKey *ecdsa.PrivateKey 48 49 // Flow control and capacity management 50 fcManager *flowcontrol.ClientManager 51 costTracker *costTracker 52 defParams flowcontrol.ServerParams 53 servingQueue *servingQueue 54 clientPool *clientPool 55 56 minCapacity, maxCapacity, freeCapacity uint64 57 threadsIdle int // Request serving threads count when system is idle. 58 threadsBusy int // Request serving threads count when system is busy(block insertion). 59 } 60 61 // add new for mainchain and subchain 62 type Simplechain interface { 63 BlockChain() *core.BlockChain 64 TxPool() *core.TxPool 65 EventMux() *event.TypeMux 66 Engine() consensus.Engine 67 ChainDb() ethdb.Database 68 ArchiveMode() bool 69 GetSynced() func() bool 70 } 71 72 func NewLesServer(e Simplechain, config *eth.Config) (*LesServer, error) { 73 // Collect les protocol version information supported by local node. 74 lesTopics := make([]discv5.Topic, len(AdvertiseProtocolVersions)) 75 for i, pv := range AdvertiseProtocolVersions { 76 lesTopics[i] = lesTopic(e.BlockChain().Genesis().Hash(), pv) 77 } 78 // Calculate the number of threads used to service the light client 79 // requests based on the user-specified value. 80 threads := config.LightServ * 4 / 100 81 if threads < 4 { 82 threads = 4 83 } 84 srv := &LesServer{ 85 lesCommons: lesCommons{ 86 genesis: e.BlockChain().Genesis().Hash(), 87 config: config, 88 chainConfig: e.BlockChain().Config(), 89 iConfig: light.DefaultServerIndexerConfig, 90 chainDb: e.ChainDb(), 91 peers: newPeerSet(), 92 chainReader: e.BlockChain(), 93 chtIndexer: light.NewChtIndexer(e.ChainDb(), nil, params.CHTFrequency, params.HelperTrieProcessConfirmations), 94 bloomTrieIndexer: light.NewBloomTrieIndexer(e.ChainDb(), nil, params.BloomBitsBlocks, params.BloomTrieFrequency), 95 closeCh: make(chan struct{}), 96 }, 97 archiveMode: e.ArchiveMode(), 98 lesTopics: lesTopics, 99 fcManager: flowcontrol.NewClientManager(nil, &mclock.System{}), 100 servingQueue: newServingQueue(int64(time.Millisecond*10), float64(config.LightServ)/100), 101 threadsBusy: config.LightServ/100 + 1, 102 threadsIdle: threads, 103 } 104 srv.handler = newServerHandler(srv, e.BlockChain(), e.ChainDb(), e.TxPool(), e.GetSynced()) 105 srv.costTracker, srv.minCapacity = newCostTracker(e.ChainDb(), config) 106 srv.freeCapacity = srv.minCapacity 107 108 // Set up checkpoint oracle. 109 oracle := config.CheckpointOracle 110 if oracle == nil { 111 oracle = params.CheckpointOracles[e.BlockChain().Genesis().Hash()] 112 } 113 srv.oracle = newCheckpointOracle(oracle, srv.localCheckpoint) 114 115 // Initialize server capacity management fields. 116 srv.defParams = flowcontrol.ServerParams{ 117 BufLimit: srv.freeCapacity * bufLimitRatio, 118 MinRecharge: srv.freeCapacity, 119 } 120 // LES flow control tries to more or less guarantee the possibility for the 121 // clients to send a certain amount of requests at any time and get a quick 122 // response. Most of the clients want this guarantee but don't actually need 123 // to send requests most of the time. Our goal is to serve as many clients as 124 // possible while the actually used server capacity does not exceed the limits 125 totalRecharge := srv.costTracker.totalRecharge() 126 srv.maxCapacity = srv.freeCapacity * uint64(srv.config.LightPeers) 127 if totalRecharge > srv.maxCapacity { 128 srv.maxCapacity = totalRecharge 129 } 130 srv.fcManager.SetCapacityLimits(srv.freeCapacity, srv.maxCapacity, srv.freeCapacity*2) 131 srv.clientPool = newClientPool(srv.chainDb, srv.freeCapacity, mclock.System{}, func(id enode.ID) { go srv.peers.Unregister(peerIdToString(id)) }) 132 srv.clientPool.setDefaultFactors(priceFactors{0, 1, 1}, priceFactors{0, 1, 1}) 133 134 checkpoint := srv.latestLocalCheckpoint() 135 if !checkpoint.Empty() { 136 log.Info("Loaded latest checkpoint", "section", checkpoint.SectionIndex, "head", checkpoint.SectionHead, 137 "chtroot", checkpoint.CHTRoot, "bloomroot", checkpoint.BloomRoot) 138 } 139 srv.chtIndexer.Start(e.BlockChain()) 140 return srv, nil 141 } 142 143 func (s *LesServer) APIs() []rpc.API { 144 return []rpc.API{ 145 { 146 Namespace: "les", 147 Version: "1.0", 148 Service: NewPrivateLightAPI(&s.lesCommons), 149 Public: false, 150 }, 151 { 152 Namespace: "les", 153 Version: "1.0", 154 Service: NewPrivateLightServerAPI(s), 155 Public: false, 156 }, 157 { 158 Namespace: "debug", 159 Version: "1.0", 160 Service: NewPrivateDebugAPI(s), 161 Public: false, 162 }, 163 } 164 } 165 166 func (s *LesServer) Protocols() []p2p.Protocol { 167 ps := s.makeProtocols(ServerProtocolVersions, s.handler.runPeer, func(id enode.ID) interface{} { 168 if p := s.peers.Peer(peerIdToString(id)); p != nil { 169 return p.Info() 170 } 171 return nil 172 }) 173 // Add "les" ENR entries. 174 for i := range ps { 175 ps[i].Attributes = []enr.Entry{&lesEntry{}} 176 } 177 return ps 178 } 179 180 // Start starts the LES server 181 func (s *LesServer) Start(srvr *p2p.Server) { 182 s.privateKey = srvr.PrivateKey 183 s.handler.start() 184 185 s.wg.Add(1) 186 go s.capacityManagement() 187 188 if srvr.DiscV5 != nil { 189 for _, topic := range s.lesTopics { 190 topic := topic 191 go func() { 192 logger := log.New("topic", topic) 193 logger.Info("Starting topic registration") 194 defer logger.Info("Terminated topic registration") 195 196 srvr.DiscV5.RegisterTopic(topic, s.closeCh) 197 }() 198 } 199 } 200 } 201 202 // Stop stops the LES service 203 func (s *LesServer) Stop() { 204 close(s.closeCh) 205 206 // Disconnect existing sessions. 207 // This also closes the gate for any new registrations on the peer set. 208 // sessions which are already established but not added to pm.peers yet 209 // will exit when they try to register. 210 s.peers.Close() 211 212 s.fcManager.Stop() 213 s.costTracker.stop() 214 s.handler.stop() 215 s.clientPool.stop() // client pool should be closed after handler. 216 s.servingQueue.stop() 217 218 // Note, bloom trie indexer is closed by parent bloombits indexer. 219 s.chtIndexer.Close() 220 s.wg.Wait() 221 log.Info("Les server stopped") 222 } 223 224 func (s *LesServer) SetBloomBitsIndexer(bloomIndexer *core.ChainIndexer) { 225 bloomIndexer.AddChildIndexer(s.bloomTrieIndexer) 226 } 227 228 // SetClient sets the rpc client and starts running checkpoint contract if it is not yet watched. 229 func (s *LesServer) SetContractBackend(backend bind.ContractBackend) { 230 if s.oracle == nil { 231 return 232 } 233 s.oracle.start(backend) 234 } 235 236 // capacityManagement starts an event handler loop that updates the recharge curve of 237 // the client manager and adjusts the client pool's size according to the total 238 // capacity updates coming from the client manager 239 func (s *LesServer) capacityManagement() { 240 defer s.wg.Done() 241 242 processCh := make(chan bool, 100) 243 sub := s.handler.blockchain.SubscribeBlockProcessingEvent(processCh) 244 defer sub.Unsubscribe() 245 246 totalRechargeCh := make(chan uint64, 100) 247 totalRecharge := s.costTracker.subscribeTotalRecharge(totalRechargeCh) 248 249 totalCapacityCh := make(chan uint64, 100) 250 totalCapacity := s.fcManager.SubscribeTotalCapacity(totalCapacityCh) 251 s.clientPool.setLimits(s.config.LightPeers, totalCapacity) 252 253 var ( 254 busy bool 255 freePeers uint64 256 blockProcess mclock.AbsTime 257 ) 258 updateRecharge := func() { 259 if busy { 260 s.servingQueue.setThreads(s.threadsBusy) 261 s.fcManager.SetRechargeCurve(flowcontrol.PieceWiseLinear{{0, 0}, {totalRecharge, totalRecharge}}) 262 } else { 263 s.servingQueue.setThreads(s.threadsIdle) 264 s.fcManager.SetRechargeCurve(flowcontrol.PieceWiseLinear{{0, 0}, {totalRecharge / 10, totalRecharge}, {totalRecharge, totalRecharge}}) 265 } 266 } 267 updateRecharge() 268 269 for { 270 select { 271 case busy = <-processCh: 272 if busy { 273 blockProcess = mclock.Now() 274 } else { 275 blockProcessingTimer.Update(time.Duration(mclock.Now() - blockProcess)) 276 } 277 updateRecharge() 278 case totalRecharge = <-totalRechargeCh: 279 totalRechargeGauge.Update(int64(totalRecharge)) 280 updateRecharge() 281 case totalCapacity = <-totalCapacityCh: 282 totalCapacityGauge.Update(int64(totalCapacity)) 283 newFreePeers := totalCapacity / s.freeCapacity 284 if newFreePeers < freePeers && newFreePeers < uint64(s.config.LightPeers) { 285 log.Warn("Reduced free peer connections", "from", freePeers, "to", newFreePeers) 286 } 287 freePeers = newFreePeers 288 s.clientPool.setLimits(s.config.LightPeers, totalCapacity) 289 case <-s.closeCh: 290 return 291 } 292 } 293 }