|
|
|
@ -27,6 +27,7 @@ import ( |
|
|
|
|
"github.com/ethereum/go-ethereum/common/mclock" |
|
|
|
|
"github.com/ethereum/go-ethereum/core/txpool" |
|
|
|
|
"github.com/ethereum/go-ethereum/core/types" |
|
|
|
|
"github.com/ethereum/go-ethereum/params" |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
var ( |
|
|
|
@ -993,15 +994,14 @@ func TestTransactionFetcherTimeoutTimerResets(t *testing.T) { |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Tests that if thousands of transactions are announces, only a small
|
|
|
|
|
// Tests that if thousands of transactions are announced, only a small
|
|
|
|
|
// number of them will be requested at a time.
|
|
|
|
|
func TestTransactionFetcherRateLimiting(t *testing.T) { |
|
|
|
|
// Create a slew of transactions and to announce them
|
|
|
|
|
// Create a slew of transactions and announce them
|
|
|
|
|
var hashes []common.Hash |
|
|
|
|
for i := 0; i < maxTxAnnounces; i++ { |
|
|
|
|
hashes = append(hashes, common.Hash{byte(i / 256), byte(i % 256)}) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
testTransactionFetcherParallel(t, txFetcherTest{ |
|
|
|
|
init: func() *TxFetcher { |
|
|
|
|
return NewTxFetcher( |
|
|
|
@ -1029,6 +1029,68 @@ func TestTransactionFetcherRateLimiting(t *testing.T) { |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Tests that if huge transactions are announced, only a small number of them will
|
|
|
|
|
// be requested at a time, to keep the responses below a resonable level.
|
|
|
|
|
func TestTransactionFetcherBandwidthLimiting(t *testing.T) { |
|
|
|
|
testTransactionFetcherParallel(t, txFetcherTest{ |
|
|
|
|
init: func() *TxFetcher { |
|
|
|
|
return NewTxFetcher( |
|
|
|
|
func(common.Hash) bool { return false }, |
|
|
|
|
nil, |
|
|
|
|
func(string, []common.Hash) error { return nil }, |
|
|
|
|
nil, |
|
|
|
|
) |
|
|
|
|
}, |
|
|
|
|
steps: []interface{}{ |
|
|
|
|
// Announce mid size transactions from A to verify that multiple
|
|
|
|
|
// ones can be piled into a single request.
|
|
|
|
|
doTxNotify{peer: "A", |
|
|
|
|
hashes: []common.Hash{{0x01}, {0x02}, {0x03}, {0x04}}, |
|
|
|
|
types: []byte{types.LegacyTxType, types.LegacyTxType, types.LegacyTxType, types.LegacyTxType}, |
|
|
|
|
sizes: []uint32{48 * 1024, 48 * 1024, 48 * 1024, 48 * 1024}, |
|
|
|
|
}, |
|
|
|
|
// Announce exactly on the limit transactions to see that only one
|
|
|
|
|
// gets requested
|
|
|
|
|
doTxNotify{peer: "B", |
|
|
|
|
hashes: []common.Hash{{0x05}, {0x06}}, |
|
|
|
|
types: []byte{types.LegacyTxType, types.LegacyTxType}, |
|
|
|
|
sizes: []uint32{maxTxRetrievalSize, maxTxRetrievalSize}, |
|
|
|
|
}, |
|
|
|
|
// Announce oversized blob transactions to see that overflows are ok
|
|
|
|
|
doTxNotify{peer: "C", |
|
|
|
|
hashes: []common.Hash{{0x07}, {0x08}}, |
|
|
|
|
types: []byte{types.BlobTxType, types.BlobTxType}, |
|
|
|
|
sizes: []uint32{params.MaxBlobGasPerBlock, params.MaxBlobGasPerBlock}, |
|
|
|
|
}, |
|
|
|
|
doWait{time: txArriveTimeout, step: true}, |
|
|
|
|
isWaiting(nil), |
|
|
|
|
isScheduledWithMeta{ |
|
|
|
|
tracking: map[string][]announce{ |
|
|
|
|
"A": { |
|
|
|
|
{common.Hash{0x01}, typeptr(types.LegacyTxType), sizeptr(48 * 1024)}, |
|
|
|
|
{common.Hash{0x02}, typeptr(types.LegacyTxType), sizeptr(48 * 1024)}, |
|
|
|
|
{common.Hash{0x03}, typeptr(types.LegacyTxType), sizeptr(48 * 1024)}, |
|
|
|
|
{common.Hash{0x04}, typeptr(types.LegacyTxType), sizeptr(48 * 1024)}, |
|
|
|
|
}, |
|
|
|
|
"B": { |
|
|
|
|
{common.Hash{0x05}, typeptr(types.LegacyTxType), sizeptr(maxTxRetrievalSize)}, |
|
|
|
|
{common.Hash{0x06}, typeptr(types.LegacyTxType), sizeptr(maxTxRetrievalSize)}, |
|
|
|
|
}, |
|
|
|
|
"C": { |
|
|
|
|
{common.Hash{0x07}, typeptr(types.BlobTxType), sizeptr(params.MaxBlobGasPerBlock)}, |
|
|
|
|
{common.Hash{0x08}, typeptr(types.BlobTxType), sizeptr(params.MaxBlobGasPerBlock)}, |
|
|
|
|
}, |
|
|
|
|
}, |
|
|
|
|
fetching: map[string][]common.Hash{ |
|
|
|
|
"A": {{0x02}, {0x03}, {0x04}}, |
|
|
|
|
"B": {{0x06}}, |
|
|
|
|
"C": {{0x08}}, |
|
|
|
|
}, |
|
|
|
|
}, |
|
|
|
|
}, |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Tests that then number of transactions a peer is allowed to announce and/or
|
|
|
|
|
// request at the same time is hard capped.
|
|
|
|
|
func TestTransactionFetcherDoSProtection(t *testing.T) { |
|
|
|
@ -1664,7 +1726,7 @@ func testTransactionFetcher(t *testing.T, tt txFetcherTest) { |
|
|
|
|
if (meta == nil && (ann.kind != nil || ann.size != nil)) || |
|
|
|
|
(meta != nil && (ann.kind == nil || ann.size == nil)) || |
|
|
|
|
(meta != nil && (meta.kind != *ann.kind || meta.size != *ann.size)) { |
|
|
|
|
t.Errorf("step %d, peer %s, hash %x: waitslot metadata mismatch: want %v, have %v/%v", i, peer, ann.hash, meta, ann.kind, ann.size) |
|
|
|
|
t.Errorf("step %d, peer %s, hash %x: waitslot metadata mismatch: want %v, have %v/%v", i, peer, ann.hash, meta, *ann.kind, *ann.size) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -1733,7 +1795,7 @@ func testTransactionFetcher(t *testing.T, tt txFetcherTest) { |
|
|
|
|
if (meta == nil && (ann.kind != nil || ann.size != nil)) || |
|
|
|
|
(meta != nil && (ann.kind == nil || ann.size == nil)) || |
|
|
|
|
(meta != nil && (meta.kind != *ann.kind || meta.size != *ann.size)) { |
|
|
|
|
t.Errorf("step %d, peer %s, hash %x: announce metadata mismatch: want %v, have %v/%v", i, peer, ann.hash, meta, ann.kind, ann.size) |
|
|
|
|
t.Errorf("step %d, peer %s, hash %x: announce metadata mismatch: want %v, have %v/%v", i, peer, ann.hash, meta, *ann.kind, *ann.size) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|