Skip to content

fix: Guard mnauth by local masternode service#4974

Open
UdjinM6 wants to merge 3 commits into
dashpay:developfrom
UdjinM6:mnauth_same_addr_only
Open

fix: Guard mnauth by local masternode service#4974
UdjinM6 wants to merge 3 commits into
dashpay:developfrom
UdjinM6:mnauth_same_addr_only

Conversation

@UdjinM6
Copy link
Copy Markdown

@UdjinM6 UdjinM6 commented Aug 17, 2022

A node can be bound to multiple addresses. Send mnauth to nodes connected to the right address only to avoid confusion.

Thanks @kxcd 👍

@UdjinM6 UdjinM6 added this to the 18.1 milestone Aug 17, 2022
@PastaPastaPasta
Copy link
Copy Markdown
Member

I'm pretty sure I'd like some tests on this one please :)

@kxcd
Copy link
Copy Markdown

kxcd commented Aug 17, 2022

I can test it on testnet, just get me a build.

@UdjinM6
Copy link
Copy Markdown
Author

UdjinM6 commented Aug 17, 2022

I can test it on testnet, just get me a build.

You should be able to download it from CI build artefacts e.g. https://gitlab.com/dashpay/dash/-/jobs/2893007730/artifacts/browse/build-ci/dashcore-linux64/src/dashd for linux64-build

@kxcd
Copy link
Copy Markdown

kxcd commented Aug 17, 2022

404 on that link, I am guessing because the build failed, I will check back later.

@UdjinM6
Copy link
Copy Markdown
Author

UdjinM6 commented Aug 17, 2022

404 on that link, I am guessing because the build failed, I will check back later.

oh, sorry, my bad
results (../browse/..): https://gitlab.com/dashpay/dash/-/jobs/2893007730/artifacts/browse/build-ci/dashcore-linux64/src/
link to dashd (../file/..): https://gitlab.com/dashpay/dash/-/jobs/2893007730/artifacts/file/build-ci/dashcore-linux64/src/dashd

@MrDefacto
Copy link
Copy Markdown

MrDefacto commented Aug 17, 2022

What about nodes that uses local addresses to bind? Local IP that is translated 1:1 to public? There are certain DMZ setup or other cases when nodes are running like that.
There bind address doesn't match MN registered service IP.

EDIT: of course externalip is set to public ip

@kxcd
Copy link
Copy Markdown

kxcd commented Aug 17, 2022

My test will be on a node whose P2P is port forwarded into the VM, so I assume the dashd will bind to some private address eg, 10.x.y.z however, I believe it is still a condition that a Masternode specify the correct externalip= paramater to work and as such if this patch fails, maybe the comparison should be done against that property?

@PastaPastaPasta
Copy link
Copy Markdown
Member

Just for clarity, I'm asking for functional tests

@kxcd
Copy link
Copy Markdown

kxcd commented Aug 19, 2022

I tested this fix first with my Masternode configured for TOR, I then checked on a node with onlynet=onion and another node without TOR, the result was that on the onion network, the the MN was not disclosed and on the plain net node, it was shown as a verified MN as expected. From the logs, the top IPs that were not the same as mine where.

Num   IP
914 185.220.100.243
856 185.220.100.255
732 185.220.100.241
707 185.220.100.253
705 185.220.100.252

and
358 ::
and a few IPv6 IPs. Are these IPs TOR node IPs?
I then re-ran the test with no masternode connected to TOR and checked the log and the message still prints, I got 294 hits for :: in about 30 mins. All my masternodes are connected on behind a NAT F/W and presumably bind to a private IP. I was not able to test on VM with a public IP at this time. Just one thing, the log message says 'differents' instead of 'different', otherwise this fix seems to work.

@UdjinM6 UdjinM6 modified the milestones: 18.1, 18.2 Oct 17, 2022
@thephez
Copy link
Copy Markdown
Collaborator

thephez commented Jan 31, 2023

@PastaPastaPasta @UdjinM6 Are we planning to merge this at some point? It's still assigned to the 18.2 milestone

@PastaPastaPasta
Copy link
Copy Markdown
Member

I'm not sure... I'd really like to see a functional test on this, but if we let it sit this long w/o adding a test we may have to wait a very long time before Udjin or I decide to write the test. That makes me inclined to be okay merging it. Any thoughts Udjin?

@UdjinM6 UdjinM6 force-pushed the mnauth_same_addr_only branch from eddd6bc to 46ee326 Compare February 2, 2023 13:11
@UdjinM6
Copy link
Copy Markdown
Author

UdjinM6 commented Feb 2, 2023

I'm not sure how to make it testable cause local addresses aren't passed via version message, only routable ones are... Squashed and reworked the fix a bit - you can change https://github.com/dashpay/dash/pull/4974/files#diff-0f59ac68e534009ef1063c98c5df0b13d16771ad367cfae36850f5f2fc035d1fR34 to smth else (e.g. 127.0.0.2) and all mn-related tests should fail. That's probably the best option I have in my mind 🤷

EDIT: @kxcd could you test the new version on your nodes pls?

@UdjinM6 UdjinM6 removed this from the 18.2 milestone Feb 2, 2023
@UdjinM6 UdjinM6 force-pushed the mnauth_same_addr_only branch from 46ee326 to 4ddda42 Compare November 16, 2023 18:41
@github-actions
Copy link
Copy Markdown

This pull request has conflicts, please rebase.

@knst
Copy link
Copy Markdown
Collaborator

knst commented Apr 23, 2024

Is it still relevant? Can it be merged without tests?

@DashCoreAutoGuix
Copy link
Copy Markdown

❌ Backport Verification - Not Applicable

This PR is not a Bitcoin backport - it contains Dash-specific functionality and should not be processed by the backport verification system.

Original Bitcoin commit: (none - Dash-specific change)
Reviewed commit hash: 4ddda42324-verify-1753721929

Analysis:

  • This PR implements Dash-specific masternode functionality (mnauth, DML)
  • It addresses masternode authentication for nodes bound to multiple addresses
  • This is native Dash development, not a Bitcoin Core backport

Recommendation:
This PR should be reviewed through the standard Dash development process, not the backport verification workflow. The backport verification system is specifically designed for Bitcoin Core backports.

Note: If this PR was incorrectly labeled as a backport, please remove any backport-related labels and process it as a native Dash enhancement.

@UdjinM6 UdjinM6 force-pushed the mnauth_same_addr_only branch from 4ddda42 to 4de3119 Compare March 27, 2026 12:53
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Mar 27, 2026

✅ No Merge Conflicts Detected

This PR currently has no conflicts with other open PRs.

@UdjinM6 UdjinM6 force-pushed the mnauth_same_addr_only branch from 4de3119 to e8e8767 Compare March 27, 2026 12:59
@UdjinM6 UdjinM6 changed the title fix: Only reply with mnauth to peers that are connected to the address registered in DML fix: Guard mnauth by local masternode service Mar 27, 2026
UdjinM6 and others added 2 commits March 27, 2026 16:31
Co-authored-by: OpenAI Codex <codex@openai.com>
Co-authored-by: OpenAI Codex <codex@openai.com>
@UdjinM6 UdjinM6 force-pushed the mnauth_same_addr_only branch from e8e8767 to 20c6139 Compare March 27, 2026 13:38
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 27, 2026

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

Run ID: 93207802-39fc-497e-b7ca-9b13fec92347

📥 Commits

Reviewing files that changed from the base of the PR and between 20c6139 and dcf382e.

📒 Files selected for processing (4)
  • src/evo/mnauth.cpp
  • test/functional/p2p_mnauth.py
  • test/functional/p2p_mnauth_onion.py
  • test/functional/test_runner.py

Walkthrough

This pull request caches the masternode proTx hash and adds an inbound peer service-address validation in CMNAuth::PushMNAUTH: if an inbound peer's bound service differs from mn_activeman.GetService(), the code logs and returns without sending MNAUTH. Tests were added: p2p_mnauth.py probes registered and alternate binds (including optional 127.0.0.2 on Linux) to assert MNAUTH is sent only for the expected service; p2p_mnauth_onion.py verifies suppression for onion-tagged listeners. The test runner default list was updated to include these tests with v1/v2 transport variants.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. 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 and concisely summarizes the main change: guarding mnauth (masternode authentication) by local masternode service address.
Description check ✅ Passed The description is directly related to the changeset, explaining that mnauth should be sent only to nodes connected via the correct address to avoid confusion.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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 and usage tips.

Copy link
Copy Markdown

@thepastaclaw thepastaclaw left a comment

Choose a reason for hiding this comment

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

Code Review

Clean mnauth service guard implementation. The new check correctly compares the accepted socket local endpoint (peer.addrBind) against the active masternode registered service, properly handling multi-homed inbound connections. Functional test covers both the expected-service and alternate-bind paths for v1/v2 transport.

Reviewed commit: 20c6139

Copy link
Copy Markdown
Member

@PastaPastaPasta PastaPastaPasta left a comment

Choose a reason for hiding this comment

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

MNList now supports multiple core p2p addresses, we should acknowledge that here and use that.

@thepastaclaw
Copy link
Copy Markdown

thepastaclaw commented Mar 30, 2026

✅ Review complete (commit dcf382e)

@UdjinM6
Copy link
Copy Markdown
Author

UdjinM6 commented Mar 30, 2026

MNList now supports multiple core p2p addresses, we should acknowledge that here and use that.

That's true for MNList but masternodes themselves are single-address today - see CService m_service which is assigned via GetLocalAddress() and checked against dmn->pdmnState->netInfo->GetPrimary() in CActiveMasternodeManager::InitInternal(). If/when the active MN manager gains multi-address awareness, the MNAUTH guard should be updated to match it too - but that's a broader change beyond the scope of this fix.

@UdjinM6 UdjinM6 added this to the 24 milestone Mar 31, 2026
Copy link
Copy Markdown

@thepastaclaw thepastaclaw left a comment

Choose a reason for hiding this comment

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

Code Review

Small, focused PR adding an inbound-only guard so masternodes only emit MNAUTH on the registered service. The convergent finding from both Claude and Codex is the main concern: the new exact-match comparison between peer.addrBind (kernel getsockname() on the accepted socket) and mn_activeman.GetService() (advertised service, often derived from -externalip) silently suppresses MNAUTH for legitimate inbound peers on NAT/port-forwarded masternode deployments. The new functional test only covers loopback where the two values coincide, so it would not catch this regression.

Reviewed commit: 20c6139

Fresh dispatcher run for this queue item. A same-SHA review already existed, so this records the fresh verification without duplicating inline threads.

Code Review

Reviewed commit: 20c6139

🔴 1 blocking | 🟡 1 suggestion(s) | 💬 2 nitpick(s)

🤖 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 `src/evo/mnauth.cpp`:
- [BLOCKING] lines 26-36: Strict addrBind == GetService() check breaks MNAUTH for NAT/port-forwarded masternodes
  `mn_activeman.GetService()` is the masternode's *advertised* service, populated by `CActiveMasternodeManager::GetLocalAddress()` (src/active/masternode.cpp:217), which preferentially returns the address from `GetLocal()` — typically the value of `-externalip` or another discovered public address. By contrast, `peer.addrBind` is filled from `getsockname()` on the accepted socket (`GetBindAddress` in src/net.cpp:359, used at src/net.cpp:1867), i.e. the concrete local endpoint the kernel reports for the inbound connection.

For a typical VPS where the public IP is bound directly to the NIC, these coincide and the new guard is a no-op. But for masternodes behind NAT or port forwarding (e.g. `-bind=0.0.0.0:9999 -externalip=PUBLIC_IP:9999` while the host's real interface IP is a LAN/private address), the two values diverge for legitimate inbound probes to the registered service. The new check then silently skips MNAUTH on those connections, the remote side logs `connection is a masternode probe but first received message is not MNAUTH`, and InstantSend/CoinJoin/quorum probing breaks for that masternode. `RequireRoutableExternalIP()` on mainnet only forces externalip to be routable; it does not require it to equal the locally bound interface, so this is a real regression for an existing deployment pattern.

The new functional test (test/functional/p2p_mnauth.py) sets `-externalip=127.0.0.1:{mn_port}` so that the advertised service equals the loopback bind, making the test pass even though the NAT case it doesn't model is exactly the case this guard breaks. Consider relaxing the check (e.g. compare ports and accept any locally bound address, or fall back to checking `peer.addrBind.GetPort() == expected_service.GetPort()` when the addresses differ) and add a test variant where externalip differs from the bind address.

In `test/functional/p2p_mnauth.py`:
- [SUGGESTION] lines 84-94: Test depends on implicit framework-default bind alongside explicit -bind
  The masternode is started with `extra_args=["-bind=127.0.0.1:{alt_port}", "-externalip=127.0.0.1:{mn_port}"]` and the test then expects to connect successfully to both `mn_port` and `alt_port`. The first connection only works because the framework's default `-bind=127.0.0.1:p2p_port(2)` is also active; that coupling is invisible from reading the test. A future change to `bind_to_localhost_only` defaults or to how `extra_confs`/`extra_args` are merged could silently leave the masternode listening on `alt_port` only, at which point the first `connect(expected_addr)` would fail with a hard-to-diagnose connection error rather than the MNAUTH-related assertion the test is designed to catch. Make the test self-contained by either passing both binds explicitly via `-bind=` or asserting (e.g. via `getnetworkinfo`/`localaddresses`) that both endpoints are listening before exercising the probes.

The strict `expected_service != connected_service` equality check broke MNAUTH
on legitimate inbound for NAT/port-forwarded masternodes, where the advertised
service (from `-externalip` / `GetLocal()`) is the public IP but `peer.addrBind`
(from `getsockname()`) is the LAN/NIC interface IP. A pure port-only relaxation
would in turn leak the masternode's identity over Tor: a hidden service
forwarding to a local port matching the registered port would receive an MNAUTH
naming the IPv4-registered ProRegTx, linking the .onion to the IPv4 endpoint.

Replace the equality check with two conditions that must both hold: the local
listening port must match the registered service port (so NAT setups work), and
the inbound's `ConnectedThroughNetwork()` must match the registered service's
network class (so an IPv4-registered masternode never emits MNAUTH on a
Tor-tagged inbound, and vice versa).

Tests:
- `p2p_mnauth.py`: pass all binds explicitly via `-bind=` so the test no longer
  depends on the framework's implicit `bind=127.0.0.1` conf entry; on Linux,
  add a NAT-style sub-test that connects to `127.0.0.2:mn_port` (different
  loopback address, same port as the advertised service) and expects MNAUTH.
- `p2p_mnauth_onion.py` (new): tag the masternode's listener at the registered
  port with `=onion` so port match is guaranteed and only the network class
  differs, isolating the network check; verify MNAUTH is suppressed.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Copy link
Copy Markdown

@thepastaclaw thepastaclaw left a comment

Choose a reason for hiding this comment

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

Code Review

Refinement is a sensible tradeoff: it fixes the NAT regression introduced by the prior strict-equality check while preserving the onion-privacy guard. One legitimate gap remains — same-port multi-IPv4-bind deployments are still indistinguishable to the guard since ConnectedThroughNetwork() reflects the remote peer's net class, not the local listener. Two minor nitpicks on style and test robustness.

Reviewed commit: dcf382e

🟡 1 suggestion(s) | 💬 2 nitpick(s)

🤖 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 `src/evo/mnauth.cpp`:
- [SUGGESTION] lines 26-37: Same-port multi-bind IPv4 listeners are still indistinguishable; `ConnectedThroughNetwork()` reflects remote net class, not the local listener
  For non-onion inbound peers, `CNode::ConnectedThroughNetwork()` returns `addr.GetNetClass()` (src/net.cpp:584-586) — the *remote* peer's net class — not the local listener's. The guard therefore reduces `peer.addrBind` to `(port, peer-net-class)`, which has two consequences:

1. A masternode started with multiple IPv4 binds on the same port (e.g. `-bind=A:9999 -bind=B:9999 -externalip=A:9999`) will still emit MNAUTH on inbounds that arrived on bind B, because port matches and both endpoints are NET_IPV4. The original 'node bound to multiple addresses' confusion is unresolved for the same-port multi-homing case, which is also currently untested.
2. Edge cases like a dual-stack IPv6 listener accepting an IPv4-mapped peer, or a public-IPv4 MN receiving an inbound from a private/LAN peer (`NET_UNROUTABLE`), can flip the network comparison even though the local listener is unchanged.

This is not a regression — strict address equality would re-break the NAT case the PR is designed to fix, and the consensus-critical privacy concern (onion deanonymization) is correctly handled because `m_inbound_onion` is set on the listener side. But the partial fix is worth documenting in a code comment so future readers don't expect the guard to enforce listener-address identity, and the same-port multi-bind case could be covered by an additional test or an explicit address-family comparison against the local bind.

Comment thread src/evo/mnauth.cpp
Comment on lines +26 to +37
if (peer.IsInboundConn()) {
const CService expected_service{mn_activeman.GetService()};
const CService connected_service{static_cast<const CService&>(peer.addrBind)};
if (expected_service.GetPort() != connected_service.GetPort() ||
expected_service.GetNetwork() != peer.ConnectedThroughNetwork()) {
LogPrint(BCLog::NET_NETCONN, /* Continued */
"CMNAuth::%s -- Not sending MNAUTH on unexpected local service, expected=%s, connected=%s, "
"peer=%d\n",
__func__, expected_service.ToStringAddrPort(), connected_service.ToStringAddrPort(), peer.GetId());
return;
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Suggestion: Same-port multi-bind IPv4 listeners are still indistinguishable; ConnectedThroughNetwork() reflects remote net class, not the local listener

For non-onion inbound peers, CNode::ConnectedThroughNetwork() returns addr.GetNetClass() (src/net.cpp:584-586) — the remote peer's net class — not the local listener's. The guard therefore reduces peer.addrBind to (port, peer-net-class), which has two consequences:

  1. A masternode started with multiple IPv4 binds on the same port (e.g. -bind=A:9999 -bind=B:9999 -externalip=A:9999) will still emit MNAUTH on inbounds that arrived on bind B, because port matches and both endpoints are NET_IPV4. The original 'node bound to multiple addresses' confusion is unresolved for the same-port multi-homing case, which is also currently untested.
  2. Edge cases like a dual-stack IPv6 listener accepting an IPv4-mapped peer, or a public-IPv4 MN receiving an inbound from a private/LAN peer (NET_UNROUTABLE), can flip the network comparison even though the local listener is unchanged.

This is not a regression — strict address equality would re-break the NAT case the PR is designed to fix, and the consensus-critical privacy concern (onion deanonymization) is correctly handled because m_inbound_onion is set on the listener side. But the partial fix is worth documenting in a code comment so future readers don't expect the guard to enforce listener-address identity, and the same-port multi-bind case could be covered by an additional test or an explicit address-family comparison against the local bind.

source: ['claude', 'codex']

🤖 Fix this 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 `src/evo/mnauth.cpp`:
- [SUGGESTION] lines 26-37: Same-port multi-bind IPv4 listeners are still indistinguishable; `ConnectedThroughNetwork()` reflects remote net class, not the local listener
  For non-onion inbound peers, `CNode::ConnectedThroughNetwork()` returns `addr.GetNetClass()` (src/net.cpp:584-586) — the *remote* peer's net class — not the local listener's. The guard therefore reduces `peer.addrBind` to `(port, peer-net-class)`, which has two consequences:

1. A masternode started with multiple IPv4 binds on the same port (e.g. `-bind=A:9999 -bind=B:9999 -externalip=A:9999`) will still emit MNAUTH on inbounds that arrived on bind B, because port matches and both endpoints are NET_IPV4. The original 'node bound to multiple addresses' confusion is unresolved for the same-port multi-homing case, which is also currently untested.
2. Edge cases like a dual-stack IPv6 listener accepting an IPv4-mapped peer, or a public-IPv4 MN receiving an inbound from a private/LAN peer (`NET_UNROUTABLE`), can flip the network comparison even though the local listener is unchanged.

This is not a regression — strict address equality would re-break the NAT case the PR is designed to fix, and the consensus-critical privacy concern (onion deanonymization) is correctly handled because `m_inbound_onion` is set on the listener side. But the partial fix is worth documenting in a code comment so future readers don't expect the guard to enforce listener-address identity, and the same-port multi-bind case could be covered by an additional test or an explicit address-family comparison against the local bind.

Comment thread src/evo/mnauth.cpp
Comment on lines +27 to +34
const CService expected_service{mn_activeman.GetService()};
const CService connected_service{static_cast<const CService&>(peer.addrBind)};
if (expected_service.GetPort() != connected_service.GetPort() ||
expected_service.GetNetwork() != peer.ConnectedThroughNetwork()) {
LogPrint(BCLog::NET_NETCONN, /* Continued */
"CMNAuth::%s -- Not sending MNAUTH on unexpected local service, expected=%s, connected=%s, "
"peer=%d\n",
__func__, expected_service.ToStringAddrPort(), connected_service.ToStringAddrPort(), peer.GetId());
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💬 Nitpick: Redundant static_cast<const CService&> and connected_service local

CAddress publicly inherits from CService (src/protocol.h:398), so peer.addrBind.GetPort() and peer.addrBind.ToStringAddrPort() already invoke the CService members directly. The intermediate connected_service and the explicit slicing cast add noise without changing behavior.

💡 Suggested change
Suggested change
const CService expected_service{mn_activeman.GetService()};
const CService connected_service{static_cast<const CService&>(peer.addrBind)};
if (expected_service.GetPort() != connected_service.GetPort() ||
expected_service.GetNetwork() != peer.ConnectedThroughNetwork()) {
LogPrint(BCLog::NET_NETCONN, /* Continued */
"CMNAuth::%s -- Not sending MNAUTH on unexpected local service, expected=%s, connected=%s, "
"peer=%d\n",
__func__, expected_service.ToStringAddrPort(), connected_service.ToStringAddrPort(), peer.GetId());
if (peer.IsInboundConn()) {
const CService expected_service{mn_activeman.GetService()};
if (expected_service.GetPort() != peer.addrBind.GetPort() ||
expected_service.GetNetwork() != peer.ConnectedThroughNetwork()) {
LogPrint(BCLog::NET_NETCONN, /* Continued */
"CMNAuth::%s -- Not sending MNAUTH on unexpected local service, expected=%s, connected=%s, "
"peer=%d\n",
__func__, expected_service.ToStringAddrPort(), peer.addrBind.ToStringAddrPort(), peer.GetId());
return;
}
}

source: ['claude']

Comment on lines +64 to +67
with connector.assert_debug_log(["connection is a masternode probe but first received message is not MNAUTH"]):
assert_equal(connector.masternode("connect", alternate_addr, use_v2transport), "successfully connected")

if self.nat_capable:
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💬 Nitpick: Negative cases assert only on log strings

Both new tests verify suppression by matching log lines (Not sending MNAUTH on unexpected local service, connection is a masternode probe but first received message is not MNAUTH). These strings are coupled to log formatting that may be reworded later. A more durable assertion would also confirm that getpeerinfo on the connector for the alt-port (or onion-tagged) peer never reports verified_proregtx_hash as set — that catches the regression class even if the log lines are renamed, and rules out a hypothetical path where MNAUTH is suppressed but the peer is authenticated by some other route.

source: ['claude']

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.

8 participants