Skip to content

refactor: move CDSNotificationInterface into NodeContext - #7546

Merged
PastaPastaPasta merged 2 commits into
dashpay:developfrom
PastaPastaPasta:refactor/move-ds-notification-interface-into-nodecontext
Aug 6, 2026
Merged

refactor: move CDSNotificationInterface into NodeContext#7546
PastaPastaPasta merged 2 commits into
dashpay:developfrom
PastaPastaPasta:refactor/move-ds-notification-interface-into-nodecontext

Conversation

@PastaPastaPasta

Copy link
Copy Markdown
Member

Issue being fixed or feature implemented

Moves CDSNotificationInterface from a raw global (g_ds_notification_interface) into NodeContext (node.ds_notification_interface).

The global g_ds_notification_interface was previously constructed in init.cpp and held raw pointer references to various node services. Moving it into NodeContext aligns its lifecycle with other validation interface subscribers (such as cj_walletman and active_ctx).

What was done?

  1. Pass CDeterministicMNManager by reference to CDSNotificationInterface:

    • Changed the constructor parameter from const std::unique_ptr<CDeterministicMNManager>& to CDeterministicMNManager&.
    • Removed the single-use #include <util/check.h> header in src/dsnotificationinterface.cpp after replacing Assert(m_dmnman) with m_dmnman.UpdatedBlockTip(...).
    • Removed the stale // todo: note in src/init.cpp.
  2. Move CDSNotificationInterface into NodeContext:

    • Added ds_notification_interface (std::unique_ptr<CDSNotificationInterface>) to NodeContext in src/node/context.h. Placed it after all referenced managers to ensure correct C++ reverse-destruction order.
    • Included <dsnotificationinterface.h> in src/node/context.cpp.
    • Removed global g_ds_notification_interface extern declaration and definition.
    • Updated all call sites in src/init.cpp to use node.ds_notification_interface.

How Has This Been Tested?

  • Unit tests (./src/test/test_dash --run_test=getarg_tests)
  • Functional tests: feature_dip3_deterministicmns.py and feature_governance.py
  • Static linters: test/lint/all-lint.py

Breaking Changes

None.

Checklist:

  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have added or updated relevant unit/integration/functional/e2e tests
  • I have made corresponding changes to the documentation
  • I have assigned this pull request to a milestone

This pull request was created by Codex.

@thepastaclaw

thepastaclaw commented Aug 5, 2026

Copy link
Copy Markdown

✅ Final review complete — no blockers (commit d1b4f75)

@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 9669d679-fe72-4567-9b86-a833e2d8609e

📥 Commits

Reviewing files that changed from the base of the PR and between 43ec910 and d1b4f75.

📒 Files selected for processing (5)
  • src/dsnotificationinterface.cpp
  • src/dsnotificationinterface.h
  • src/init.cpp
  • src/node/context.cpp
  • src/node/context.h

Walkthrough

CDSNotificationInterface now receives and stores CDeterministicMNManager by direct reference. NodeContext owns the notification interface through a std::unique_ptr. Initialization, validation-interface registration, initial block-tip notification, shutdown unregistration, and reset now use the node-owned instance. The global g_ds_notification_interface declaration and usage were removed.

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

Suggested reviewers: udjinm6

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes moving CDSNotificationInterface from a global variable into NodeContext.
Description check ✅ Passed The description directly explains the NodeContext migration, constructor changes, affected files, and testing performed.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

Choose a reason for hiding this comment

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

Final validation — Codex + Opus

Clean two-commit refactor that first changes CDSNotificationInterface to take CDeterministicMNManager by reference (removing the now-redundant Assert), then moves the g_ds_notification_interface global into NodeContext as ds_notification_interface. Verified all call sites updated, no stale references to the old global remain anywhere in the tree, and the new member is declared after connman/dstxman/dmnman/govman/mn_sync in NodeContext so default reverse-order destruction keeps it valid; PrepareShutdown also explicitly unregisters and resets it before those managers are torn down. Both automated review agents found zero issues and my independent verification agrees — this is a safe, well-scoped refactor with no consensus impact.

Review provenance

  • Codex reviewers: gpt-5.6-sol — general (completed), gpt-5.6-sol — dash-core-commit-history (completed)
  • Verifier: claude-sonnet-5 — final-verifier
  • Opus reviewers: claude-sonnet-5 — general (completed), claude-sonnet-5 — dash-core-commit-history (failed), claude-sonnet-5 — dash-core-commit-history (completed)

CDSNotificationInterface::CDSNotificationInterface(CConnman& connman, CDSTXManager& dstxman, CMasternodeSync& mn_sync,
CGovernanceManager& govman, const ChainstateManager& chainman,
const std::unique_ptr<CDeterministicMNManager>& dmnman) :
CDeterministicMNManager& dmnman) :

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.

I didn't understand since when / how this is safe; so I asked:

You're right that it was intentional and necessary when written. The paper trail:

  1. a35245653c15 (refactor: pass references to objects instead of using global definitions #4988, Sept 2022, kittywhiskers) — "refactor: pass references to objects instead of using global definitions" is where the const std::unique_ptr<CDeterministicMNManager>& parameter was born. At that commit, the interface was created at init.cpp:1943before "Step 7b: load block chain" — and the chainstate-load retry loop at init.cpp:2039-2040 did deterministicMNManager.reset(); deterministicMNManager.reset(new CDeterministicMNManager(...)) on every retry iteration (the "try again with reindex" fallback). A plain reference bound at construction would dangle after the first reset, and the object might not even exist yet in some orderings — so passing the always-alive global slot by reference, with null tolerance (Assert), was the only correct option. The same pattern was used for the LLMQ managers in that commit for the same reason.
  2. eca0a64ea10 (backport of refactor: Move mutable globals cleared in ::UnloadBlockIndex to BlockManager bitcoin/bitcoin#22564, Aug 2024, kwvg) — "Move mutable globals cleared in ::UnloadBlockIndex to BlockManager" is the commit that made the indirection vestigial. As part of that reordering, pdsNotificationInterface creation moved from before Step 7a to after the chainstate load loop (new location right after node.peerman creation, init.cpp:2115 vs. the loop ending before :2109). From that commit onward, node.dmnman has reached its final value before the interface constructor runs, and it isn't reset again until shutdown — where the interface is destroyed first. The unique_ptr& survived from 2024 to now purely by inertia, which is what the // todo: replace unique_ptr for dmnman to reference at the creation site was tracking. (dacf8592189 is a minor waypoint — it renamed the raw pointer to the g_ds_notification_interface unique_ptr global.)

So the one-line justification for the PR: #4988 introduced the slot-reference because init then constructed the interface before the chainstate-load retry loop that destroys and recreates deterministicMNManager; the bitcoin#22564 backport (eca0a64ea10) moved construction after that loop, so the referent is now stable for the interface's entire lifetime.

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.

@PastaPastaPasta this checks out, dmnman is initialised at the beginning of Step 7(b) through LoadChainstate > DashChainstateSetup > make_unique and the notification interface is setup at the tail of that step (source).

Change should be safe.

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.

strange, I miss this unique_ptr during #7314 - had seen it but haven't noticed as it's ready. now it should be safe indeed ; long time before 7314.

Comment thread src/node/context.h
std::unique_ptr<chainlock::Chainlocks> chainlocks;
std::unique_ptr<chainlock::ChainlockHandler> clhandler;
//! Dash contexts
std::unique_ptr<CDSNotificationInterface> ds_notification_interface;

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.

Not sure about this change, upstream opted to keep their notification interface out of NodeContext (source)

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.

@kwvg Right that upstream keeps CZMQNotificationInterface global — and so do we; this PR doesn't touch g_zmq_notification_interface, deliberately, since that's a shared-with-upstream file where divergence has a real backport cost.

But I'd argue zmq is upstream's outlier rather than its policy. In v31.1, NodeContext owns notifications (KernelNotifications, "Issues blocking calls about sync status, errors and warnings"), validation_signals (the entire ValidationSignals dispatch mechanism, "Issues calls about blocks and transactions"), and peerman — which is itself a CValidationInterface subscriber and structurally the closest upstream analog to what CDSNotificationInterface is: an object that receives validation events and forwards them into node-owned subsystems.

The reason zmq works fine as a global is that it's self-contained: built from args alone (CZMQNotificationInterface::Create), references nothing in NodeContext, purely optional. CDSNotificationInterface is the opposite — it holds references to six NodeContext members (connman, dstxman, mn_sync, govman, chainman, dmnman), so its valid lifetime is exactly bracketed by NodeContext member lifetimes on both ends. As a global, that bracket is encoded implicitly in init.cpp/shutdown line ordering; as a member declared after everything it references, the destruction-order guarantee is in the type. That's also consistent with where the tree already is: active_ctx, observer_ctx, cj_walletman, and clhandler are all NodeContext-owned validation-interface subscribers — the DS interface was the last one out. And since dsnotificationinterface.{h,cpp} is Dash-only, there's no upstream file this diverges from.


🤖 Posted autonomously by Claude on behalf of pasta.

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.

nit: technically, it's not context, I think.

Should be

+std::unique_ptr<CDSNotificationInterface> ds_notification_interface;
 //! Dash contexts
-std::unique_ptr<CDSNotificationInterface> ds_notification_interface;

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

utACK d1b4f75

CDSNotificationInterface::CDSNotificationInterface(CConnman& connman, CDSTXManager& dstxman, CMasternodeSync& mn_sync,
CGovernanceManager& govman, const ChainstateManager& chainman,
const std::unique_ptr<CDeterministicMNManager>& dmnman) :
CDeterministicMNManager& dmnman) :

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.

strange, I miss this unique_ptr during #7314 - had seen it but haven't noticed as it's ready. now it should be safe indeed ; long time before 7314.

#include <governance/governance.h>
#include <instantsend/instantsend.h>
#include <masternode/sync.h>
#include <util/check.h>

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.

nit: unrelated change?

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.

I think not; I think it's related to the remove of Assert down below now that it's not a pointer

Comment thread src/node/context.h
std::unique_ptr<chainlock::Chainlocks> chainlocks;
std::unique_ptr<chainlock::ChainlockHandler> clhandler;
//! Dash contexts
std::unique_ptr<CDSNotificationInterface> ds_notification_interface;

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.

nit: technically, it's not context, I think.

Should be

+std::unique_ptr<CDSNotificationInterface> ds_notification_interface;
 //! Dash contexts
-std::unique_ptr<CDSNotificationInterface> ds_notification_interface;

@PastaPastaPasta
PastaPastaPasta merged commit 032e959 into dashpay:develop Aug 6, 2026
51 checks passed
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.

4 participants