Skip to content

test: use single-member in functional tests: feature_mnehf, feature_notifications, p2p_instantsend - #7778

Merged
PastaPastaPasta merged 4 commits into
dashpay:developfrom
knst:test-more-single-node-q
Oct 3, 2026
Merged

PastaPastaPasta merged 4 commits into
dashpay:developfrom
knst:test-more-single-node-q

Conversation

@knst

@knst knst commented Oct 1, 2026 •

Copy link
Copy Markdown
Collaborator

Issue being fixed or feature implemented

The ChainLock and InstantSend Notifications, P2P InstantSend and EHF feature tests only need the locks & ehf to happen, not a multi-member quorum.

What was done?

  • fix: make mine_quorum_single_member usable right after setup
  • fix: stall of single-member quorum due to mempool's sync
  • use a single-member quorum in feature_mnehf
  • use a single-member quorum in feature_notifications
  • use a single-member quorum in p2p_instantsend
  • moved testing of node's connection after restart to feature_llmq_connections

How Has This Been Tested?

CI run with tsan:
https://github.com/dashpay/dash/actions/runs/36907697165/job/110532135383?pr=7778
https://github.com/dashpay/dash/actions/runs/36752482052/job/110043834012

Test develop (s) PR (s)
feature_llmq_connections.py 142 157
feature_mnehf.py 102 74
feature_notifications.py 44 31
p2p_instantsend.py 100 56

Local run:

Test develop (s) PR (s)
feature_llmq_connections.py 80 88
feature_mnehf.py 49 41
feature_notifications.py 29 21
p2p_instantsend.py 81 42
ALL (accumulated) 239 192

Breaking Changes

N/A

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

knst added 4 commits October 2, 2026 01:04
Mine until the masternodes are confirmed for the next DKG first, like mine_quorum does, and sync blocks only.

mine_quorum_single_member mined the next cycle without checking that the masternode is confirmed for it, so the first cycle after setup was skipped and the quorum only appeared one cycle later than the caller expected.

Also sync of mempools could stalls when a masternode's mempool legitimately differs from the miner's.
The EHF signal only needs a recovered signature of any quorum.

Using single-member quorum reduces overhead by adding extra nodes, mining heavier quorums and exchanging recovered sigs messages

The blocks before the `started` check are mined up to the window boundary instead of a fixed count, since the window no longer lines up with the shorter setup.
The ChainLock and InstantSend notifications only need the locks to happen, not a multi-member quorum, and the quorum formation with four masternodes dominated the runtime.
Run it with one masternode and single-member quorums.
The functional test p2p_instantsend.py is about InstantSend on the non-masternode nodes.
Run them with one masternode and single-member quorums.

The InstantSend after a full restart scenario needs sig shares from several restarted members, which a single-member quorum can't exercise, so it moves to feature_llmq_connections.
@knst knst added this to the 24.1 milestone Oct 1, 2026
@chatgpt-codex-connector

Copy link
Copy Markdown

Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits.
Repo admins can enable using credits for code reviews in their settings.

@thepastaclaw

thepastaclaw commented Oct 1, 2026 •

Copy link
Copy Markdown
Collaborator

✅ Final review complete — no blockers (commit e308b31)

@coderabbitai

coderabbitai Bot commented Oct 1, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

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

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: c7ede566-151e-47df-a7eb-e12b0650a4cf

📥 Commits

Reviewing files that changed from the base of the PR and between a31fcf2 and e308b31.

📒 Files selected for processing (5)
  • test/functional/feature_llmq_connections.py
  • test/functional/feature_mnehf.py
  • test/functional/feature_notifications.py
  • test/functional/p2p_instantsend.py
  • test/functional/test_framework/test_framework.py

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 functional tests now use smaller node and masternode setups with single-member quorum mining. The MNEHF test updates quorum selection and its window-boundary check. Post-restart peer verification and InstantSend coverage now run in the LLMQ connections test instead of the P2P InstantSend test.

Priority: ⬇️ Low

Estimated code review effort: 3 (Moderate) | ~25 minutes

Merge Risk: ⚪ Minimal · up to e308b

The quorum setup and relocated restart checks have no established merge-blocking defect. The relay safely accepts already-known transactions; merge after normal checks pass.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 4.55% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 22 functions across 5 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
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.
Title check ✅ Passed The title clearly identifies the main change: using single-member quorums in the listed functional tests. It omits related changes in feature_llmq_connections and the test framework, but it remains co…
Description check ✅ Passed The description directly explains the single-member quorum changes, framework updates, moved restart coverage, and test results. It is clearly related to the changeset.
  • Fix all pre-merge checks with AI
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Autopilot is currently an internal CodeRabbit preview.


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 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

The PR efficiently reduces functional-test quorum overhead, but the MnEHF duplicate-signal case can construct a payload naming one quorum while signing it with another. The signing helper independently selects a quorum from the current chain, so the transaction may fail signature validation before the duplicate-bit behavior is exercised.

🔴 1 blocking

Review provenance

Source: reviewer 1: gemini-3.8-flash-high (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: normal by gpt-6.1-sol (effort low) — This is a cross-cutting functional-test refactor affecting quorum setup, mempool synchronization, and test coverage across five files, but it does not change production consensus, networking, cryptography, funds, or storage behavior.
  • Phase 1 reviewers: gemini-3.8-flash-high — general (completed, effort high); agent phase1-reviewer
  • Phase 1 model: gemini-3.8-flash-high — antigravity quota: weekly 90% left, 5h 45% left
  • Fresh verifier: gpt-6.1-sol — final-verifier; agent sol-verifier
  • Phase 2 reviewers: gpt-6.1-sol — general (completed, effort high); agent phase2-reviewer, gpt-6.1-sol — dash-core-commit-history (completed, effort high); agent phase2-reviewer
🤖 Prompt for all review comments with AI agents
These findings are from an automated code review. Verify each finding against the current code and only fix it if needed.

In `test/functional/feature_mnehf.py`:
- [BLOCKING] test/functional/feature_mnehf.py:225: Sign the duplicate MnEHF transaction with the quorum named in its payload
  This call explicitly forces the payload's `quorumHash` to the original signal's quorum, but `create_mnehf()` still calls `get_recovered_sig(request_id, msgHash)` without passing that quorum. `get_recovered_sig()` independently runs `selectquorum` against the current chain and uses the selected quorum for signing. If selection has changed, the signature is produced by a different quorum than the one encoded in the payload. `CheckMNHFTx` verifies against the payload's quorum, so `send_tx()` can fail with an invalid MnEHF signature instead of testing duplicate-bit rejection. Make the signing helper accept and use the explicitly selected quorum, or otherwise reuse the original quorum's recovered signature.

ehf_tx_duplicate = self.send_tx(self.create_mnehf(28, pubkey))
# Same quorum as the original signal: a quorum member never signs the same request id twice,
# so only an identical payload gets its (already existing) recovered signature
ehf_tx_duplicate = self.send_tx(self.create_mnehf(28, pubkey, quorumHash=format(mnehf_payload.quorumHash, '064x')))

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.

🔴 Blocking: Sign the duplicate MnEHF transaction with the quorum named in its payload

This call explicitly forces the payload's quorumHash to the original signal's quorum, but create_mnehf() still calls get_recovered_sig(request_id, msgHash) without passing that quorum. get_recovered_sig() independently runs selectquorum against the current chain and uses the selected quorum for signing. If selection has changed, the signature is produced by a different quorum than the one encoded in the payload. CheckMNHFTx verifies against the payload's quorum, so send_tx() can fail with an invalid MnEHF signature instead of testing duplicate-bit rejection. Make the signing helper accept and use the explicitly selected quorum, or otherwise reuse the original quorum's recovered signature.

source: gpt-6.1-sol (phase2-reviewer: general)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

The mismatch can't happen: the member has already voted on this request id
with the same msgHash, so quorum sign for the newly selected quorum is
refused ("already voted ... Not voting again", allowReSign=false) and
get_recovered_sig returns the existing recovered signature of the original
quorum, which is the one named in the payload.

That said, the pinned payload was byte-identical to the original signal, so
there is no reason to build and "sign" it again. Changed the duplicate step to
resend the original ehf_tx and dropped the quorumHash parameter from
create_mnehf.

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.

Agreed. Reusing the original ehf_tx avoids attempting a second signature for the same request ID and preserves the original quorum hash and recovered signature, so this resolves the mismatch concern.

Marking this resolved.

@thepastaclaw thepastaclaw added the pastaclaw:changes-requested thepastaclaw's latest review requested changes label Oct 1, 2026

@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.

Re-review after discussion — commit e308b31

Standing review was CHANGES_REQUESTED; this re-review is COMMENT: no blocking findings remain.

🔴 0 blocking | 🟡 0 suggestion(s) | 💬 0 nitpick(s)

No longer blocking:

  • Sign the duplicate MnEHF transaction with the quorum named in its payload

Same commit as the standing review; the inline threads above carry the per-finding outcome. This follow-up exists only to correct the verdict.

Review provenance

Source: conversation lane gpt-6.1-sol (agent: conversation); no reviewer or verifier lanes ran for this follow-up

  • Verdict moved because every blocking finding on this commit was withdrawn, resolved or deferred in the inline discussion; the code was not re-reviewed

@thepastaclaw thepastaclaw added pastaclaw:commented thepastaclaw's latest review was comment-only and removed pastaclaw:changes-requested thepastaclaw's latest review requested changes labels Oct 1, 2026
PastaPastaPasta added a commit to thepastaclaw/review-system that referenced this pull request Oct 3, 2026
…D on the reviewed commit (#38)

On dashpay/dash#7778 the full review's only finding was a blocker the author
argued away. The conversation lane lifted it but posted a COMMENT, which on
GitHub never clears a REQUEST_CHANGES, so a ready PR kept showing a blocking
review. It also labelled an unpushed change FIXED.

- A conversation follow-up now APPROVEs when no blocker and nothing above a
  nitpick is left of the publishing run's final verifier set, something of
  that set was lifted, and the run is one the pipeline would approve on
  (Phase 2 ok, not degraded, fresh audit ok on a later round). If only the
  fresh audit is missing, it posts COMMENT and re-queues the commit once.
- The standing set comes from the verifier's verify2 rows, so findings dedupe
  carried onto other (even resolved) threads still count; open threads from
  earlier heads no longer do.
- Live head and review state are re-read right before posting.
- FIXED is replaced by FIX_PENDING in the conversation lane; it lifts nothing.
- A lifted finding whose thread stays open gets a status line on the bot's
  own root comment (the bot cannot resolve threads without write access);
  dedupe strips it, and a later review that keeps the finding clears it.

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@PastaPastaPasta
PastaPastaPasta merged commit 8819507 into dashpay:develop Oct 3, 2026
55 checks passed
@thepastaclaw thepastaclaw removed the pastaclaw:commented thepastaclaw's latest review was comment-only label Oct 3, 2026
PastaPastaPasta added a commit that referenced this pull request Oct 7, 2026
…hf, feature_notifications, p2p_instantsend

e308b31 test: use a single-member quorum in p2p_instantsend (Konstantin Akimov)
233a89b test: use a single-member quorum in feature_notifications (Konstantin Akimov)
49e09b9 test: use a single-member quorum in feature_mnehf (Konstantin Akimov)
2e6e5bb test: make mine_quorum_single_member usable right after setup (Konstantin Akimov)

Pull request description:

  ## Issue being fixed or feature implemented
  The ChainLock and InstantSend Notifications, P2P InstantSend and EHF feature tests only need the locks & ehf to happen, not a multi-member quorum.

  ## What was done?
   - fix: make mine_quorum_single_member usable right after setup
   - fix: stall of single-member quorum due to mempool's sync
   - use a single-member quorum in feature_mnehf
   - use a single-member quorum in feature_notifications
   - use a single-member quorum in p2p_instantsend
   - moved testing of node's connection after restart to feature_llmq_connections

  ## How Has This Been Tested?

  CI run with tsan:
  https://github.com/dashpay/dash/actions/runs/36907697165/job/110532135383?pr=7778
  https://github.com/dashpay/dash/actions/runs/36752482052/job/110043834012

  | Test                        | develop (s) | PR (s) |
  |-----------------------------|-------------|--------|
  | feature_llmq_connections.py | 142          | 157     |
  | feature_mnehf.py            | 102          | 74     |
  | feature_notifications.py    | 44          | 31     |
  | p2p_instantsend.py          | 100          | 56     |

  Local run:
  | Test                        | develop (s) | PR (s) |
  |-----------------------------|-------------|--------|
  | feature_llmq_connections.py | 80          | 88     |
  | feature_mnehf.py            | 49          | 41     |
  | feature_notifications.py    | 29          | 21     |
  | p2p_instantsend.py          | 81          | 42     |
  | **ALL (accumulated)**       | **239**     | **192** |

  ## Breaking Changes
  N/A

  ## 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: 03de5bb1bbeb525848a5d0079f31e89f2906e1fde0606f5a8af9d30bb959d737bdb98ed0fe74261ceab909488b6b96cc512557aeb150105e1dce909c65f7f9a0
(cherry picked from commit 8819507)
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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants