Skip to content

fix: keep p2p entropy scores monotonic on attestation sync#2131

Merged
Scottcjn merged 1 commit intoScottcjn:mainfrom
createkr:feat/issue-p2p-entropy-downgrade
Apr 6, 2026
Merged

fix: keep p2p entropy scores monotonic on attestation sync#2131
Scottcjn merged 1 commit intoScottcjn:mainfrom
createkr:feat/issue-p2p-entropy-downgrade

Conversation

@createkr
Copy link
Copy Markdown
Contributor

@createkr createkr commented Apr 6, 2026

fix(p2p): prevent entropy_score downgrade via P2P attestation sync

Problem

_save_attestation_to_db in the P2P gossip layer unconditionally overwrote
entropy_score on conflict (entropy_score = excluded.entropy_score), allowing
any authenticated P2P peer to erase a legitimately-measured high entropy score
by sending a crafted attestation with entropy_score: 0.

entropy_score is used as the primary tiebreaker in anti-double-mining canonical
miner selection (ORDER BY entropy_score DESC). Downgrading it to 0 allows a
spoofed miner ID with even a low score to become canonical, undermining the
double-mining defense.

Fix

Apply MAX() monotonicity protection — same pattern already used for
fingerprint_passed:

entropy_score = MAX(
    COALESCE(miner_attest_recent.entropy_score, 0),
    excluded.entropy_score)

Changes

  • node/rustchain_p2p_gossip.py_save_attestation_to_db: replace
    unconditional entropy_score = excluded.entropy_score with
    MAX(COALESCE(miner_attest_recent.entropy_score, 0), excluded.entropy_score).
    Updated comment to document both protected fields.

  • node/tests/test_p2p_entropy_score_downgrade.py — new test file, 9 tests:

    • test_old_p2p_downgrade_zero_erases_high_entropy — demonstrates bug
    • test_old_p2p_partial_downgrade — demonstrates partial downgrade
    • test_old_behaviour_downgrade_changes_canonical_miner — end-to-end attack
    • test_fixed_p2p_zero_cannot_downgrade — verifies fix
    • test_fixed_p2p_lower_score_cannot_downgrade — verifies fix
    • test_fixed_p2p_higher_score_allowed_to_upgrade — monotonic increase OK
    • test_fixed_p2p_first_attestation_still_works — no regression
    • test_fixed_p2p_null_entropy_treated_as_zero — NULL handling
    • test_fixed_behaviour_canonical_miner_preserved — end-to-end fix verify

Testing

node/tests/test_p2p_entropy_score_downgrade.py: 9 passed
node/tests/test_attestation_overwrite_reward_loss.py: 11 passed (no regression)

Compatibility

No breaking changes. MAX() is monotonic — higher scores from honest peers are
still accepted. No schema changes, no migration needed. Backward compatible with
nodes running older code.

@github-actions github-actions bot added BCOS-L1 Beacon Certified Open Source tier BCOS-L1 (required for non-doc PRs) node Node server related tests Test suite changes size/L PR: 201-500 lines labels Apr 6, 2026
@createkr
Copy link
Copy Markdown
Contributor Author

createkr commented Apr 6, 2026

For bounty payout, please use RTC wallet: RTC1d48d848a5aa5ecf2c5f01aa5fb64837daaf2f35.

@Scottcjn
Copy link
Copy Markdown
Owner

Scottcjn commented Apr 6, 2026

Reviewed. Two-part fix: (1) MAX() on entropy_score in P2P attestation save prevents malicious peers from zeroing out legitimate high-entropy measurements — directly impacts anti-double-mining canonical selection. (2) Cross-references epoch distribution recipients against miner_attest_recent, closing the tautological merkle self-validation flaw. 296-line test with old vs new behavior comparison.

Payment: 75 RTC — P2P entropy monotonicity + epoch validation (High severity)

Merging. Thank you createkr.

@Scottcjn Scottcjn merged commit 1a2597b into Scottcjn:main Apr 6, 2026
8 of 9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

BCOS-L1 Beacon Certified Open Source tier BCOS-L1 (required for non-doc PRs) node Node server related size/L PR: 201-500 lines tests Test suite changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants