Skip to content

refactor(net): merge duplicate peer discouragement query - #7584

Merged
PastaPastaPasta merged 1 commit into
dashpay:developfrom
PastaPastaPasta:t3code/clarify-disconnected-ban-state
Oct 5, 2026
Merged

PastaPastaPasta merged 1 commit into
dashpay:developfrom
PastaPastaPasta:t3code/clarify-disconnected-ban-state

Conversation

@PastaPastaPasta

@PastaPastaPasta PastaPastaPasta commented Aug 12, 2026 •

Copy link
Copy Markdown
Member

Issue being fixed or feature implemented

PeerManager exposed the same check twice: IsBanned(NodeId) on PeerManager and PeerIsBanned(NodeId) on PeerManagerInternal, which only forwarded to the former. Neither name describes what the check does. It does not consult BanMan; it only reports whether the live Peer has crossed the discouragement threshold and SendMessages() has not yet consumed m_should_discourage, and it returns false for peers that are unknown or already finalized. Both declarations also required cs_main, which the lookup never uses (it only takes m_peer_mutex and the peer's m_misbehavior_mutex).

This PR originally also changed LLMQ cleanup to drop pending recovered sigs and sig-share state for peers that disconnected. That part is superseded by #7563, which purges pending recovered sigs eagerly in NetSigning::BanNode and deliberately keeps queued recovered sigs from peers that disconnect without misbehaving. Sig-share state for vanished peers is already cleaned by CSigSharesManager::Cleanup(). The behavior change has been dropped; this PR is now a behavior-neutral refactor.

What was done?

  • Replaced PeerManager::IsBanned() and PeerManagerInternal::PeerIsBanned() with a single PeerManagerInternal::PeerShouldBeDiscouraged(), documented with its actual semantics.
  • Removed the cs_main requirement from the annotation; it keeps !m_peer_mutex.
  • Renamed NetSigning::RemoveBannedNodeStates() to RemoveDiscouragedNodeStates().
  • Kept the existing semantics, including returning false for missing peers.
  • Added peer_discouragement assertions for the flag before and after crossing the threshold, after SendMessages() consumes it, below the threshold, and after FinalizeNode().

How Has This Been Tested?

macOS arm64, depends toolchain, Apple clang with -Wthread-safety, --enable-werror --disable-bench --without-gui:

  • make -j6 (clean build, no new warnings)
  • ./src/test/test_dash --run_test=denialofservice_tests, net_tests, llmq_utils_tests, llmq_qgetdata_tests, llmq_invalid_type_tests, llmq_chainlock_tests
  • test/functional/test_runner.py feature_llmq_signing.py "feature_llmq_signing.py --spork21" p2p_disconnect_ban.py
  • test/lint/lint-whitespace.py, lint-includes.py, lint-circular-dependencies.py, contrib/devtools/clang-format-diff.py on the diff
  • test/lint/all-lint.py: only lint-cppcheck-dash.py failed, on src/governance/object.cpp:854 (untouched by this PR, identical to develop); codespell, vulture and flake8 were skipped because they are not installed locally.

Breaking Changes

None. The renamed interface is internal to the networking and LLMQ implementation.

Checklist:

  • I have performed a self-review of my own code
  • I have made corresponding changes to the documentation
  • I have assigned this pull request to a milestone (for repository code-owners and collaborators only)

🤖 Generated with Claude Code

@coderabbitai

coderabbitai Bot commented Aug 12, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

🧰 Additional context used
📚 Code guidelines (1)
doc/developer-notes.md — auto-discovered

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 4dcb747a-e506-4fd6-8f98-22492bf2f2ff
📥 Commits

Reviewing files that changed from the base of the PR and between 315f683 and fed2f49.

📒 Files selected for processing (5)
  • src/llmq/net_signing.cpp
  • src/llmq/net_signing.h
  • src/net_processing.cpp
  • src/net_processing.h
  • src/test/denialofservice_tests.cpp

Included review availability: This review used your included allowance. Your plan provides up to 4 included reviews per hour; 3 remain after this review.


Walkthrough

The peer manager replaces banned-state queries with PeerShouldBeDiscouraged. The query returns false for an absent peer and checks the discouragement flag under the misbehavior mutex. NetSigning uses this query to remove share-manager state for discouraged peers. Tests check the state at and below the threshold, after SendMessages, and during node finalization.

Priority: ⬇️ Low

Estimated code review effort: 2 (Simple) | ~10 minutes

Merge Risk: ⚪ Minimal · up to fed2f

This refactor merges two peer discouragement queries and renames a cleanup helper. No concrete defect was found, so the change looks safe to merge after the usual checks.

Security Architecture Review

Security architecture risk: ⚪ Minimal · up to fed2f

The refactor preserves peer selection, discouragement timing, and signing-state cleanup. The reviewed changes introduce no new remote capability or weakened enforcement control.

Retained concerns
No architecture-level concerns identified.

Security review details

Security Blast Radius

  • inferred — The reviewed exposure remains peer-scoring and signing bookkeeping within the node. Cleanup selects NodeId-keyed state; address-wide discouragement remains a separate enforcement outcome. The renamed query adds no remote entrypoint or broader cleanup authority.

Trust Boundaries and Controls

  • observed — Misbehavior scoring sets the pending flag only when the score crosses the discouragement threshold. The query reads that peer-owned flag under the same misbehavior mutex; its caller cannot supply a replacement policy or arbitrary removal predicate through the network.

Resilience and Maintainability Implications

  • observed — Flag observation and share-state deletion are not a cross-component transaction: concurrent flag consumption can defer predicate-based deletion. That timing is inherited. The existing cleanup worker repeats cleanup, and the share manager separately removes states for peers absent from CConnman, including their requested-share keys. This PR introduces no new durable transition or recovery owner.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 8.33% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 12 functions across 5 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: merging duplicate peer-discouragement queries.
Description check ✅ Passed The description explains the query refactor, related renaming, added tests, and reported validation.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
  • Fix all pre-merge checks with AI
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@thepastaclaw

thepastaclaw commented Aug 12, 2026 •

Copy link
Copy Markdown
Collaborator

✅ Final review complete — no blockers (commit fed2f49) · triage: low

@PastaPastaPasta

Copy link
Copy Markdown
Member Author

@coderabbitai review\n\n---\n🤖 Posted autonomously by Codex on behalf of pasta.

@coderabbitai

coderabbitai Bot commented Aug 13, 2026 •

Copy link
Copy Markdown

@PastaPastaPasta I will review pull request #7584.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@PastaPastaPasta
PastaPastaPasta marked this pull request as draft August 15, 2026 18:11
@github-actions

github-actions Bot commented Sep 8, 2026

Copy link
Copy Markdown

This pull request has conflicts, please rebase.

PeerManager exposed the same check twice: IsBanned() on PeerManager and
PeerIsBanned() on PeerManagerInternal, the latter only forwarding to the
former. Neither name described the check: it does not consult BanMan,
it only reports whether the live Peer has crossed the discouragement
threshold and SendMessages() has not consumed m_should_discourage yet,
and it returns false for peers that are unknown or already finalized.
Both declarations also required cs_main, which the lookup never uses;
it only takes m_peer_mutex and the peer's m_misbehavior_mutex.

Replace both with a single PeerManagerInternal::PeerShouldBeDiscouraged()
without the cs_main requirement, and rename NetSigning's
RemoveBannedNodeStates() to RemoveDiscouragedNodeStates() to match.
Behavior is unchanged, including returning false for missing peers.

Add peer_discouragement assertions covering the flag before and after
crossing the threshold, after SendMessages() consumes it, below the
threshold, and after FinalizeNode().

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@PastaPastaPasta
PastaPastaPasta force-pushed the t3code/clarify-disconnected-ban-state branch from 315f683 to fed2f49 Compare October 4, 2026 04:00
@PastaPastaPasta PastaPastaPasta changed the title fix(net): clean up disconnected peer state refactor(net): merge duplicate peer discouragement query Oct 4, 2026
@PastaPastaPasta

Copy link
Copy Markdown
Member Author

Reshaped this PR after rebasing onto develop (8819507); new head fed2f49.

The fix part is superseded by #7563, which purges pending recovered sigs in NetSigning::BanNode. That PR deliberately keeps queued recovered sigs from peers that disconnect without misbehaving, because those sigs may be the only copy we receive. The old version of this PR deleted them on disconnect, so that change has been dropped. Treating a missing peer as "disconnected" in the sig-share sweep would also have changed behavior (it would duplicate what CSigSharesManager::Cleanup() already does on its own schedule), so that is dropped too.

What remains is a behavior-neutral refactor(net): single commit:

  • IsBanned() and PeerIsBanned() are merged into PeerManagerInternal::PeerShouldBeDiscouraged(), which still returns false for unknown peers.
  • The unused cs_main lock requirement is removed.
  • RemoveBannedNodeStates() is renamed to RemoveDiscouragedNodeStates().
  • peer_discouragement assertions are added.

The build is clean with clang thread-safety analysis and -Werror. denialofservice_tests, the net/llmq unit suites, feature_llmq_signing.py (both variants) and p2p_disconnect_ban.py pass. The title and description have been updated to match.


🤖 Posted autonomously by Codex on behalf of pasta.

@PastaPastaPasta
PastaPastaPasta marked this pull request as ready for review October 4, 2026 04:01

@thepastaclaw thepastaclaw left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Final validation — Phase 1 + Phase 2

Verified the supplied reviewer assessments against the complete diff and relevant callers at fed2f49. The consolidated query preserves the discouragement flag and unknown-peer behavior, requires no cs_main-protected state, and leaves LLMQ cleanup semantics unchanged; no actionable findings were identified. This was a static review only: the supplied CI snapshot reports successful lint, formatting, and Linux64/aarch64 source builds, while tests and several other builds remain queued or in progress.

Review provenance

Source: reviewer 1: glm-5.3-flash (agent: phase1-reviewer, role: general); reviewer 2: gpt-6.1-sol (agent: phase2-reviewer, role: general); reviewer 3: gpt-6.1-sol (agent: phase2-reviewer, role: dash-core-commit-history); final verifier: gpt-6.1-sol (agent: sol-verifier, role: final-verifier)

  • Triage: low by gpt-6.1-sol (effort low) — This small, behavior-neutral refactor consolidates a peer-state query, removes an unused locking requirement, updates LLMQ callers, and adds focused assertions whose correctness is straightforward to confirm.
  • Phase 1 reviewers: glm-5.3-flash — general (completed, effort high); agent phase1-reviewer
  • Phase 1 model: glm-5.3-flash — zai quota: 5h 99% left, weekly 69% left; passed over gemini-3.8-flash-high (antigravity below 15% reserve: weekly 15% left, 5h 100% left)
  • Fresh verifier: gpt-6.1-sol — final-verifier; agent sol-verifier
  • Phase 2 reviewers: gpt-6.1-sol — general (completed, effort medium); agent phase2-reviewer, gpt-6.1-sol — dash-core-commit-history (completed, effort medium); agent phase2-reviewer

@thepastaclaw thepastaclaw added the pastaclaw:approved thepastaclaw's latest review approved this PR label Oct 4, 2026

@PastaPastaPasta PastaPastaPasta left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

approved

@PastaPastaPasta
PastaPastaPasta merged commit bfa517b into dashpay:develop Oct 5, 2026
50 checks passed
@thepastaclaw thepastaclaw removed the pastaclaw:approved thepastaclaw's latest review approved this PR label Oct 5, 2026
PastaPastaPasta added a commit that referenced this pull request Oct 5, 2026
…lang-analyzer null dereference)

92365cc fix(qt): reserve the coin vector in the coin control test helper (Konstantin Akimov)
9c6ccd0 fix(qt): clear ItemIsEnabled through QFlags::setFlag in coin control test (Konstantin Akimov)
7daa67d fix(test): assert the chain tip before dereferencing it in reward reallocation tests (Konstantin Akimov)

Pull request description:

  ## Issue being fixed or feature implemented

  `develop` CI is red since the merge of #7260 (aec4994). Both `linux64_asan-build` and `linux64_multiprocess-build` pass on the merge of #7790 (2ca083a) and on the head of #7584 (fed2f49), and both are red on the head of #7260 (3034e98) and on its merge commit. #7260 was merged with those two jobs failing.

  1. `linux64_asan` fails in `test_dash-qt`: `CoinControlTreeWidgetTests::disabledCoinsSkipped()` triggers an UBSan implicit-integer-sign-change inside `QFlags::operator&`. The test, added by #7260 in 3034e98, clears a flag with `flags() & ~Qt::ItemIsEnabled`. `~Qt::ItemIsEnabled` is evaluated as a plain `int` (-33) and QFlags converts it to its unsigned storage type.

  2. `linux64_multiprocess` reports a clang static analyzer diagnostic in `test/block_reward_reallocation_tests.cpp:209`: `tip->nBits` dereferences a pointer the analyzer considers possibly null, because `GetMnRewardEraAfter()` (via `DeploymentActiveAfter()`) accepts a null `pindexPrev`. The pattern dates back to #7339 (7f2058e) and the file was last touched by #7536 in August, so this diagnostic is not caused by #7260's diff. The analyzer runs in that job because the tidy step operates on the `make distdir` copy of the tree, which does not include `src/.clang-tidy`, so clang-tidy falls back to its default `clang-analyzer-*` checks. I could not read the job log (needs credentials) to confirm that this diagnostic alone fails the step, so this part is fixed on the evidence of the pasted output.

  ## What was done?

  - `src/qt/test/coincontroltreewidgettests.cpp`: clear the flag with `flags().setFlag(Qt::ItemIsEnabled, false)`, which stays inside the `QFlags` type.
  - `src/test/block_reward_reallocation_tests.cpp`: wrap every chain-tip lookup that feeds `GetMnRewardEraAfter()` in `Assert()` and include `util/check.h`. The chain is never empty at those points; the assertion documents it for the analyzer and the reader. This is test code, so a fatal check is acceptable.

  ## How Has This Been Tested?

  see CI

  ## Breaking Changes

  None.

  ## Checklist:
  - [x] I have performed a self-review of my own code
  - [ ] I have made corresponding changes to the documentation
  - [x] I have assigned this pull request to a milestone

Top commit has no ACKs.

Tree-SHA512: cd7d524e35ec6039f5b72ae05cfd498c83c00d842a617bf412de87a5759eb7fbd74f5b96698e9a3aab27174d8ac8942f5624bbe49a1028c4d9d0fbc3cfb3dd33
PastaPastaPasta added a commit that referenced this pull request Oct 7, 2026
fbe6526 Merge #7807: feat(consensus): hold EvoNode shares and multiple payouts behind a new evo_shares deployment (pasta)
57fd2d9 Merge #7776: fix: keep a pending ProUpServTx across a registrar update that keeps the operator key (pasta)
ca69801 Merge #7803: fix: return non-zero amount of accounts after sethdseed (pasta)
57a8f07 Merge #7796: backport: bitcoin#26720 (remaining), partial bitcoin#29523: weight-check the knapsack exact-match selection (pasta)
4eb82f6 Merge #7786: fix(net): keep a dedicated onion listener when -bind is given and correct the bind release note (pasta)
70626a0 Merge #7793: backport: partial bitcoin#28868 (wallet: reload wallet if migration exited early, keep mixed watchonly txs) (pasta)
250a3cd Merge #7790: fix: guard cached governance object flags with the object lock (pasta)
700c195 Merge #7787: fix: only sign EHF signals inside the deployment's start/timeout window (pasta)
a3b0f3c Merge #7785: fix: restore the txindex requirement when governance validation is enabled (pasta)
2d1735d Merge #7794: fix(wallet): floor the denomination gap threshold so rebalancing cannot oscillate (pasta)
d9f6592 Merge #7783: fix: stop fish completion from re-running the typed dash-cli command (pasta)
89d44c8 Merge #7795: backport: bitcoin#34272, partial bitcoin#31650 (pass PSBT by const reference in PSBTInputSignedAndVerified) (pasta)
a1d7411 Merge #7779: fix!: report legacy evonode Platform addresses when listdiff changes its address (pasta)
73f6ea2 Merge #7789: fix(qt): report malformed lang/font settings instead of aborting at startup (pasta)
40de493 Merge #7781: fix(rpc): use a consistent tip height in quorum dkgstatus (pasta)
7d1a90d Merge #7791: fix(net): request object votes from nPeersPerHashMax peers (pasta)
51b145c Merge #7778: test: use single-member in functional tests: feature_mnehf, feature_notifications, p2p_instantsend (pasta)

Pull request description:

  ## Issue being fixed or feature implemented

  Backports for v24.0.0-rc.3. `v24.0.x` was cut at the v24.0.0-rc.2 tag (1e239d4), and develop has since moved to 24.1.0 (#7775), so rc.3 is built from this branch instead of being tagged on develop like rc.1 and rc.2.

  ## What was done?

  Cherry-picked (`git cherry-pick -m1 -x`) every develop merge since rc.2 that carries `backport-candidate-24.0.x`, plus #7778, which #7807's test needs. They are in develop merge order:

  - #7778 test: use single-member in functional tests: feature_mnehf, feature_notifications, p2p_instantsend (test-only. Needed because #7807's `feature_evo_shares_activation.py` depends on its `mine_quorum_single_member()` fix and fails without it.)
  - #7791 fix(net): request object votes from nPeersPerHashMax peers
  - #7781 fix(rpc): use a consistent tip height in quorum dkgstatus
  - #7789 fix(qt): report malformed lang/font settings instead of aborting at startup
  - #7779 fix!: report legacy evonode Platform addresses when listdiff changes its address
  - #7795 backport: bitcoin#34272, partial bitcoin#31650 (pass PSBT by const reference in PSBTInputSignedAndVerified)
  - #7783 fix: stop fish completion from re-running the typed dash-cli command
  - #7794 fix(wallet): floor the denomination gap threshold so rebalancing cannot oscillate
  - #7785 fix: restore the txindex requirement when governance validation is enabled
  - #7787 fix: only sign EHF signals inside the deployment's start/timeout window
  - #7790 fix: guard cached governance object flags with the object lock
  - #7793 backport: partial bitcoin#28868 (wallet: reload wallet if migration exited early, keep mixed watchonly txs)
  - #7786 fix(net): keep a dedicated onion listener when -bind is given and correct the bind release note. Includes partial bitcoin#36170 (5f40d56). Upstream's dedicated-onion-bind changes to `feature_torcontrol.py` and `p2p_private_broadcast.py` are not included, because those tests depend on upstream commits (5693833, e74d54e) that Dash does not have.
  - #7796 backport: bitcoin#26720 (remaining), partial bitcoin#29523: weight-check the knapsack exact-match selection
  - #7803 fix: return non-zero amount of accounts after sethdseed
  - #7776 fix: keep a pending ProUpServTx across a registrar update that keeps the operator key
  - #7807 feat(consensus): hold EvoNode shares and multiple payouts behind a new evo_shares deployment

  One pick needed conflict resolution, in a test only, described in its commit message: #7793, `test/functional/wallet_migration.py`. `test_conflict_txs()` comes from bitcoin#28542 (#7762), which is not on this branch, so it is left out. The C++ part of #7793 is identical to develop.

  Merged since rc.2 but intentionally not included: #7775 (24.1 version bump), #7260 and #7804 (new Qt feature and its CI fix), #7584 (refactor), routine upstream backports #7257, #7759, #7762, #7768, #7788, #7801, and test/CI-only changes #7777 and #7797.

  No version change is needed. `configure.ac` is already 24.0.0 with `CLIENT_VERSION_IS_RELEASE` false, so the build takes its version string from the `v24.0.0-rc.3` tag, as it did for rc.2.

  ## How Has This Been Tested?

  Built on macOS arm64 against depends with `--enable-debug --enable-werror` (dashd, dash-qt, tests).

  - `make check`: all unit test suites pass, including `test_dash-qt`.
  - Functional tests, all passing: `feature_evo_shares_activation.py`, `feature_masternode_shares.py`, `feature_mnehf.py`, `feature_governance.py --descriptors`, `feature_governance_objects.py`, `feature_governance_txindex_devnet.py`, `feature_proxy.py`, `feature_notifications.py`, `feature_llmq_connections.py`, `feature_llmq_chainlocks_automatic.py`, `feature_llmq_singlenode.py`, `p2p_instantsend.py`, `rpc_blockchain.py` (v1 and v2 transport), `rpc_netinfo.py`, `rpc_quorum.py`, `rpc_verifychainlock.py`, `wallet_hd.py` (legacy and descriptors), `wallet_migration.py`.
  - `feature_bind_extra.py` (from #7786) only runs on Linux and was skipped locally, so CI covers it.

  Every touched file was diffed against develop. The remaining differences come only from develop PRs that are not part of this backport.

  ## Breaking Changes

  Carried over from the picked PRs:

  - #7807: consensus change behind the new `evo_shares` deployment (bit 14). Mainnet and testnet are unaffected until it activates. Devnets with `v24` already active and an EvoNode carrying several owner payouts need to check or reset. New RPC `protx shared_register_prepare_evo`.
  - #7785: outside regtest, a node with `-txindex=0` and without `-disablegovernance` refuses to start again, as before v23.1.0.
  - #7786: carries a partial bitcoin#36170. A node started with `-bind` but no specific `-bind=<addr:port>=onion` now refuses to start while `-listenonion` is enabled. That is the default when listening, even without Tor configured. A wildcard onion bind is also refused. Such nodes need `-bind=127.0.0.1:<port>=onion` or `-listenonion=0`. Nodes without `-bind`, including those using only `-whitebind`, keep the default `127.0.0.1:9996` (`19996` testnet) onion target. See `doc/release-notes-7300.md`.
  - #7779: `protx listdiff` now includes `platform_p2p` and `platform_https` for a legacy-address evonode whose core P2P address changes.

  ## Checklist:
  - [x] I have performed a self-review of my own code
  - [ ] I have made corresponding changes to the documentation
  - [ ] I have assigned this pull request to a milestone

  🤖 Generated with [Claude Code](https://claude.com/claude-code)

Top commit has no ACKs.

Tree-SHA512: 8cb01bdb0234f31b5dd2c105b69673de148922991a7523627395c0e0ccfa22b94be5ffbecc842398d443bc90fd9baf2eee6a9cf6fcdbbd1626eb00b93726a55a
@UdjinM6 UdjinM6 added this to the 24 milestone Oct 13, 2026
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.

3 participants