github.com/arieschain/arieschain@v0.0.0-20191023063405-37c074544356/les/server.go (about)

     1  // Package les implements the Light Ethereum Subprotocol.
     2  package les
     3  
     4  import (
     5  	"crypto/ecdsa"
     6  	"encoding/binary"
     7  	"math"
     8  	"sync"
     9  
    10  	"github.com/quickchainproject/quickchain/common"
    11  	"github.com/quickchainproject/quickchain/core"
    12  	"github.com/quickchainproject/quickchain/core/types"
    13  	"github.com/quickchainproject/quickchain/qct"
    14  	"github.com/quickchainproject/quickchain/qctdb"
    15  	"github.com/quickchainproject/quickchain/les/flowcontrol"
    16  	"github.com/quickchainproject/quickchain/light"
    17  	"github.com/quickchainproject/quickchain/log"
    18  	"github.com/quickchainproject/quickchain/p2p"
    19  	"github.com/quickchainproject/quickchain/p2p/discv5"
    20  	"github.com/quickchainproject/quickchain/rlp"
    21  )
    22  
    23  type LesServer struct {
    24  	config          *qct.Config
    25  	protocolManager *ProtocolManager
    26  	fcManager       *flowcontrol.ClientManager // nil if our node is client only
    27  	fcCostStats     *requestCostStats
    28  	defParams       *flowcontrol.ServerParams
    29  	lesTopics       []discv5.Topic
    30  	privateKey      *ecdsa.PrivateKey
    31  	quitSync        chan struct{}
    32  
    33  	chtIndexer, bloomTrieIndexer *core.ChainIndexer
    34  }
    35  
    36  func NewLesServer(eth *qct.Ethereum, config *qct.Config) (*LesServer, error) {
    37  	quitSync := make(chan struct{})
    38  	pm, err := NewProtocolManager(eth.BlockChain().Config(), false, ServerProtocolVersions, config.NetworkId, eth.EventMux(), eth.Engine(), newPeerSet(), eth.BlockChain(), eth.TxPool(), eth.ChainDb(), nil, nil, quitSync, new(sync.WaitGroup))
    39  	if err != nil {
    40  		return nil, err
    41  	}
    42  
    43  	lesTopics := make([]discv5.Topic, len(AdvertiseProtocolVersions))
    44  	for i, pv := range AdvertiseProtocolVersions {
    45  		lesTopics[i] = lesTopic(eth.BlockChain().Genesis().Hash(), pv)
    46  	}
    47  
    48  	srv := &LesServer{
    49  		config:           config,
    50  		protocolManager:  pm,
    51  		quitSync:         quitSync,
    52  		lesTopics:        lesTopics,
    53  		chtIndexer:       light.NewChtIndexer(eth.ChainDb(), false),
    54  		bloomTrieIndexer: light.NewBloomTrieIndexer(eth.ChainDb(), false),
    55  	}
    56  	logger := log.New()
    57  
    58  	chtV1SectionCount, _, _ := srv.chtIndexer.Sections() // indexer still uses LES/1 4k section size for backwards server compatibility
    59  	chtV2SectionCount := chtV1SectionCount / (light.CHTFrequencyClient / light.CHTFrequencyServer)
    60  	if chtV2SectionCount != 0 {
    61  		// convert to LES/2 section
    62  		chtLastSection := chtV2SectionCount - 1
    63  		// convert last LES/2 section index back to LES/1 index for chtIndexer.SectionHead
    64  		chtLastSectionV1 := (chtLastSection+1)*(light.CHTFrequencyClient/light.CHTFrequencyServer) - 1
    65  		chtSectionHead := srv.chtIndexer.SectionHead(chtLastSectionV1)
    66  		chtRoot := light.GetChtV2Root(pm.chainDb, chtLastSection, chtSectionHead)
    67  		logger.Info("Loaded CHT", "section", chtLastSection, "head", chtSectionHead, "root", chtRoot)
    68  	}
    69  	bloomTrieSectionCount, _, _ := srv.bloomTrieIndexer.Sections()
    70  	if bloomTrieSectionCount != 0 {
    71  		bloomTrieLastSection := bloomTrieSectionCount - 1
    72  		bloomTrieSectionHead := srv.bloomTrieIndexer.SectionHead(bloomTrieLastSection)
    73  		bloomTrieRoot := light.GetBloomTrieRoot(pm.chainDb, bloomTrieLastSection, bloomTrieSectionHead)
    74  		logger.Info("Loaded bloom trie", "section", bloomTrieLastSection, "head", bloomTrieSectionHead, "root", bloomTrieRoot)
    75  	}
    76  
    77  	srv.chtIndexer.Start(eth.BlockChain())
    78  	pm.server = srv
    79  
    80  	srv.defParams = &flowcontrol.ServerParams{
    81  		BufLimit:    300000000,
    82  		MinRecharge: 50000,
    83  	}
    84  	srv.fcManager = flowcontrol.NewClientManager(uint64(config.LightServ), 10, 1000000000)
    85  	srv.fcCostStats = newCostStats(eth.ChainDb())
    86  	return srv, nil
    87  }
    88  
    89  func (s *LesServer) Protocols() []p2p.Protocol {
    90  	return s.protocolManager.SubProtocols
    91  }
    92  
    93  // Start starts the LES server
    94  func (s *LesServer) Start(srvr *p2p.Server) {
    95  	s.protocolManager.Start(s.config.LightPeers)
    96  	if srvr.DiscV5 != nil {
    97  		for _, topic := range s.lesTopics {
    98  			topic := topic
    99  			go func() {
   100  				logger := log.New("topic", topic)
   101  				logger.Info("Starting topic registration")
   102  				defer logger.Info("Terminated topic registration")
   103  
   104  				srvr.DiscV5.RegisterTopic(topic, s.quitSync)
   105  			}()
   106  		}
   107  	}
   108  	s.privateKey = srvr.PrivateKey
   109  	s.protocolManager.blockLoop()
   110  }
   111  
   112  func (s *LesServer) SetBloomBitsIndexer(bloomIndexer *core.ChainIndexer) {
   113  	bloomIndexer.AddChildIndexer(s.bloomTrieIndexer)
   114  }
   115  
   116  // Stop stops the LES service
   117  func (s *LesServer) Stop() {
   118  	s.chtIndexer.Close()
   119  	// bloom trie indexer is closed by parent bloombits indexer
   120  	s.fcCostStats.store()
   121  	s.fcManager.Stop()
   122  	go func() {
   123  		<-s.protocolManager.noMorePeers
   124  	}()
   125  	s.protocolManager.Stop()
   126  }
   127  
   128  type requestCosts struct {
   129  	baseCost, reqCost uint64
   130  }
   131  
   132  type requestCostTable map[uint64]*requestCosts
   133  
   134  type RequestCostList []struct {
   135  	MsgCode, BaseCost, ReqCost uint64
   136  }
   137  
   138  func (list RequestCostList) decode() requestCostTable {
   139  	table := make(requestCostTable)
   140  	for _, e := range list {
   141  		table[e.MsgCode] = &requestCosts{
   142  			baseCost: e.BaseCost,
   143  			reqCost:  e.ReqCost,
   144  		}
   145  	}
   146  	return table
   147  }
   148  
   149  type linReg struct {
   150  	sumX, sumY, sumXX, sumXY float64
   151  	cnt                      uint64
   152  }
   153  
   154  const linRegMaxCnt = 100000
   155  
   156  func (l *linReg) add(x, y float64) {
   157  	if l.cnt >= linRegMaxCnt {
   158  		sub := float64(l.cnt+1-linRegMaxCnt) / linRegMaxCnt
   159  		l.sumX -= l.sumX * sub
   160  		l.sumY -= l.sumY * sub
   161  		l.sumXX -= l.sumXX * sub
   162  		l.sumXY -= l.sumXY * sub
   163  		l.cnt = linRegMaxCnt - 1
   164  	}
   165  	l.cnt++
   166  	l.sumX += x
   167  	l.sumY += y
   168  	l.sumXX += x * x
   169  	l.sumXY += x * y
   170  }
   171  
   172  func (l *linReg) calc() (b, m float64) {
   173  	if l.cnt == 0 {
   174  		return 0, 0
   175  	}
   176  	cnt := float64(l.cnt)
   177  	d := cnt*l.sumXX - l.sumX*l.sumX
   178  	if d < 0.001 {
   179  		return l.sumY / cnt, 0
   180  	}
   181  	m = (cnt*l.sumXY - l.sumX*l.sumY) / d
   182  	b = (l.sumY / cnt) - (m * l.sumX / cnt)
   183  	return b, m
   184  }
   185  
   186  func (l *linReg) toBytes() []byte {
   187  	var arr [40]byte
   188  	binary.BigEndian.PutUint64(arr[0:8], math.Float64bits(l.sumX))
   189  	binary.BigEndian.PutUint64(arr[8:16], math.Float64bits(l.sumY))
   190  	binary.BigEndian.PutUint64(arr[16:24], math.Float64bits(l.sumXX))
   191  	binary.BigEndian.PutUint64(arr[24:32], math.Float64bits(l.sumXY))
   192  	binary.BigEndian.PutUint64(arr[32:40], l.cnt)
   193  	return arr[:]
   194  }
   195  
   196  func linRegFromBytes(data []byte) *linReg {
   197  	if len(data) != 40 {
   198  		return nil
   199  	}
   200  	l := &linReg{}
   201  	l.sumX = math.Float64frombits(binary.BigEndian.Uint64(data[0:8]))
   202  	l.sumY = math.Float64frombits(binary.BigEndian.Uint64(data[8:16]))
   203  	l.sumXX = math.Float64frombits(binary.BigEndian.Uint64(data[16:24]))
   204  	l.sumXY = math.Float64frombits(binary.BigEndian.Uint64(data[24:32]))
   205  	l.cnt = binary.BigEndian.Uint64(data[32:40])
   206  	return l
   207  }
   208  
   209  type requestCostStats struct {
   210  	lock  sync.RWMutex
   211  	db    qctdb.Database
   212  	stats map[uint64]*linReg
   213  }
   214  
   215  type requestCostStatsRlp []struct {
   216  	MsgCode uint64
   217  	Data    []byte
   218  }
   219  
   220  var rcStatsKey = []byte("_requestCostStats")
   221  
   222  func newCostStats(db qctdb.Database) *requestCostStats {
   223  	stats := make(map[uint64]*linReg)
   224  	for _, code := range reqList {
   225  		stats[code] = &linReg{cnt: 100}
   226  	}
   227  
   228  	if db != nil {
   229  		data, err := db.Get(rcStatsKey)
   230  		var statsRlp requestCostStatsRlp
   231  		if err == nil {
   232  			err = rlp.DecodeBytes(data, &statsRlp)
   233  		}
   234  		if err == nil {
   235  			for _, r := range statsRlp {
   236  				if stats[r.MsgCode] != nil {
   237  					if l := linRegFromBytes(r.Data); l != nil {
   238  						stats[r.MsgCode] = l
   239  					}
   240  				}
   241  			}
   242  		}
   243  	}
   244  
   245  	return &requestCostStats{
   246  		db:    db,
   247  		stats: stats,
   248  	}
   249  }
   250  
   251  func (s *requestCostStats) store() {
   252  	s.lock.Lock()
   253  	defer s.lock.Unlock()
   254  
   255  	statsRlp := make(requestCostStatsRlp, len(reqList))
   256  	for i, code := range reqList {
   257  		statsRlp[i].MsgCode = code
   258  		statsRlp[i].Data = s.stats[code].toBytes()
   259  	}
   260  
   261  	if data, err := rlp.EncodeToBytes(statsRlp); err == nil {
   262  		s.db.Put(rcStatsKey, data)
   263  	}
   264  }
   265  
   266  func (s *requestCostStats) getCurrentList() RequestCostList {
   267  	s.lock.Lock()
   268  	defer s.lock.Unlock()
   269  
   270  	list := make(RequestCostList, len(reqList))
   271  	//fmt.Println("RequestCostList")
   272  	for idx, code := range reqList {
   273  		b, m := s.stats[code].calc()
   274  		//fmt.Println(code, s.stats[code].cnt, b/1000000, m/1000000)
   275  		if m < 0 {
   276  			b += m
   277  			m = 0
   278  		}
   279  		if b < 0 {
   280  			b = 0
   281  		}
   282  
   283  		list[idx].MsgCode = code
   284  		list[idx].BaseCost = uint64(b * 2)
   285  		list[idx].ReqCost = uint64(m * 2)
   286  	}
   287  	return list
   288  }
   289  
   290  func (s *requestCostStats) update(msgCode, reqCnt, cost uint64) {
   291  	s.lock.Lock()
   292  	defer s.lock.Unlock()
   293  
   294  	c, ok := s.stats[msgCode]
   295  	if !ok || reqCnt == 0 {
   296  		return
   297  	}
   298  	c.add(float64(reqCnt), float64(cost))
   299  }
   300  
   301  func (pm *ProtocolManager) blockLoop() {
   302  	pm.wg.Add(1)
   303  	headCh := make(chan core.ChainHeadEvent, 10)
   304  	headSub := pm.blockchain.SubscribeChainHeadEvent(headCh)
   305  	go func() {
   306  		var lastHead *types.Header
   307  		lastBroadcastTd := common.Big0
   308  		for {
   309  			select {
   310  			case ev := <-headCh:
   311  				peers := pm.peers.AllPeers()
   312  				if len(peers) > 0 {
   313  					header := ev.Block.Header()
   314  					hash := header.Hash()
   315  					number := header.Number.Uint64()
   316  					td := core.GetTd(pm.chainDb, hash, number)
   317  					if td != nil && td.Cmp(lastBroadcastTd) > 0 {
   318  						var reorg uint64
   319  						if lastHead != nil {
   320  							reorg = lastHead.Number.Uint64() - core.FindCommonAncestor(pm.chainDb, header, lastHead).Number.Uint64()
   321  						}
   322  						lastHead = header
   323  						lastBroadcastTd = td
   324  
   325  						log.Debug("Announcing block to peers", "number", number, "hash", hash, "td", td, "reorg", reorg)
   326  
   327  						announce := announceData{Hash: hash, Number: number, Td: td, ReorgDepth: reorg}
   328  						var (
   329  							signed         bool
   330  							signedAnnounce announceData
   331  						)
   332  
   333  						for _, p := range peers {
   334  							switch p.announceType {
   335  
   336  							case announceTypeSimple:
   337  								select {
   338  								case p.announceChn <- announce:
   339  								default:
   340  									pm.removePeer(p.id)
   341  								}
   342  
   343  							case announceTypeSigned:
   344  								if !signed {
   345  									signedAnnounce = announce
   346  									signedAnnounce.sign(pm.server.privateKey)
   347  									signed = true
   348  								}
   349  
   350  								select {
   351  								case p.announceChn <- signedAnnounce:
   352  								default:
   353  									pm.removePeer(p.id)
   354  								}
   355  							}
   356  						}
   357  					}
   358  				}
   359  			case <-pm.quitSync:
   360  				headSub.Unsubscribe()
   361  				pm.wg.Done()
   362  				return
   363  			}
   364  		}
   365  	}()
   366  }