Skip to content

Fix #4162: limit concurrent outgoing TransactionListQuery conversations#4164

Draft
reinkrul wants to merge 1 commit intoV5.4from
fix/4162-limit-parallel-transactionlist-queries
Draft

Fix #4162: limit concurrent outgoing TransactionListQuery conversations#4164
reinkrul wants to merge 1 commit intoV5.4from
fix/4162-limit-parallel-transactionlist-queries

Conversation

@reinkrul
Copy link
Copy Markdown
Member

@reinkrul reinkrul commented Apr 9, 2026

Summary

Second mitigation for #4162.

  • When many peers connect at startup, sendTransactionListQuery/sendTransactionRangeQuery is called for each peer that has missing transactions
  • All peers respond simultaneously with TransactionList messages, causing a flood of BBolt writes
  • Concurrent writes starve read operations (e.g. notifier.Run() during startup)

Fix: a token bucket rate-limiter shared by both sendTransactionListQuery and sendTransactionRangeQuery. Queries that find no token available are dropped — the gossip/state-comparison mechanism retries them naturally.

  • The bucket (buffered channel) is pre-filled to capacity at startup, so queries are allowed immediately
  • A goroutine refills one token per tick (1s / rate) up to the bucket capacity
  • Default rate: 2/s (configurable via network.v2.transactionlistqueryrate)
  • Unlike a semaphore, a rate limiter is unaffected by slow or non-responsive peers

Test plan

  • TestProtocol_sendTransactionListQuery/rate_limit_reached_-_query_is_dropped: drains the bucket, verifies the next query is dropped without error and no conversation is left open
  • TestProtocolV2_Pagination: integration test still passes
  • All existing network/... tests pass

🤖 Generated with Claude Code

@qltysh
Copy link
Copy Markdown

qltysh bot commented Apr 9, 2026

Qlty

Coverage Impact

This PR will not change total coverage.

Modified Files with Diff Coverage (2)

RatingFile% DiffUncovered Line #s
Coverage rating: B Coverage rating: B
network/transport/v2/protocol.go97.0%242
Coverage rating: A Coverage rating: A
network/transport/v2/senders.go82.4%139-141
Total92.0%
🤖 Increase coverage with AI coding...

In the `fix/4162-limit-parallel-transactionlist-queries` branch, add test coverage for this new code:

- `network/transport/v2/protocol.go` -- Line 242
- `network/transport/v2/senders.go` -- Line 139-141

🚦 See full report on Qlty Cloud »

🛟 Help
  • Diff Coverage: Coverage for added or modified lines of code (excludes deleted files). Learn more.

  • Total Coverage: Coverage for the whole repository, calculated as the sum of all File Coverage. Learn more.

  • File Coverage: Covered Lines divided by Covered Lines plus Missed Lines. (Excludes non-executable lines including blank lines and comments.)

    • Indirect Changes: Changes to File Coverage for files that were not modified in this PR. Learn more.

…ngeQuery messages

When many peers connect at startup, sendTransactionListQuery/sendTransactionRangeQuery
can be called for many peers simultaneously. Each peer responds with TransactionList
messages that cause BBolt writes, starving read operations (e.g. notifier startup).

Add a token bucket (buffered channel, pre-filled to capacity) that rate-limits both
sendTransactionListQuery and sendTransactionRangeQuery. The bucket is refilled at
the configured rate (default 2/s, configurable via network.v2.transactionlistqueryrate).
Queries that find no token available are dropped; the gossip/state-comparison
mechanism will retry them naturally.

Unlike a semaphore, a rate limiter is unaffected by slow or non-responsive peers.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@reinkrul reinkrul force-pushed the fix/4162-limit-parallel-transactionlist-queries branch from 48c077d to 332ea98 Compare April 9, 2026 12:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant