Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
50cdc84
fix: don't return invalid values with empty `MnNetInfo`
kwvg Aug 19, 2025
ef2fb7b
evo: drop `std::reference_wrapper` usage, make copies instead
kwvg Aug 10, 2025
e9cac47
evo: introduce barebones extended addresses (`ExtNetInfo`) impl
kwvg Sep 14, 2025
56b1bb6
evo: introduce versioning for `ExtNetInfo`
kwvg Apr 10, 2025
a35d9c6
evo: prohibit entries with duplicate addresses in `ExtNetInfo`
kwvg Sep 14, 2025
4ca6542
evo: introduce the ability to store multiple lists of addresses
kwvg Aug 19, 2025
53f993c
evo: allow address entries to be differentiated by port
kwvg Aug 3, 2025
bfbfe3c
evo: allow storing platform P2P and HTTPS addresses in `ExtNetInfo`
kwvg Sep 14, 2025
e155529
evo: stop using `platform{HTTP,P2P}Port` fields if using extended addrs
kwvg Sep 14, 2025
7664ecf
refactor: consolidate input processing in ProcessNetInfo*, update errs
kwvg Sep 14, 2025
1d36005
rpc: set `platform{HTTP,P2P}Port` with `netInfo`, allow addr:port str
kwvg Sep 14, 2025
01ee293
rpc: make setting `platform{HTTP,P2P}Port` optional if using `netInfo`
kwvg Sep 14, 2025
d519eea
rpc: allow multiple entries in `platform{HTTP,P2P}Port`
kwvg Sep 14, 2025
f59f9f5
refactor(rpc): `platform{HTTP,P2P}Port` > `platform{HTTPS,P2P}Addrs`
kwvg Aug 5, 2025
f04ed99
refactor(test): `platform_{http,p2p}_port` > `addrs_platform_{https,p…
kwvg Aug 5, 2025
8efbad8
refactor(test): `coreP2PAddrs` > `addrs_core_p2p`
kwvg Aug 5, 2025
17d17af
rpc: allow `addresses` to report data from legacy platform port fields
kwvg Sep 14, 2025
245a6ee
rpc: implement special platform port shim for `CDeterministicMNStateD…
kwvg Aug 19, 2025
b69ca87
rpc: allow `platform{P2P,HTTP}Port` to return port of first address
kwvg Sep 14, 2025
885e223
test: allow passing empty `coreP2PAddrs` to `MasternodeInfo` helpers
kwvg Aug 5, 2025
30500f7
refactor(test): deduplicate common input validation in `MasternodeInfo`
kwvg Aug 5, 2025
fef8332
refactor(test): remove non-EvoNode paths from `rpc_netinfo`, cleanup
kwvg Aug 5, 2025
8843fc2
test: activate v23 fork and test post-fork input validation rules
kwvg Sep 14, 2025
5317eef
test: validate post-fork shim behavior
kwvg Aug 10, 2025
e97a650
test: validate address reporting behavior for empty address ProRegTxes
kwvg Sep 14, 2025
5b1b168
rpc: don't report Platform-specific fields in CoinJoin RPCs
kwvg Sep 14, 2025
90713a2
doc: add release notes for base extended addresses and shims
kwvg Aug 10, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion contrib/seeds/makeseeds.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ def main():
mns = filtermulticollateraladdress(mns)
mns = filtermultipayoutaddress(mns)
# Extract IPs
ips = [parseip(mn['state']['addresses'][0]) for mn in mns]
ips = [parseip(mn['state']['addresses']['core_p2p'][0]) for mn in mns]
for onion in onions:
parsed = parseip(onion)
if parsed is not None:
Expand Down
65 changes: 65 additions & 0 deletions doc/release-notes-6666.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
Notable Changes
---------------

* Dash Core has added support for the ability to register multiple addr:port pairs to a masternode and for specifying
distinct addresses for platform P2P and platform HTTPS endpoints. The consensus and format changes needed to enable
this capability is referred to as "extended addresses" and is enabled by the deployment of the v23 fork, affecting
new masternode registrations and service updates to basic BLS masternodes.
Comment on lines +6 to +7
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix subject-verb agreement and wording (“changes … are referred to … are enabled …”).

The sentence mixes plural “changes” with singular verbs. Tighten wording for clarity.

Apply this diff:

-  distinct addresses for platform P2P and platform HTTPS endpoints. The consensus and format changes needed to enable
-  this capability is referred to as "extended addresses" and is enabled by the deployment of the v23 fork, affecting
+  distinct addresses for platform P2P and platform HTTPS endpoints. The consensus and format changes needed to enable
+  this capability are referred to as "extended addresses" and are enabled by the deployment of the v23 fork, affecting
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
this capability is referred to as "extended addresses" and is enabled by the deployment of the v23 fork, affecting
new masternode registrations and service updates to basic BLS masternodes.
distinct addresses for platform P2P and platform HTTPS endpoints. The consensus and format changes needed to enable
this capability are referred to as "extended addresses" and are enabled by the deployment of the v23 fork, affecting
new masternode registrations and service updates to basic BLS masternodes.
🧰 Tools
🪛 LanguageTool

[grammar] ~7-~7: There might be a mistake here.
Context: ...ervice updates to basic BLS masternodes. * Operators must upgrade from legacy BLS s...

(QB_NEW_EN)

🤖 Prompt for AI Agents
In doc/release-notes-6666.md around lines 6 to 7, the sentence mixes plural
subject and singular verbs and is awkwardly worded; rephrase it to use
consistent plural agreement and clearer structure — e.g. start with "These
changes are referred to as 'extended addresses' and are enabled by the
deployment of the v23 fork; they affect new masternode registrations and service
updates to basic BLS masternodes." — replace the original line with a corrected
sentence that uses plural verbs and clearer punctuation.

* Operators must upgrade from legacy BLS scheme to basic BLS scheme before utilizing extended address capabilities

Additional Notes
----------------

* While the field `service` is deprecated (see dash#6665), its effective value can be obtained by querying
`addresses['core_p2p'][0]`.

* If the masternode is eligible for extended addresses, operators may register non-IPv4 addresses, subject to validation
and consensus rules.

Updated RPCs
------------

* The input field `platformP2PPort` has been renamed to `platformP2PAddrs`. In addition to numeric inputs (i.e. ports),
the field can now accept a string (i.e. an addr:port pair) and arrays of strings (i.e. multiple addr:port pairs),
subject to validation rules.

* The input field `platformHTTPPort` has been renamed to `platformHTTPSAddrs`. In addition to numeric inputs (i.e. ports),
the field can now accept a string (i.e. an addr:port pair) and arrays of strings (i.e. multiple addr:port pairs),
subject to validation rules.

* The field `addresses` will now also report on platform P2P and platform HTTPS endpoints as `addresses['platform_p2p']`
and `addresses['platform_https']` respectively.
* On payloads before extended addresses, if a masternode update affects `platformP2PPort` and/or `platformHTTPPort`
but does not affect `netInfo`, `protx listdiff` does not contain enough information to report on the masternode's
address and will report the changed port paired with the dummy address `255.255.255.255`.

This does not affect `protx listdiff` queries where `netInfo` was updated or diffs relating to masternodes that
have upgraded to extended addresses.

* If the masternode is eligible for extended addresses, `protx register{,_evo}` and `register_fund{,_evo}` will continue
allowing `coreP2PAddrs` to be left blank, as long as `platformP2PAddrs` and `platformHTTPSAddrs` are _also_ left blank.
* Attempting to populate any three address fields will make populating all fields mandatory.
* This does not affect nodes ineligible for extended addresses (i.e. all nodes before fork activation or legacy BLS nodes)
and they will have to continue specifying `platformP2PAddrs` and `platformHTTPSAddrs` even if they wish to keep
`coreP2PAddrs` blank.

* If the masternode is eligible for extended addresses, `protx register{,_evo}` and `register_fund{,_evo}` will no longer
default to the core P2P port if a port is not specified in the addr:port pair. All ports must be specified explicitly.
* This does not affect nodes ineligible for extended addresses, continuing to default to the core P2P port if provided an
addr without a port.

* `protx register{,_evo}` and `register_fund{,_evo}` will continue to allow specifying only the port number for `platformP2PAddrs`
and `platformHTTPSAddrs`, pairing it with the address from the first `coreP2PAddrs` entry. This mirrors existing behavior.
* This method of entry may not be available in future releases of Dash Core and operators are recommended to switch over to
explicitly specifying (arrays of) addr:port strings for all address fields.

* When reporting on extended address payloads, `platformP2PPort` and `platformHTTPPort` will read the port value from
`netInfo[PLATFORM_P2P][0]` and `netInfo[PLATFORM_HTTPS][0]` respectively as both fields are subsumed into `netInfo`.
* If `netInfo` is blank (which is allowed by ProRegTx), `platformP2PPort` and `platformHTTPPort` will report `-1` to indicate
that the port number cannot be determined.
* `protx listdiff` will not report `platformP2PPort` or `platformHTTPPort` if the legacy fields were not updated (i.e.
changes to `netInfo` will not translate into reporting). This is because `platformP2PPort` or `platformHTTPPort` have
dedicated diff flags and post-consolidation, all changes are now affected by `netInfo`'s diff flag.

To avoid the perception of changes to fields that not serialized by extended address payloads, data from `netInfo` will
not be translated for this RPC call.
3 changes: 2 additions & 1 deletion src/coinjoin/client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include <net.h>
#include <net_processing.h>
#include <netmessagemaker.h>
#include <rpc/evo_util.h>
#include <shutdown.h>
#include <util/check.h>
#include <util/irange.h>
Expand Down Expand Up @@ -1875,7 +1876,7 @@ void CCoinJoinClientSession::GetJsonInfo(UniValue& obj) const
if (m_wallet->chain().rpcEnableDeprecated("service")) {
obj.pushKV("service", mixingMasternode->pdmnState->netInfo->GetPrimary().ToStringAddrPort());
}
obj.pushKV("addresses", mixingMasternode->pdmnState->netInfo->ToJson());
obj.pushKV("addrs_core_p2p", mixingMasternode->pdmnState->netInfo->ToJson(NetInfoPurpose::CORE_P2P));
}
obj.pushKV("denomination", ValueFromAmount(CoinJoin::DenominationToAmount(nSessionDenom)));
obj.pushKV("state", GetStateString());
Expand Down
17 changes: 9 additions & 8 deletions src/evo/core_write.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include <evo/simplifiedmns.h>
#include <evo/smldiff.h>
#include <llmq/commitment.h>
#include <rpc/evo_util.h>

#include <univalue.h>

Expand Down Expand Up @@ -74,7 +75,7 @@
if (IsServiceDeprecatedRPCEnabled()) {
ret.pushKV("service", netInfo->GetPrimary().ToStringAddrPort());
}
ret.pushKV("addresses", netInfo->ToJson());
ret.pushKV("addresses", GetNetInfoWithLegacyFields(*this, nType));
ret.pushKV("ownerAddress", EncodeDestination(PKHash(keyIDOwner)));
ret.pushKV("votingAddress", EncodeDestination(PKHash(keyIDVoting)));
if (CTxDestination dest; ExtractDestination(scriptPayout, dest)) {
Expand All @@ -84,8 +85,8 @@
ret.pushKV("operatorReward", (double)nOperatorReward / 100);
if (nType == MnType::Evo) {
ret.pushKV("platformNodeID", platformNodeID.ToString());
ret.pushKV("platformP2PPort", platformP2PPort);
ret.pushKV("platformHTTPPort", platformHTTPPort);
ret.pushKV("platformP2PPort", GetPlatformPort</*is_p2p=*/true>(*this));
ret.pushKV("platformHTTPPort", GetPlatformPort</*is_p2p=*/false>(*this));
}
ret.pushKV("inputsHash", inputsHash.ToString());
return ret;
Expand Down Expand Up @@ -124,14 +125,14 @@
if (IsServiceDeprecatedRPCEnabled()) {
ret.pushKV("service", netInfo->GetPrimary().ToStringAddrPort());
}
ret.pushKV("addresses", netInfo->ToJson());
ret.pushKV("addresses", GetNetInfoWithLegacyFields(*this, nType));
if (CTxDestination dest; ExtractDestination(scriptOperatorPayout, dest)) {
ret.pushKV("operatorPayoutAddress", EncodeDestination(dest));
}
if (nType == MnType::Evo) {
ret.pushKV("platformNodeID", platformNodeID.ToString());
ret.pushKV("platformP2PPort", platformP2PPort);
ret.pushKV("platformHTTPPort", platformHTTPPort);
ret.pushKV("platformP2PPort", GetPlatformPort</*is_p2p=*/true>(*this));
ret.pushKV("platformHTTPPort", GetPlatformPort</*is_p2p=*/false>(*this));
}
ret.pushKV("inputsHash", inputsHash.ToString());
return ret;
Expand Down Expand Up @@ -164,12 +165,12 @@
if (IsServiceDeprecatedRPCEnabled()) {
obj.pushKV("service", netInfo->GetPrimary().ToStringAddrPort());
}
obj.pushKV("addresses", netInfo->ToJson());
obj.pushKV("addresses", GetNetInfoWithLegacyFields(*this, nType));
obj.pushKV("pubKeyOperator", pubKeyOperator.ToString());
obj.pushKV("votingAddress", EncodeDestination(PKHash(keyIDVoting)));
obj.pushKV("isValid", isValid);
if (nType == MnType::Evo) {
obj.pushKV("platformHTTPPort", platformHTTPPort);
obj.pushKV("platformHTTPPort", GetPlatformPort</*is_p2p=*/false>(*this));
obj.pushKV("platformNodeID", platformNodeID.ToString());
}

Expand Down
92 changes: 45 additions & 47 deletions src/evo/deterministicmns.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -432,13 +432,12 @@ void CDeterministicMNList::AddMN(const CDeterministicMNCPtr& dmn, bool fBumpTota
throw(std::runtime_error(strprintf("%s: Can't add a masternode %s with a duplicate collateralOutpoint=%s", __func__,
dmn->proTxHash.ToString(), dmn->collateralOutpoint.ToStringShort())));
}
for (const NetInfoEntry& entry : dmn->pdmnState->netInfo->GetEntries()) {
if (const auto& service_opt{entry.GetAddrPort()}; service_opt.has_value()) {
const CService& service{service_opt.value()};
if (!AddUniqueProperty(*dmn, service)) {
for (const auto& entry : dmn->pdmnState->netInfo->GetEntries()) {
if (const auto service_opt{entry.GetAddrPort()}) {
if (!AddUniqueProperty(*dmn, *service_opt)) {
mnUniquePropertyMap = mnUniquePropertyMapSaved;
throw std::runtime_error(strprintf("%s: Can't add a masternode %s with a duplicate address=%s",
__func__, dmn->proTxHash.ToString(), service.ToStringAddrPort()));
throw std::runtime_error(strprintf("%s: Can't add a masternode %s with a duplicate address=%s", __func__,
dmn->proTxHash.ToString(), service_opt->ToStringAddrPort()));
}
} else {
mnUniquePropertyMap = mnUniquePropertyMapSaved;
Expand Down Expand Up @@ -489,21 +488,19 @@ void CDeterministicMNList::UpdateMN(const CDeterministicMN& oldDmn, const std::s
// We track each individual entry in netInfo as opposed to netInfo itself (preventing us from
// using UpdateUniqueProperty()), so we need to successfully purge all old entries and insert
// new entries to successfully update.
for (const NetInfoEntry& old_entry : oldInfo->GetEntries()) {
if (const auto& service_opt{old_entry.GetAddrPort()}) {
const CService& service{service_opt.value()};
if (!DeleteUniqueProperty(dmn, service)) {
for (const auto& old_entry : oldInfo->GetEntries()) {
if (const auto service_opt{old_entry.GetAddrPort()}) {
if (!DeleteUniqueProperty(dmn, *service_opt)) {
return "internal error"; // This shouldn't be possible
}
} else {
return "invalid address";
}
}
for (const NetInfoEntry& new_entry : newInfo->GetEntries()) {
if (const auto& service_opt{new_entry.GetAddrPort()}) {
const CService& service{service_opt.value()};
if (!AddUniqueProperty(dmn, service)) {
return strprintf("duplicate (%s)", service.ToStringAddrPort());
for (const auto& new_entry : newInfo->GetEntries()) {
if (const auto service_opt{new_entry.GetAddrPort()}) {
if (!AddUniqueProperty(dmn, *service_opt)) {
return strprintf("duplicate (%s)", service_opt->ToStringAddrPort());
}
} else {
return "invalid address";
Expand Down Expand Up @@ -578,13 +575,12 @@ void CDeterministicMNList::RemoveMN(const uint256& proTxHash)
throw(std::runtime_error(strprintf("%s: Can't delete a masternode %s with a collateralOutpoint=%s", __func__,
proTxHash.ToString(), dmn->collateralOutpoint.ToStringShort())));
}
for (const NetInfoEntry& entry : dmn->pdmnState->netInfo->GetEntries()) {
if (const auto& service_opt{entry.GetAddrPort()}; service_opt.has_value()) {
const CService& service{service_opt.value()};
if (!DeleteUniqueProperty(*dmn, service)) {
for (const auto& entry : dmn->pdmnState->netInfo->GetEntries()) {
if (const auto service_opt{entry.GetAddrPort()}) {
if (!DeleteUniqueProperty(*dmn, *service_opt)) {
mnUniquePropertyMap = mnUniquePropertyMapSaved;
throw std::runtime_error(strprintf("%s: Can't delete a masternode %s with an address=%s", __func__,
proTxHash.ToString(), service.ToStringAddrPort()));
proTxHash.ToString(), service_opt->ToStringAddrPort()));
}
} else {
mnUniquePropertyMap = mnUniquePropertyMapSaved;
Expand Down Expand Up @@ -914,46 +910,49 @@ static bool CheckService(const ProTx& proTx, TxValidationState& state)
return true;
// Shouldn't be possible during self-checks
case NetInfoStatus::BadInput:
case NetInfoStatus::Duplicate:
case NetInfoStatus::MaxLimit:
assert(false);
} // no default case, so the compiler can warn about missing cases
assert(false);
}

template <typename ProTx>
static bool CheckPlatformFields(const ProTx& proTx, TxValidationState& state)
static bool CheckPlatformFields(const ProTx& proTx, bool is_extended_addr, TxValidationState& state)
{
if (proTx.platformNodeID.IsNull()) {
return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-platform-nodeid");
}

// TODO: use real args here
static int mainnetPlatformP2PPort = CreateChainParams(ArgsManager{}, CBaseChainParams::MAIN)->GetDefaultPlatformP2PPort();
if (Params().NetworkIDString() == CBaseChainParams::MAIN) {
if (proTx.platformP2PPort != mainnetPlatformP2PPort) {
if (is_extended_addr) {
// platformHTTPPort and platformP2PPort have been subsumed by netInfo. They should always be zero.
if (proTx.platformP2PPort != 0) {
return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-platform-p2p-port");
}
if (proTx.platformHTTPPort != 0) {
return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-platform-http-port");
}
return true;
}

// TODO: use real args here
static int mainnetPlatformHTTPPort = CreateChainParams(ArgsManager{}, CBaseChainParams::MAIN)->GetDefaultPlatformHTTPPort();
if (Params().NetworkIDString() == CBaseChainParams::MAIN) {
if (proTx.platformHTTPPort != mainnetPlatformHTTPPort) {
if (::IsNodeOnMainnet()) {
if (proTx.platformP2PPort != ::MainParams().GetDefaultPlatformP2PPort()) {
return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-platform-p2p-port");
}
if (proTx.platformHTTPPort != ::MainParams().GetDefaultPlatformHTTPPort()) {
return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-platform-http-port");
}
}

// TODO: use real args here
static int mainnetDefaultP2PPort = CreateChainParams(ArgsManager{}, CBaseChainParams::MAIN)->GetDefaultPort();
if (proTx.platformP2PPort == mainnetDefaultP2PPort) {
if (proTx.platformP2PPort == ::MainParams().GetDefaultPort()) {
return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-platform-p2p-port");
}
if (proTx.platformHTTPPort == mainnetDefaultP2PPort) {
if (proTx.platformHTTPPort == ::MainParams().GetDefaultPort()) {
return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-platform-http-port");
}

if (proTx.platformP2PPort == proTx.platformHTTPPort || proTx.platformP2PPort == proTx.netInfo->GetPrimary().GetPort() ||
proTx.platformHTTPPort == proTx.netInfo->GetPrimary().GetPort()) {
const uint16_t core_port{proTx.netInfo->GetPrimary().GetPort()};
if (proTx.platformP2PPort == proTx.platformHTTPPort || proTx.platformP2PPort == core_port ||
proTx.platformHTTPPort == core_port) {
return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-platform-dup-ports");
}

Expand Down Expand Up @@ -1065,7 +1064,7 @@ bool CheckProRegTx(CDeterministicMNManager& dmnman, const CTransaction& tx, gsl:
}

if (opt_ptx->nType == MnType::Evo) {
if (!CheckPlatformFields(*opt_ptx, state)) {
if (!CheckPlatformFields(*opt_ptx, opt_ptx->nVersion >= ProTxVersion::ExtAddr, state)) {
return false;
}
}
Expand Down Expand Up @@ -1119,11 +1118,10 @@ bool CheckProRegTx(CDeterministicMNManager& dmnman, const CTransaction& tx, gsl:
auto mnList = dmnman.GetListForBlock(pindexPrev);

// only allow reusing of addresses when it's for the same collateral (which replaces the old MN)
for (const NetInfoEntry& entry : opt_ptx->netInfo->GetEntries()) {
if (const auto& service_opt{entry.GetAddrPort()}; service_opt.has_value()) {
const CService& service{service_opt.value()};
if (mnList.HasUniqueProperty(service) &&
mnList.GetUniquePropertyMN(service)->collateralOutpoint != collateralOutpoint) {
for (const auto& entry : opt_ptx->netInfo->GetEntries()) {
if (const auto service_opt{entry.GetAddrPort()}) {
if (mnList.HasUniqueProperty(*service_opt) &&
mnList.GetUniquePropertyMN(*service_opt)->collateralOutpoint != collateralOutpoint) {
return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-dup-netinfo-entry");
}
} else {
Expand Down Expand Up @@ -1185,7 +1183,7 @@ bool CheckProUpServTx(CDeterministicMNManager& dmnman, const CTransaction& tx, g
}

if (opt_ptx->nType == MnType::Evo) {
if (!CheckPlatformFields(*opt_ptx, state)) {
if (!CheckPlatformFields(*opt_ptx, opt_ptx->nVersion >= ProTxVersion::ExtAddr, state)) {
return false;
}
}
Expand All @@ -1202,10 +1200,10 @@ bool CheckProUpServTx(CDeterministicMNManager& dmnman, const CTransaction& tx, g
}

// don't allow updating to addresses already used by other MNs
for (const NetInfoEntry& entry : opt_ptx->netInfo->GetEntries()) {
if (const auto& service_opt{entry.GetAddrPort()}; service_opt.has_value()) {
const CService& service{service_opt.value()};
if (mnList.HasUniqueProperty(service) && mnList.GetUniquePropertyMN(service)->proTxHash != opt_ptx->proTxHash) {
for (const auto& entry : opt_ptx->netInfo->GetEntries()) {
if (const auto service_opt{entry.GetAddrPort()}) {
if (mnList.HasUniqueProperty(*service_opt) &&
mnList.GetUniquePropertyMN(*service_opt)->proTxHash != opt_ptx->proTxHash) {
return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-dup-netinfo-entry");
}
} else {
Expand Down
1 change: 1 addition & 0 deletions src/evo/deterministicmns.h
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,7 @@ class CDeterministicMNList
#define DMNL_NO_TEMPLATE(name) \
static_assert(!std::is_same_v<std::decay_t<T>, name>, "GetUniquePropertyHash cannot be templated against " #name)
DMNL_NO_TEMPLATE(CBLSPublicKey);
DMNL_NO_TEMPLATE(ExtNetInfo);
DMNL_NO_TEMPLATE(MnNetInfo);
DMNL_NO_TEMPLATE(NetInfoEntry);
DMNL_NO_TEMPLATE(NetInfoInterface);
Expand Down
Loading
Loading