diff --git a/les/peer.go b/les/peer.go index 4b69c70350..26c38501ce 100644 --- a/les/peer.go +++ b/les/peer.go @@ -49,6 +49,11 @@ const ( allowedUpdateRate = time.Millisecond * 10 // time constant for recharging one byte of allowance ) +// 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 ( announceTypeNone = iota announceTypeSimple @@ -200,6 +205,32 @@ func (p *peer) GetRequestCost(msgcode uint64, amount int) uint64 { return cost } +func (p *peer) GetTxRelayCost(amount, size int) uint64 { + p.lock.RLock() + defer p.lock.RUnlock() + + var msgcode uint64 + switch p.version { + case lpv1: + msgcode = SendTxMsg + case lpv2: + msgcode = SendTxV2Msg + default: + panic(nil) + } + + cost := p.fcCosts[msgcode].baseCost + p.fcCosts[msgcode].reqCost*uint64(amount) + sizeCost := p.fcCosts[msgcode].baseCost + p.fcCosts[msgcode].reqCost*uint64(size)/txSizeCostLimit + if sizeCost > cost { + cost = sizeCost + } + + if cost > p.fcServerParams.BufLimit { + cost = p.fcServerParams.BufLimit + } + return cost +} + // HasBlock checks if the peer has a given block func (p *peer) HasBlock(hash common.Hash, number uint64, hasState bool) bool { p.lock.RLock() @@ -338,8 +369,8 @@ func (p *peer) RequestTxStatus(reqID, cost uint64, txHashes []common.Hash) error } // SendTxStatus sends a batch of transactions to be added to the remote transaction pool. -func (p *peer) SendTxs(reqID, cost uint64, txs types.Transactions) error { - p.Log().Debug("Fetching batch of transactions", "count", len(txs)) +func (p *peer) SendTxs(reqID, cost uint64, txs rlp.RawValue) error { + p.Log().Debug("Sending batch of transactions", "size", len(txs)) switch p.version { case lpv1: return p2p.Send(p.rw, SendTxMsg, txs) // old message format does not include reqID diff --git a/les/txrelay.go b/les/txrelay.go index 7a02cc837e..5decd6e93a 100644 --- a/les/txrelay.go +++ b/les/txrelay.go @@ -21,6 +21,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/rlp" ) type ltrInfo struct { @@ -113,21 +114,22 @@ func (self *LesTxRelay) send(txs types.Transactions, count int) { for p, list := range sendTo { pp := p ll := list + enc, _ := rlp.EncodeToBytes(ll) reqID := genReqID() rq := &distReq{ getCost: func(dp distPeer) uint64 { peer := dp.(*peer) - return peer.GetRequestCost(SendTxMsg, len(ll)) + return peer.GetTxRelayCost(len(ll), len(enc)) }, canSend: func(dp distPeer) bool { return dp.(*peer) == pp }, request: func(dp distPeer) func() { peer := dp.(*peer) - cost := peer.GetRequestCost(SendTxMsg, len(ll)) + cost := peer.GetTxRelayCost(len(ll), len(enc)) peer.fcServer.QueueRequest(reqID, cost) - return func() { peer.SendTxs(reqID, cost, ll) } + return func() { peer.SendTxs(reqID, cost, enc) } }, } self.reqDist.queue(rq)