fix: make faucet drip rate limit atomic#4891
Conversation
ethever
left a comment
There was a problem hiding this comment.
Reviewed the live root faucet.py fix for the TOCTOU rate-limit race. The important property is present: create_drip_atomically() starts a SQLite BEGIN IMMEDIATE transaction before reading both the IP and wallet last-drip rows, and it inserts the new drip before committing. That serializes competing /faucet/drip requests through one write transaction, so a second request observes the first committed drip before it can pass the rate-limit checks.
Validation on PR head 15c8216:
- git diff --check origin/main...HEAD -> passed
- python3 -m py_compile faucet.py tests/test_legacy_faucet_json_validation.py -> passed
- python3 tools/bcos_spdx_check.py --base-ref origin/main -> OK
- uv run --no-project --with pytest --with flask --with flask-cors --with requests python -m pytest tests/test_legacy_faucet_json_validation.py tests/test_faucet.py -q -> 8 passed
Small environment note: the combined pytest command needs requests available because tests/test_faucet.py imports tools/testnet_faucet.py. With requests included, the listed tests pass cleanly.
Non-blocking hardening suggestion: the new concurrency regression uses the same wallet and the default test-client IP for all 8 requests, so either the IP check alone or the wallet check alone would make that specific test pass. I would add two narrower regressions as follow-up coverage: same IP with different wallets should allow only one success, and same wallet with different X-Forwarded-For/REMOTE_ADDR values should also allow only one success. That would lock both promised dimensions independently.
No blocking issues found; approving.
Code Review: Make faucet drip rate limit atomicSummarySame vulnerability as #4887 (TOCTOU race in faucet rate limiting). Different approach from #4889. Comparison with #4889
Positive ✅
Minor note 🔍
Both PRs fix the same bug correctly. #4891 has cleaner code organization. Review quality: Comparative review |
shuibui
left a comment
There was a problem hiding this comment.
Code Review: Security Fix
Good security fix. Atomic rate limiting / fail-closed patterns are correct.
Verdict: Approve.
loganoe
left a comment
There was a problem hiding this comment.
Reviewed the faucet TOCTOU fix. The rate-limit checks and drip insert now run under one SQLite BEGIN IMMEDIATE transaction on the same connection, which closes the gap between can_drip() and record_drip(). The concurrent regression verifies one success and seven rate-limit responses for eight simultaneous requests.
Validation run locally:
PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 PYTHONPATH=. /tmp/rustchain-flask-venv/bin/python -m pytest -q tests/test_legacy_faucet_json_validation.py tests/test_faucet.py/tmp/rustchain-flask-venv/bin/python -m py_compile faucet.py tests/test_legacy_faucet_json_validation.py
shuibui
left a comment
There was a problem hiding this comment.
Code Review: Approve
Good fix.
**Verdict: Approve.
shuibui
left a comment
There was a problem hiding this comment.
Code Review: Approve
Good fix. Addresses the issue correctly.
**Verdict: Approve.
shuibui
left a comment
There was a problem hiding this comment.
Code Review: Approve
Good fix. Addresses the issue correctly.
**Verdict: Approve.
shuibui
left a comment
There was a problem hiding this comment.
Code Review: Approve
Good fix.
**Verdict: Approve.
TJCurnutte
left a comment
There was a problem hiding this comment.
Verified review
Approved for PR #4891 at head 15c8216d82607148e601c766d1a5d82b36f85e08.
I inspected the PR metadata/diff for: fix: make faucet drip rate limit atomic.
Changed scope: faucet.py (+75/-38), tests/test_legacy_faucet_json_validation.py (+28/-0).
Local validation
git diff --check origin/main...HEAD— passpython3 tools/bcos_spdx_check.py --base-ref origin/main— passpython3 -B -m py_compile faucet.py tests/test_legacy_faucet_json_validation.py— passpython3 -B -m pytest tests/test_legacy_faucet_json_validation.py -q— passadded-line secret pattern scan— pass
Review reasoning
- The diff is focused on the stated security/validation/bugfix scope and is small enough to review in this bounty tick.
- Whitespace, SPDX, syntax/static, and added-line secret checks passed for this exact head.
- I did not find a blocker in the changed files or validation output.
Boundary: this review certifies the current diff/head only; payout/merge is not assumed.
himanalot
left a comment
There was a problem hiding this comment.
Reviewed the root faucet.py rate-limit changes and the concurrent regression test. The drip route now performs the IP check, wallet check, and insert under a single SQLite BEGIN IMMEDIATE write transaction, so concurrent requests serialize before the insert and losers observe the recorded drip. Existing read helpers are preserved through cursor/timestamp helper extraction.
I do not see a blocking issue in this patch. Approved.
PR Review — Standard Quality ✓PR: #4891 — Fix: make faucet drip rate limit atomic What I reviewed
Observations
LGTM. Bounty: #2782 |
Summary
faucet.py/faucet/dripTOCTOU rate-limit race from Bug: Faucet rate limiting TOCTOU race condition enables draining #4887.BEGIN IMMEDIATEwrite transaction.Validation
python -m pytest tests\test_legacy_faucet_json_validation.py -q-> 4 passedpython -m pytest tests\test_legacy_faucet_json_validation.py tests\test_faucet.py -q-> 8 passedpython -m py_compile faucet.py tests\test_legacy_faucet_json_validation.py-> passedgit diff --check-> passedpython tools\bcos_spdx_check.py --base-ref origin/main-> OKNo live faucet, production wallet, or destructive testing was performed.
Wallet: RTC253255d034065a839cd421811ec589ae5b694ffc
Fixes #4887