github.com/reapchain/go-reapchain@v0.2.15-0.20210609012950-9735c110c705/les/server.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 Ethereum Subprotocol.
    18  package les
    19  
    20  import (
    21  	"encoding/binary"
    22  	"math"
    23  	"sync"
    24  	"time"
    25  
    26  	"github.com/ethereum/go-ethereum/common"
    27  	"github.com/ethereum/go-ethereum/core"
    28  	"github.com/ethereum/go-ethereum/core/types"
    29  	"github.com/ethereum/go-ethereum/eth"
    30  	"github.com/ethereum/go-ethereum/ethdb"
    31  	"github.com/ethereum/go-ethereum/les/flowcontrol"
    32  	"github.com/ethereum/go-ethereum/light"
    33  	"github.com/ethereum/go-ethereum/log"
    34  	"github.com/ethereum/go-ethereum/p2p"
    35  	"github.com/ethereum/go-ethereum/rlp"
    36  	"github.com/ethereum/go-ethereum/trie"
    37  )
    38  
    39  type LesServer struct {
    40  	protocolManager *ProtocolManager
    41  	fcManager       *flowcontrol.ClientManager // nil if our node is client only
    42  	fcCostStats     *requestCostStats
    43  	defParams       *flowcontrol.ServerParams
    44  	stopped         bool
    45  }
    46  
    47  func NewLesServer(eth *eth.Ethereum, config *eth.Config) (*LesServer, error) {
    48  	pm, err := NewProtocolManager(eth.BlockChain().Config(), false, config.NetworkId, eth.EventMux(), eth.Engine(), eth.BlockChain(), eth.TxPool(), eth.ChainDb(), nil, nil)
    49  	if err != nil {
    50  		return nil, err
    51  	}
    52  	pm.blockLoop()
    53  
    54  	srv := &LesServer{protocolManager: pm}
    55  	pm.server = srv
    56  
    57  	srv.defParams = &flowcontrol.ServerParams{
    58  		BufLimit:    300000000,
    59  		MinRecharge: 50000,
    60  	}
    61  	srv.fcManager = flowcontrol.NewClientManager(uint64(config.LightServ), 10, 1000000000)
    62  	srv.fcCostStats = newCostStats(eth.ChainDb())
    63  	return srv, nil
    64  }
    65  
    66  func (s *LesServer) Protocols() []p2p.Protocol {
    67  	return s.protocolManager.SubProtocols
    68  }
    69  
    70  // Start starts the LES server
    71  func (s *LesServer) Start(srvr *p2p.Server) {
    72  	s.protocolManager.Start(srvr)
    73  }
    74  
    75  // Stop stops the LES service
    76  func (s *LesServer) Stop() {
    77  	s.fcCostStats.store()
    78  	s.fcManager.Stop()
    79  	go func() {
    80  		<-s.protocolManager.noMorePeers
    81  	}()
    82  	s.protocolManager.Stop()
    83  }
    84  
    85  type requestCosts struct {
    86  	baseCost, reqCost uint64
    87  }
    88  
    89  type requestCostTable map[uint64]*requestCosts
    90  
    91  type RequestCostList []struct {
    92  	MsgCode, BaseCost, ReqCost uint64
    93  }
    94  
    95  func (list RequestCostList) decode() requestCostTable {
    96  	table := make(requestCostTable)
    97  	for _, e := range list {
    98  		table[e.MsgCode] = &requestCosts{
    99  			baseCost: e.BaseCost,
   100  			reqCost:  e.ReqCost,
   101  		}
   102  	}
   103  	return table
   104  }
   105  
   106  func (table requestCostTable) encode() RequestCostList {
   107  	list := make(RequestCostList, len(table))
   108  	for idx, code := range reqList {
   109  		list[idx].MsgCode = code
   110  		list[idx].BaseCost = table[code].baseCost
   111  		list[idx].ReqCost = table[code].reqCost
   112  	}
   113  	return list
   114  }
   115  
   116  type linReg struct {
   117  	sumX, sumY, sumXX, sumXY float64
   118  	cnt                      uint64
   119  }
   120  
   121  const linRegMaxCnt = 100000
   122  
   123  func (l *linReg) add(x, y float64) {
   124  	if l.cnt >= linRegMaxCnt {
   125  		sub := float64(l.cnt+1-linRegMaxCnt) / linRegMaxCnt
   126  		l.sumX -= l.sumX * sub
   127  		l.sumY -= l.sumY * sub
   128  		l.sumXX -= l.sumXX * sub
   129  		l.sumXY -= l.sumXY * sub
   130  		l.cnt = linRegMaxCnt - 1
   131  	}
   132  	l.cnt++
   133  	l.sumX += x
   134  	l.sumY += y
   135  	l.sumXX += x * x
   136  	l.sumXY += x * y
   137  }
   138  
   139  func (l *linReg) calc() (b, m float64) {
   140  	if l.cnt == 0 {
   141  		return 0, 0
   142  	}
   143  	cnt := float64(l.cnt)
   144  	d := cnt*l.sumXX - l.sumX*l.sumX
   145  	if d < 0.001 {
   146  		return l.sumY / cnt, 0
   147  	}
   148  	m = (cnt*l.sumXY - l.sumX*l.sumY) / d
   149  	b = (l.sumY / cnt) - (m * l.sumX / cnt)
   150  	return b, m
   151  }
   152  
   153  func (l *linReg) toBytes() []byte {
   154  	var arr [40]byte
   155  	binary.BigEndian.PutUint64(arr[0:8], math.Float64bits(l.sumX))
   156  	binary.BigEndian.PutUint64(arr[8:16], math.Float64bits(l.sumY))
   157  	binary.BigEndian.PutUint64(arr[16:24], math.Float64bits(l.sumXX))
   158  	binary.BigEndian.PutUint64(arr[24:32], math.Float64bits(l.sumXY))
   159  	binary.BigEndian.PutUint64(arr[32:40], l.cnt)
   160  	return arr[:]
   161  }
   162  
   163  func linRegFromBytes(data []byte) *linReg {
   164  	if len(data) != 40 {
   165  		return nil
   166  	}
   167  	l := &linReg{}
   168  	l.sumX = math.Float64frombits(binary.BigEndian.Uint64(data[0:8]))
   169  	l.sumY = math.Float64frombits(binary.BigEndian.Uint64(data[8:16]))
   170  	l.sumXX = math.Float64frombits(binary.BigEndian.Uint64(data[16:24]))
   171  	l.sumXY = math.Float64frombits(binary.BigEndian.Uint64(data[24:32]))
   172  	l.cnt = binary.BigEndian.Uint64(data[32:40])
   173  	return l
   174  }
   175  
   176  type requestCostStats struct {
   177  	lock  sync.RWMutex
   178  	db    ethdb.Database
   179  	stats map[uint64]*linReg
   180  }
   181  
   182  type requestCostStatsRlp []struct {
   183  	MsgCode uint64
   184  	Data    []byte
   185  }
   186  
   187  var rcStatsKey = []byte("_requestCostStats")
   188  
   189  func newCostStats(db ethdb.Database) *requestCostStats {
   190  	stats := make(map[uint64]*linReg)
   191  	for _, code := range reqList {
   192  		stats[code] = &linReg{cnt: 100}
   193  	}
   194  
   195  	if db != nil {
   196  		data, err := db.Get(rcStatsKey)
   197  		var statsRlp requestCostStatsRlp
   198  		if err == nil {
   199  			err = rlp.DecodeBytes(data, &statsRlp)
   200  		}
   201  		if err == nil {
   202  			for _, r := range statsRlp {
   203  				if stats[r.MsgCode] != nil {
   204  					if l := linRegFromBytes(r.Data); l != nil {
   205  						stats[r.MsgCode] = l
   206  					}
   207  				}
   208  			}
   209  		}
   210  	}
   211  
   212  	return &requestCostStats{
   213  		db:    db,
   214  		stats: stats,
   215  	}
   216  }
   217  
   218  func (s *requestCostStats) store() {
   219  	s.lock.Lock()
   220  	defer s.lock.Unlock()
   221  
   222  	statsRlp := make(requestCostStatsRlp, len(reqList))
   223  	for i, code := range reqList {
   224  		statsRlp[i].MsgCode = code
   225  		statsRlp[i].Data = s.stats[code].toBytes()
   226  	}
   227  
   228  	if data, err := rlp.EncodeToBytes(statsRlp); err == nil {
   229  		s.db.Put(rcStatsKey, data)
   230  	}
   231  }
   232  
   233  func (s *requestCostStats) getCurrentList() RequestCostList {
   234  	s.lock.Lock()
   235  	defer s.lock.Unlock()
   236  
   237  	list := make(RequestCostList, len(reqList))
   238  	//fmt.Println("RequestCostList")
   239  	for idx, code := range reqList {
   240  		b, m := s.stats[code].calc()
   241  		//fmt.Println(code, s.stats[code].cnt, b/1000000, m/1000000)
   242  		if m < 0 {
   243  			b += m
   244  			m = 0
   245  		}
   246  		if b < 0 {
   247  			b = 0
   248  		}
   249  
   250  		list[idx].MsgCode = code
   251  		list[idx].BaseCost = uint64(b * 2)
   252  		list[idx].ReqCost = uint64(m * 2)
   253  	}
   254  	return list
   255  }
   256  
   257  func (s *requestCostStats) update(msgCode, reqCnt, cost uint64) {
   258  	s.lock.Lock()
   259  	defer s.lock.Unlock()
   260  
   261  	c, ok := s.stats[msgCode]
   262  	if !ok || reqCnt == 0 {
   263  		return
   264  	}
   265  	c.add(float64(reqCnt), float64(cost))
   266  }
   267  
   268  func (pm *ProtocolManager) blockLoop() {
   269  	pm.wg.Add(1)
   270  	sub := pm.eventMux.Subscribe(core.ChainHeadEvent{})
   271  	newCht := make(chan struct{}, 10)
   272  	newCht <- struct{}{}
   273  	go func() {
   274  		var mu sync.Mutex
   275  		var lastHead *types.Header
   276  		lastBroadcastTd := common.Big0
   277  		for {
   278  			select {
   279  			case ev := <-sub.Chan():
   280  				peers := pm.peers.AllPeers()
   281  				if len(peers) > 0 {
   282  					header := ev.Data.(core.ChainHeadEvent).Block.Header()
   283  					hash := header.Hash()
   284  					number := header.Number.Uint64()
   285  					td := core.GetTd(pm.chainDb, hash, number)
   286  					if td != nil && td.Cmp(lastBroadcastTd) > 0 {
   287  						var reorg uint64
   288  						if lastHead != nil {
   289  							reorg = lastHead.Number.Uint64() - core.FindCommonAncestor(pm.chainDb, header, lastHead).Number.Uint64()
   290  						}
   291  						lastHead = header
   292  						lastBroadcastTd = td
   293  
   294  						log.Debug("Announcing block to peers", "number", number, "hash", hash, "td", td, "reorg", reorg)
   295  
   296  						announce := announceData{Hash: hash, Number: number, Td: td, ReorgDepth: reorg}
   297  						for _, p := range peers {
   298  							select {
   299  							case p.announceChn <- announce:
   300  							default:
   301  								pm.removePeer(p.id)
   302  							}
   303  						}
   304  					}
   305  				}
   306  				newCht <- struct{}{}
   307  			case <-newCht:
   308  				go func() {
   309  					mu.Lock()
   310  					more := makeCht(pm.chainDb)
   311  					mu.Unlock()
   312  					if more {
   313  						time.Sleep(time.Millisecond * 10)
   314  						newCht <- struct{}{}
   315  					}
   316  				}()
   317  			case <-pm.quitSync:
   318  				sub.Unsubscribe()
   319  				pm.wg.Done()
   320  				return
   321  			}
   322  		}
   323  	}()
   324  }
   325  
   326  var (
   327  	lastChtKey = []byte("LastChtNumber") // chtNum (uint64 big endian)
   328  	chtPrefix  = []byte("cht")           // chtPrefix + chtNum (uint64 big endian) -> trie root hash
   329  )
   330  
   331  func getChtRoot(db ethdb.Database, num uint64) common.Hash {
   332  	var encNumber [8]byte
   333  	binary.BigEndian.PutUint64(encNumber[:], num)
   334  	data, _ := db.Get(append(chtPrefix, encNumber[:]...))
   335  	return common.BytesToHash(data)
   336  }
   337  
   338  func storeChtRoot(db ethdb.Database, num uint64, root common.Hash) {
   339  	var encNumber [8]byte
   340  	binary.BigEndian.PutUint64(encNumber[:], num)
   341  	db.Put(append(chtPrefix, encNumber[:]...), root[:])
   342  }
   343  
   344  func makeCht(db ethdb.Database) bool {
   345  	headHash := core.GetHeadBlockHash(db)
   346  	headNum := core.GetBlockNumber(db, headHash)
   347  
   348  	var newChtNum uint64
   349  	if headNum > light.ChtConfirmations {
   350  		newChtNum = (headNum - light.ChtConfirmations) / light.ChtFrequency
   351  	}
   352  
   353  	var lastChtNum uint64
   354  	data, _ := db.Get(lastChtKey)
   355  	if len(data) == 8 {
   356  		lastChtNum = binary.BigEndian.Uint64(data[:])
   357  	}
   358  	if newChtNum <= lastChtNum {
   359  		return false
   360  	}
   361  
   362  	var t *trie.Trie
   363  	if lastChtNum > 0 {
   364  		var err error
   365  		t, err = trie.New(getChtRoot(db, lastChtNum), db)
   366  		if err != nil {
   367  			lastChtNum = 0
   368  		}
   369  	}
   370  	if lastChtNum == 0 {
   371  		t, _ = trie.New(common.Hash{}, db)
   372  	}
   373  
   374  	for num := lastChtNum * light.ChtFrequency; num < (lastChtNum+1)*light.ChtFrequency; num++ {
   375  		hash := core.GetCanonicalHash(db, num)
   376  		if hash == (common.Hash{}) {
   377  			panic("Canonical hash not found")
   378  		}
   379  		td := core.GetTd(db, hash, num)
   380  		if td == nil {
   381  			panic("TD not found")
   382  		}
   383  		var encNumber [8]byte
   384  		binary.BigEndian.PutUint64(encNumber[:], num)
   385  		var node light.ChtNode
   386  		node.Hash = hash
   387  		node.Td = td
   388  		data, _ := rlp.EncodeToBytes(node)
   389  		t.Update(encNumber[:], data)
   390  	}
   391  
   392  	root, err := t.Commit()
   393  	if err != nil {
   394  		lastChtNum = 0
   395  	} else {
   396  		lastChtNum++
   397  
   398  		log.Trace("Generated CHT", "number", lastChtNum, "root", root.Hex())
   399  
   400  		storeChtRoot(db, lastChtNum, root)
   401  		var data [8]byte
   402  		binary.BigEndian.PutUint64(data[:], lastChtNum)
   403  		db.Put(lastChtKey, data[:])
   404  	}
   405  
   406  	return newChtNum > lastChtNum
   407  }