Skip to content

Commit cdae1c5

Browse files
authored
Merge pull request #19437 from zsfelfoldi/fix-sendtx
les: fix SendTx cost calculation and verify cost table
2 parents 14ae124 + 0b00e19 commit cdae1c5

File tree

6 files changed

+72
-12
lines changed

6 files changed

+72
-12
lines changed

les/handler.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -324,7 +324,11 @@ func (pm *ProtocolManager) handle(p *peer) error {
324324
}
325325
}
326326

327-
var reqList = []uint64{GetBlockHeadersMsg, GetBlockBodiesMsg, GetCodeMsg, GetReceiptsMsg, GetProofsV1Msg, SendTxMsg, SendTxV2Msg, GetTxStatusMsg, GetHeaderProofsMsg, GetProofsV2Msg, GetHelperTrieProofsMsg}
327+
var (
328+
reqList = []uint64{GetBlockHeadersMsg, GetBlockBodiesMsg, GetCodeMsg, GetReceiptsMsg, GetProofsV1Msg, SendTxMsg, SendTxV2Msg, GetTxStatusMsg, GetHeaderProofsMsg, GetProofsV2Msg, GetHelperTrieProofsMsg}
329+
reqListV1 = []uint64{GetBlockHeadersMsg, GetBlockBodiesMsg, GetCodeMsg, GetReceiptsMsg, GetProofsV1Msg, SendTxMsg, GetHeaderProofsMsg}
330+
reqListV2 = []uint64{GetBlockHeadersMsg, GetBlockBodiesMsg, GetCodeMsg, GetReceiptsMsg, SendTxV2Msg, GetTxStatusMsg, GetProofsV2Msg, GetHelperTrieProofsMsg}
331+
)
328332

329333
// handleMsg is invoked whenever an inbound message is received from a remote
330334
// peer. The remote connection is torn down upon returning any error.

les/handler_test.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -508,8 +508,9 @@ func TestTransactionStatusLes2(t *testing.T) {
508508
test := func(tx *types.Transaction, send bool, expStatus txStatus) {
509509
reqID++
510510
if send {
511-
cost := peer.GetRequestCost(SendTxV2Msg, 1)
512-
sendRequest(peer.app, SendTxV2Msg, reqID, cost, types.Transactions{tx})
511+
enc, _ := rlp.EncodeToBytes(types.Transactions{tx})
512+
cost := peer.GetTxRelayCost(1, len(enc))
513+
sendRequest(peer.app, SendTxV2Msg, reqID, cost, rlp.RawValue(enc))
513514
} else {
514515
cost := peer.GetRequestCost(GetTxStatusMsg, 1)
515516
sendRequest(peer.app, GetTxStatusMsg, reqID, cost, []common.Hash{tx.Hash()})

les/peer.go

Lines changed: 57 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,11 @@ var (
4242

4343
const maxResponseErrors = 50 // number of invalid responses tolerated (makes the protocol less brittle but still avoids spam)
4444

45+
// if the total encoded size of a sent transaction batch is over txSizeCostLimit
46+
// per transaction then the request cost is calculated as proportional to the
47+
// encoded size instead of the transaction count
48+
const txSizeCostLimit = 0x4000
49+
4550
const (
4651
announceTypeNone = iota
4752
announceTypeSimple
@@ -163,7 +168,41 @@ func (p *peer) GetRequestCost(msgcode uint64, amount int) uint64 {
163168
p.lock.RLock()
164169
defer p.lock.RUnlock()
165170

166-
cost := p.fcCosts[msgcode].baseCost + p.fcCosts[msgcode].reqCost*uint64(amount)
171+
costs := p.fcCosts[msgcode]
172+
if costs == nil {
173+
return 0
174+
}
175+
cost := costs.baseCost + costs.reqCost*uint64(amount)
176+
if cost > p.fcServerParams.BufLimit {
177+
cost = p.fcServerParams.BufLimit
178+
}
179+
return cost
180+
}
181+
182+
func (p *peer) GetTxRelayCost(amount, size int) uint64 {
183+
p.lock.RLock()
184+
defer p.lock.RUnlock()
185+
186+
var msgcode uint64
187+
switch p.version {
188+
case lpv1:
189+
msgcode = SendTxMsg
190+
case lpv2:
191+
msgcode = SendTxV2Msg
192+
default:
193+
panic(nil)
194+
}
195+
196+
costs := p.fcCosts[msgcode]
197+
if costs == nil {
198+
return 0
199+
}
200+
cost := costs.baseCost + costs.reqCost*uint64(amount)
201+
sizeCost := costs.baseCost + costs.reqCost*uint64(size)/txSizeCostLimit
202+
if sizeCost > cost {
203+
cost = sizeCost
204+
}
205+
167206
if cost > p.fcServerParams.BufLimit {
168207
cost = p.fcServerParams.BufLimit
169208
}
@@ -307,9 +346,9 @@ func (p *peer) RequestTxStatus(reqID, cost uint64, txHashes []common.Hash) error
307346
return sendRequest(p.rw, GetTxStatusMsg, reqID, cost, txHashes)
308347
}
309348

310-
// SendTxStatus sends a batch of transactions to be added to the remote transaction pool.
311-
func (p *peer) SendTxs(reqID, cost uint64, txs types.Transactions) error {
312-
p.Log().Debug("Fetching batch of transactions", "count", len(txs))
349+
// SendTxs sends a batch of transactions to be added to the remote transaction pool.
350+
func (p *peer) SendTxs(reqID, cost uint64, txs rlp.RawValue) error {
351+
p.Log().Debug("Fetching batch of transactions", "size", len(txs))
313352
switch p.version {
314353
case lpv1:
315354
return p2p.Send(p.rw, SendTxMsg, txs) // old message format does not include reqID
@@ -485,6 +524,20 @@ func (p *peer) Handshake(td *big.Int, head common.Hash, headNum uint64, genesis
485524
p.fcServerParams = params
486525
p.fcServer = flowcontrol.NewServerNode(params)
487526
p.fcCosts = MRC.decode()
527+
var checkList []uint64
528+
switch p.version {
529+
case lpv1:
530+
checkList = reqListV1
531+
case lpv2:
532+
checkList = reqListV2
533+
default:
534+
panic(nil)
535+
}
536+
for _, msgCode := range checkList {
537+
if p.fcCosts[msgCode] == nil {
538+
return errResp(ErrUselessPeer, "peer does not support message %d", msgCode)
539+
}
540+
}
488541
}
489542

490543
p.headInfo = &announceData{Td: rTd, Hash: rHash, Number: rNum}

les/txrelay.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121

2222
"github.com/ethereum/go-ethereum/common"
2323
"github.com/ethereum/go-ethereum/core/types"
24+
"github.com/ethereum/go-ethereum/rlp"
2425
)
2526

2627
type ltrInfo struct {
@@ -113,21 +114,22 @@ func (self *LesTxRelay) send(txs types.Transactions, count int) {
113114
for p, list := range sendTo {
114115
pp := p
115116
ll := list
117+
enc, _ := rlp.EncodeToBytes(ll)
116118

117119
reqID := genReqID()
118120
rq := &distReq{
119121
getCost: func(dp distPeer) uint64 {
120122
peer := dp.(*peer)
121-
return peer.GetRequestCost(SendTxMsg, len(ll))
123+
return peer.GetTxRelayCost(len(ll), len(enc))
122124
},
123125
canSend: func(dp distPeer) bool {
124126
return dp.(*peer) == pp
125127
},
126128
request: func(dp distPeer) func() {
127129
peer := dp.(*peer)
128-
cost := peer.GetRequestCost(SendTxMsg, len(ll))
130+
cost := peer.GetTxRelayCost(len(ll), len(enc))
129131
peer.fcServer.QueueRequest(reqID, cost)
130-
return func() { peer.SendTxs(reqID, cost, ll) }
132+
return func() { peer.SendTxs(reqID, cost, enc) }
131133
},
132134
}
133135
self.reqDist.queue(rq)

params/version.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import (
2323
const (
2424
VersionMajor = 1 // Major version component of the current release
2525
VersionMinor = 8 // Minor version component of the current release
26-
VersionPatch = 25 // Patch version component of the current release
26+
VersionPatch = 26 // Patch version component of the current release
2727
VersionMeta = "stable" // Version metadata to append to the version string
2828
)
2929

swarm/version/version.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import (
2323
const (
2424
VersionMajor = 0 // Major version component of the current release
2525
VersionMinor = 3 // Minor version component of the current release
26-
VersionPatch = 13 // Patch version component of the current release
26+
VersionPatch = 14 // Patch version component of the current release
2727
VersionMeta = "stable" // Version metadata to append to the version string
2828
)
2929

0 commit comments

Comments
 (0)