From 0f3222aaf0d8a7ec6928f687cdd233c9334dbb2e Mon Sep 17 00:00:00 2001 From: Zsolt Felfoldi Date: Sat, 6 Apr 2019 16:37:59 +0200 Subject: [PATCH] les: minCapacity calculation based on cpu and bandwidth limits --- cmd/utils/flags.go | 4 ++-- les/api.go | 4 ++-- les/costtracker.go | 39 +++++++++++++++++++++++++++++---------- les/peer.go | 4 ++-- les/server.go | 16 ++++++++-------- 5 files changed, 43 insertions(+), 24 deletions(-) diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index ddeb44f346..90e23556a3 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -206,12 +206,12 @@ var ( LightBandwidthInFlag = cli.IntFlag{ Name: "lightbwin", Usage: "Incoming bandwidth limit for light server (1000 bytes/sec, 0 = unlimited)", - Value: 1000, + Value: 0, } LightBandwidthOutFlag = cli.IntFlag{ Name: "lightbwout", Usage: "Outgoing bandwidth limit for light server (1000 bytes/sec, 0 = unlimited)", - Value: 5000, + Value: 0, } LightPeersFlag = cli.IntFlag{ Name: "lightpeers", diff --git a/les/api.go b/les/api.go index 24547f3da7..3a8d49ca5e 100644 --- a/les/api.go +++ b/les/api.go @@ -101,7 +101,7 @@ func (s tcSubs) send(tc uint64, underrun bool) { // MinimumCapacity queries minimum assignable capacity for a single client func (api *PrivateLightServerAPI) MinimumCapacity() hexutil.Uint64 { - return hexutil.Uint64(minCapacity) + return hexutil.Uint64(api.server.minCapacity) } // FreeClientCapacity queries the capacity provided for free clients @@ -117,7 +117,7 @@ func (api *PrivateLightServerAPI) FreeClientCapacity() hexutil.Uint64 { // Note: assigned capacity can be changed while the client is connected with // immediate effect. func (api *PrivateLightServerAPI) SetClientCapacity(id enode.ID, cap uint64) error { - if cap != 0 && cap < minCapacity { + if cap != 0 && cap < api.server.minCapacity { return ErrMinCap } return api.server.priorityClientPool.setClientCapacity(id, cap) diff --git a/les/costtracker.go b/les/costtracker.go index 6e822fc282..904c5e72f7 100644 --- a/les/costtracker.go +++ b/les/costtracker.go @@ -54,7 +54,7 @@ var ( GetCodeMsg: {0, 80}, GetProofsV2Msg: {0, 80}, GetHelperTrieProofsMsg: {0, 20}, - SendTxV2Msg: {0, 66000}, + SendTxV2Msg: {0, 16500}, GetTxStatusMsg: {0, 50}, } // maximum outgoing message size estimates @@ -68,8 +68,18 @@ var ( SendTxV2Msg: {0, 100}, GetTxStatusMsg: {0, 100}, } - minBufLimit = uint64(50000000 * maxCostFactor) // minimum buffer limit allowed for a client - minCapacity = (minBufLimit-1)/bufLimitRatio + 1 // minimum capacity allowed for a client + // request amounts that have to fit into the minimum buffer size minBufferMultiplier times + minBufferReqAmount = map[uint64]uint64{ + GetBlockHeadersMsg: 192, + GetBlockBodiesMsg: 1, + GetReceiptsMsg: 1, + GetCodeMsg: 1, + GetProofsV2Msg: 1, + GetHelperTrieProofsMsg: 16, + SendTxV2Msg: 8, + GetTxStatusMsg: 64, + } + minBufferMultiplier = 3 ) const ( @@ -107,7 +117,7 @@ type costTracker struct { } // newCostTracker creates a cost tracker and loads the cost factor statistics from the database -func newCostTracker(db ethdb.Database, config *eth.Config, logger *csvlogger.Logger) *costTracker { +func newCostTracker(db ethdb.Database, config *eth.Config, logger *csvlogger.Logger) (*costTracker, uint64) { utilTarget := float64(config.LightServ) * flowcontrol.FixedPointMultiplier / 100 ct := &costTracker{ db: db, @@ -131,7 +141,18 @@ func newCostTracker(db ethdb.Database, config *eth.Config, logger *csvlogger.Log } } ct.gfLoop() - return ct + costList := ct.makeCostList(ct.globalFactor() * 1.25) + var minBufLimit uint64 + for _, c := range costList { + amount := minBufferReqAmount[c.MsgCode] + cost := c.BaseCost + amount*c.ReqCost + if cost > minBufLimit { + minBufLimit = cost + } + } + minBufLimit *= uint64(minBufferMultiplier) + minCapacity := (minBufLimit-1)/bufLimitRatio + 1 + return ct, minCapacity } // stop stops the cost tracker and saves the cost factor statistics to the database @@ -146,16 +167,14 @@ func (ct *costTracker) stop() { // makeCostList returns upper cost estimates based on the hardcoded cost estimate // tables and the optionally specified incoming/outgoing bandwidth limits -func (ct *costTracker) makeCostList() RequestCostList { +func (ct *costTracker) makeCostList(globalFactor float64) RequestCostList { maxCost := func(avgTime, inSize, outSize uint64) uint64 { - globalFactor := ct.globalFactor() - cost := avgTime * maxCostFactor - inSizeCost := uint64(float64(inSize) * ct.inSizeFactor * globalFactor * maxCostFactor) + inSizeCost := uint64(float64(inSize) * ct.inSizeFactor * globalFactor) if inSizeCost > cost { cost = inSizeCost } - outSizeCost := uint64(float64(outSize) * ct.outSizeFactor * globalFactor * maxCostFactor) + outSizeCost := uint64(float64(outSize) * ct.outSizeFactor * globalFactor) if outSizeCost > cost { cost = outSizeCost } diff --git a/les/peer.go b/les/peer.go index e4a7d01e8b..a29a135111 100644 --- a/les/peer.go +++ b/les/peer.go @@ -58,7 +58,7 @@ const ( // if the total encoded size of a sent transaction batch is over txSizeCostLimit // per transaction then the request cost is calculated as proportional to the // encoded size instead of the transaction count -const txSizeCostLimit = 0x10000 +const txSizeCostLimit = 0x4000 const ( announceTypeNone = iota @@ -537,7 +537,7 @@ func (p *peer) Handshake(td *big.Int, head common.Hash, headNum uint64, genesis send = send.add("flowControl/MRR", server.defParams.MinRecharge) var costList RequestCostList if server.costTracker != nil { - costList = server.costTracker.makeCostList() + costList = server.costTracker.makeCostList(server.costTracker.globalFactor()) } else { costList = testCostList() } diff --git a/les/server.go b/les/server.go index 27d4ce091f..78d9618e2b 100644 --- a/les/server.go +++ b/les/server.go @@ -63,10 +63,10 @@ type LesServer struct { thcNormal, thcBlockProcessing int // serving thread count for normal operation and block processing mode - maxPeers int - freeClientCap uint64 - freeClientPool *freeClientPool - priorityClientPool *priorityClientPool + maxPeers int + minCapacity, freeClientCap uint64 + freeClientPool *freeClientPool + priorityClientPool *priorityClientPool } func NewLesServer(eth *eth.Ethereum, config *eth.Config) (*LesServer, error) { @@ -119,13 +119,13 @@ func NewLesServer(eth *eth.Ethereum, config *eth.Config) (*LesServer, error) { bloomTrieIndexer: light.NewBloomTrieIndexer(eth.ChainDb(), nil, params.BloomBitsBlocks, params.BloomTrieFrequency), protocolManager: pm, }, - costTracker: newCostTracker(eth.ChainDb(), config, requestLogger), quitSync: quitSync, lesTopics: lesTopics, onlyAnnounce: config.OnlyAnnounce, csvLogger: csvLogger, logTotalCap: requestLogger.NewChannel("totalCapacity", 0.01), } + srv.costTracker, srv.minCapacity = newCostTracker(eth.ChainDb(), config, requestLogger) logger := log.New() pm.server = srv @@ -229,9 +229,9 @@ func (s *LesServer) Start(srvr *p2p.Server) { s.maxPeers = s.config.LightPeers totalRecharge := s.costTracker.totalRecharge() if s.maxPeers > 0 { - s.freeClientCap = minCapacity //totalRecharge / uint64(s.maxPeers) - if s.freeClientCap < minCapacity { - s.freeClientCap = minCapacity + s.freeClientCap = s.minCapacity //totalRecharge / uint64(s.maxPeers) + if s.freeClientCap < s.minCapacity { + s.freeClientCap = s.minCapacity } if s.freeClientCap > 0 { s.defParams = flowcontrol.ServerParams{