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