fix: prevent failed-fingerprint attestations from earning rewards#5560
fix: prevent failed-fingerprint attestations from earning rewards#5560iamdinhthuan wants to merge 6 commits into
Conversation
|
Welcome to RustChain! Thanks for your first pull request. Before we review, please make sure:
Bounty tiers: Micro (1-10 RTC) | Standard (20-50) | Major (75-100) | Critical (100-150) A maintainer will review your PR soon. Thanks for contributing! |
|
Status update after the CI rerun:
python3 -m pytest node/tests/test_attest_missing_fingerprint_reward_bypass.py node/tests/test_settlement_integrity.py node/tests/test_attestation_overwrite_reward_loss.py node/tests/test_rip309_fingerprint_rotation.py -q
python3 -m py_compile node/rustchain_v2_integrated_v2.2.1_rip200.py node/tests/test_attest_missing_fingerprint_reward_bypass.py
git diff --checkObserved locally on the current PR branch: The remaining |
TJCurnutte
left a comment
There was a problem hiding this comment.
Reviewed PR #5560 at head c511c77427e50deacb0acd14329cc241f7681517.
This looks good to me. The patch changes failed-fingerprint enrollment from the previous minimum non-zero unit to FAILED_FINGERPRINT_WEIGHT_UNITS = 0, and applies that in both auto-enroll after /attest/submit and explicit /epoch/enroll paths while preserving the first-enrollment-wins guard.
Validation run:
git diff --check origin/main...HEAD -- node/rustchain_v2_integrated_v2.2.1_rip200.py node/tests/test_attest_missing_fingerprint_reward_bypass.py tests/requirements.txt
uv run --no-project --python /opt/homebrew/bin/python3.11 --with pytest --with flask --with requests --with pynacl --with psutil --with prometheus-client python -B -m py_compile node/rustchain_v2_integrated_v2.2.1_rip200.py node/tests/test_attest_missing_fingerprint_reward_bypass.py
uv run --no-project --python /opt/homebrew/bin/python3.11 --with pytest --with flask --with requests --with pynacl --with psutil --with prometheus-client python -B -m pytest -q -o addopts='' --noconftest node/tests/test_attest_missing_fingerprint_reward_bypass.py
# 1 passed
uv run --no-project --python /opt/homebrew/bin/python3.11 --with pytest --with flask --with requests --with pynacl --with psutil --with prometheus-client python -B -m pytest -q -o addopts='' --noconftest node/tests/test_epoch_weight_fixedpoint.py node/tests/test_attestation_overwrite_reward_loss.py node/tests/test_rip309_fingerprint_rotation.py
# 19 passedThe new regression proves a missing/failed fingerprint attestation is still accepted and recorded with fingerprint_passed=false, but finalizing the epoch leaves the miner at amount_i64 == 0 and balance_rtc == 0.0. I did not find a blocker in the reward-bypass fix.
kekehanshujun
left a comment
There was a problem hiding this comment.
I found a merge-gate issue in the new test coverage. node/tests/test_attest_missing_fingerprint_reward_bypass.py is a newly added Python file without the required SPDX header, so the repository BCOS/SPDX check will reject this PR even though the focused pytest path is useful. Please add the license header and rerun the advertised py_compile/pytest checks. I would also keep the broad tests/requirements.txt additions separate if possible, but the missing header is the blocker here.
|
Update after requested SPDX fix:
This addresses the missing-header merge-gate blocker. |
ZacharyZhang-NY
left a comment
There was a problem hiding this comment.
Blocking zero-weight side effect found at commit 574e682. This PR now stores failed-fingerprint enrollments with weight 0, but vrf_is_selected() still builds all_miners from every epoch_enroll row. In the selection loop, a zero-weight row can satisfy cumulative >= threshold when threshold is 0 and return False before a later positive-weight miner is evaluated. Manual probe: epoch_enroll rows (failed, 0) then (good, 1), slot 144, vrf_is_selected('good', 144) returned False even though good was the only positive-weight miner; vrf_is_selected('failed', 144) also returned False. Please filter all_miners to positive normalized weights before computing total_weight/threshold and before iterating selection. Validation run: diff check passed; py_compile passed; new missing-fingerprint regression passed with 1 passed; the expanded author test group produced 3 passed and 20 Windows SQLite temp-file cleanup failures.
|
Addressed the zero-weight VRF selection blocker in commit What changed:
Verification:
Note: I kept the missing-fingerprint import-heavy test as a separate pytest command from the epoch-weight module because importing the integrated node twice under different module names in one process triggers duplicate Prometheus metric registration; both scoped commands pass independently. |
ZacharyZhang-NY
left a comment
There was a problem hiding this comment.
Follow-up review on current head a6e70ed.
The previous zero-weight selection blocker is resolved in the product code. A manual probe with epoch_enroll rows (failed-fingerprint, 0) followed by (good-miner, 1) now returns:
failed_selected=False
good_selected=True
Requesting changes for the new regression test portability failure on Windows. The focused test added for this exact fix fails after the assertions during TemporaryDirectory cleanup because the SQLite DB file remains locked:
PYTHONPATH=node python -B -m pytest -q node/tests/test_epoch_weight_fixedpoint.py::test_vrf_selection_ignores_zero_weight_enrollments --noconftest --tb=short
PermissionError: [WinError 32] The process cannot access the file because it is being used by another process: ...\vrf_zero_weight.db
1 failed
The module loader already uses TemporaryDirectory(ignore_cleanup_errors=True) for import-time DB cleanup; the added VRF regression should use the same Windows-safe cleanup pattern or otherwise ensure every SQLite handle/background user is released before the temp directory is deleted. That will keep the regression usable for local reviewers on Windows while preserving the fixed zero-weight selection behavior.
Validation run:
git diff --check origin/main...HEAD -- node/rustchain_v2_integrated_v2.2.1_rip200.py node/tests/test_attest_missing_fingerprint_reward_bypass.py node/tests/test_epoch_weight_fixedpoint.py tests/requirements.txt
python -B -m py_compile node/rustchain_v2_integrated_v2.2.1_rip200.py node/tests/test_attest_missing_fingerprint_reward_bypass.py node/tests/test_epoch_weight_fixedpoint.py
PYTHONPATH=node python -B -m pytest -q node/tests/test_attest_missing_fingerprint_reward_bypass.py --noconftest --tb=short
python tools/bcos_spdx_check.py --base-ref origin/main
Result: diff check clean, py_compile clean, missing-fingerprint focused test 1 passed, BCOS SPDX check OK. The broader focused group still hits the known Windows SQLite temp-file cleanup failures in other tests.
|
Addressed the Windows cleanup issue in commit What changed:
Verification on head
|
ZacharyZhang-NY
left a comment
There was a problem hiding this comment.
Follow-up review on current head 462883a.
Approved. The Windows cleanup blocker from my previous review is fixed: the new VRF zero-weight regression now uses TemporaryDirectory(ignore_cleanup_errors=True), matching the existing module import cleanup pattern, and the exact focused test now passes on Windows.
The product behavior is still correct. Failed-fingerprint enrollment uses FAILED_FINGERPRINT_WEIGHT_UNITS = 0, and vrf_is_selected() filters normalized weights <= 0 before building the candidate list, so a failed-fingerprint zero-weight row stays ineligible while the positive-weight miner remains selectable.
Validation run:
git diff --check origin/main...HEAD -- node/rustchain_v2_integrated_v2.2.1_rip200.py node/tests/test_attest_missing_fingerprint_reward_bypass.py node/tests/test_epoch_weight_fixedpoint.py tests/requirements.txt
python -B -m py_compile node/rustchain_v2_integrated_v2.2.1_rip200.py node/tests/test_attest_missing_fingerprint_reward_bypass.py node/tests/test_epoch_weight_fixedpoint.py
python tools/bcos_spdx_check.py --base-ref origin/main
PYTHONPATH=node python -B -m pytest -q node/tests/test_epoch_weight_fixedpoint.py::test_vrf_selection_ignores_zero_weight_enrollments --noconftest --tb=short
PYTHONPATH=node python -B -m pytest -q node/tests/test_attest_missing_fingerprint_reward_bypass.py --noconftest --tb=short
PYTHONPATH=node python -B -m pytest -q node/tests/test_epoch_weight_fixedpoint.py node/tests/test_attestation_overwrite_reward_loss.py node/tests/test_rip309_fingerprint_rotation.py --noconftest --tb=short
Result: diff check clean, py_compile clean, BCOS SPDX check OK, focused VRF regression 1 passed, focused failed-fingerprint bypass test 1 passed. The expanded Windows group still reports 16 PermissionError cleanup failures in unchanged SQLite temp-file tests under test_attestation_overwrite_reward_loss.py and test_rip309_fingerprint_rotation.py; the PR-added regression now clears its Windows cleanup path.
jaxint
left a comment
There was a problem hiding this comment.
LGTM! Great work on this PR. 🚀
Summary
Verification
Safety