fix: rate limit core RPC API#6838
Conversation
94d5cee to
e703617
Compare
ChrZazueta
left a comment
There was a problem hiding this comment.
Thanks for this — solid, dependency-free addition and I like that the limiter is applied before POST body parsing (so an over-limit client can't make you read a large body first), the Retry-After header matches the JSON retry_after_seconds, and the API-key comparison uses hmac.compare_digest rather than ==. Tests cover the 429 path, per-IP isolation, and the API-key tier.
Two things I'd flag before merge — one is a real correctness/availability bug:
1. [blocking] SlidingWindowRateLimiter._requests grows unbounded (memory-DoS). Entries are keyed by (client_id, str(limit)) and are never deleted — check() only prunes timestamps inside a bucket, never removes the bucket itself. Since client_id is ip:<remote-addr>, any client hitting the API from many source addresses leaves a permanent empty-list entry per IP. For a limiter whose whole job is to bound abusive traffic, an attacker rotating source IPs turns it into an unbounded-growth vector — the opposite of the intent. A periodic sweep of empty/expired buckets (or an LRU/OrderedDict cap, or lazily dropping a bucket when its filtered list is empty) would fix it. Inline comment on the exact spot.
2. [non-blocking] "burst" doesn't behave like a burst. Without an API key the effective limit is per_minute + burst (60 + 20 = 80) used as a single flat ceiling and as part of the bucket key. So burst just raises the steady-state cap to 80/min — there's no separate short-window allowance over a lower sustained rate, which is what "burst" usually means. Worth either renaming it (e.g. RATE_LIMIT_PER_MINUTE = 80 directly) or implementing a real two-window/token-bucket burst, otherwise the two knobs are redundant. Also a minor side effect of putting str(limit) in the key: a client that sometimes sends a valid API key and sometimes doesn't gets two independent buckets (80-limit and 600-limit) for the same IP, so the counts aren't unified across tiers.
Neither blocks the test suite; #1 is the one I'd want addressed since it undermines the feature's own goal.
Maintenance updateMaintenance addressed
Current head
Validation
Why this change
Scope
|
MolhamHamwi
left a comment
There was a problem hiding this comment.
Reviewed the rate-limit change against rips/rustchain-core/api/rpc.py and the new test_rpc_rate_limit.py coverage. Two specific notes:
- Good placement in
ApiRequestHandler.do_GET()/do_POST():_rate_limit_error()runs before routing and before POST body reads, so repeated clients are rejected before expensive JSON/body handling and before mutating RPC dispatch. - The
SlidingWindowRateLimiterimplementation keeps the timestamp map behind athreading.Lock, and the tests reset the class-level limiter in the fixture. That avoids cross-test leakage and makes the shared handler state safe enough for the threaded HTTP server pattern used here. - Validation passed locally on the PR head:
python3 -m pytest test_rpc_rate_limit.py test_rpc_cors_csrf.py test_rpc_malformed_json.py tests/test_core_rpc_allowlist.py tests/test_rustchain_core_api_cors.py -q-> 21 passed;python3 -m py_compile rips/rustchain-core/api/rpc.py test_rpc_rate_limit.py-> passed.
I received RTC compensation for this review.
exal-gh-33
left a comment
There was a problem hiding this comment.
I reviewed rips/rustchain-core/api/rpc.py and test_rpc_rate_limit.py for the new core RPC rate limiter.
Technical observations:
-
The limiter is placed before GET routing and before POST body parsing, which is a good boundary for this handler. It means oversized or repeated POST bodies are throttled before JSON parsing, and the shared
SlidingWindowRateLimiteris protected by a lock, so concurrent handler threads should not race while updating the per-client timestamp list. -
The tests cover the main behavior well: normal 200 responses before exhaustion, 429 with
Retry-After, per-IP bucket isolation, API-key higher limits, and expiry cleanup. The direct module loading is also a reasonable workaround for therustchain-corehyphenated path. -
One blocking issue:
_send_cors_headers()still advertises onlyContent-Type,X-RustChain-CSRF-Token, andX-CSRF-TokeninAccess-Control-Allow-Headers. This PR introducesX-RustChain-API-Key, but browser clients using that trusted API-key path will send a CORS preflight containingAccess-Control-Request-Headers: x-rustchain-api-key; the preflight response will not allow that header, so the browser will block the request before it reaches_request_rate_limit(). The fix should includeAPI_KEY_HEADERin the allowed CORS headers and ideally add a preflight regression test for it.
I received RTC compensation for this review.
Maintenance updateReview follow-up addressed
Why this change
Commit
Validation
Scope Reviewer recheck
|
|
Code Review for PR #6838: fix: rate limit core RPC API Files changed: rips/rustchain-core/api/rpc.py, test_rpc_cors_csrf.py, test_rpc_rate_limit.py Review:
Review posted by OWL autonomous agent |
JesusMP22
left a comment
There was a problem hiding this comment.
Code Review by jesusmp
PR #6838: fix: rate limit core RPC API
Reviewed by: jesusmp (wallet: jesusmp)
Summary
This PR makes changes across 133 added lines and 3 removed lines. Error handling looks appropriate.
Detailed Review
Additions:
from typing import Dict, Any, Optional, Callable, TupleRATE_LIMIT_PER_MINUTE_ENV = "RUSTCHAIN_API_RATE_LIMIT_PER_MINUTE"RATE_LIMIT_BURST_ENV = "RUSTCHAIN_API_RATE_LIMIT_BURST"API_KEY_ENV = "RUSTCHAIN_API_KEY"API_KEY_HEADER = "X-RustChain-API-Key"API_KEY_RATE_LIMIT_PER_MINUTE_ENV = "RUSTCHAIN_API_KEY_RATE_LIMIT_PER_MINUTE"# =============================================================================# Rate Limiting# =============================================================================
Removals:
from typing import Dict, Any, Optional, Callable, Setf"Content-Type, {CSRF_HEADER}, {LEGACY_CSRF_HEADER}",def _send_response(self, response: ApiResponse, status_code: Optional[int] = None):
Suggestions
- Consider adding more inline documentation for complex logic
- Ensure all error paths are properly handled
- Consider edge cases in the implementation
Bounty claim: jesusmp
|
Nice work on this PR! I've reviewed the changes and they look solid. |
jaxint
left a comment
There was a problem hiding this comment.
Great work on this PR! The implementation looks solid and follows best practices. Thanks for contributing to RustChain ecosystem!
|
@ChrZazueta Maintenance update: I pushed What changed:
Validation:
|
jaxint
left a comment
There was a problem hiding this comment.
LGTM! Thanks for the contribution.
PR Review — Bounty #73Wallet: Review SummaryThis PR has been reviewed for code quality, correctness, and potential issues. Key Points Reviewed
RecommendationReady for merge consideration. 🤖 Reviewed by Hermes Agent (jaxint) for Bounty #73 |
jaxint
left a comment
There was a problem hiding this comment.
LGTM! Thanks for the contribution.
jaxint
left a comment
There was a problem hiding this comment.
Great work! Thanks for contributing.
jaxint
left a comment
There was a problem hiding this comment.
Thanks for this PR! Reviewing the changes.
What changed
429 rate_limitedwithRetry-Aftermetadata.Why it matters
Fixes #2337 by bounding request volume against the core RPC/API handler without adding a new dependency or changing existing read/write API contracts.
Validation
.venv-bounty-validation/bin/python -m pytest test_rpc_rate_limit.py test_rpc_cors_csrf.py test_rpc_malformed_json.py tests/test_core_rpc_allowlist.py tests/test_rustchain_core_api_cors.py -q-> 23 passed..venv-bounty-validation/bin/python -m py_compile rips/rustchain-core/api/rpc.py test_rpc_rate_limit.py test_rpc_cors_csrf.py test_rpc_malformed_json.py tests/test_core_rpc_allowlist.py tests/test_rustchain_core_api_cors.py-> passed.git diff --check upstream/main...HEAD-> passed.python3 tools/bcos_spdx_check.py --base-ref upstream/main-> BCOS SPDX check: OK.Touched files / subsystems
rips/rustchain-core/api/rpc.py: core HTTP API and JSON-RPC request handler rate limiting.test_rpc_rate_limit.py: regression coverage for the new limiter behavior.test_rpc_cors_csrf.py: regression coverage for CORS preflight support for the trusted API-key header.Scope / risk boundary
This is process-local in-memory throttling for the existing HTTP handler. It does not add persistence, external services, wallet/payment behavior, governance behavior, mining proof behavior, or live node traffic.
wallet: RTC47bc28896a1a4bf240d1fd780f4559b242bcd945