Skip to content

feat: introduce basic extended addresses implementation, stop using platform{HTTP,P2P}Port #6666

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 23 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
18ac2ab
evo: expand error codes for `netInfo` validation
kwvg May 10, 2025
d73aa0a
evo: introduce type-flexible `NetInfoEntry` to allow non-`CService` data
kwvg May 16, 2025
8a9d249
evo: ensure the ADDRV2 serialization is always used in `NetInfoEntry`
kwvg May 9, 2025
34687b1
evo: change internal type of `MnNetInfo` to `NetInfoEntry`
kwvg May 15, 2025
b9d5319
evo: return `MnNetInfo::GetEntries()` with `NetInfoEntry`
kwvg May 10, 2025
ee6cf6f
evo: utilize `NetInfoEntry::IsTriviallyValid()` in ProTx trivial checks
kwvg May 3, 2025
e49f8e3
evo: prohibit overwriting entry in `MnNetInfo`
kwvg May 9, 2025
c3e48ab
evo: fast-fail `MnNetInfo::AddEntry()` if invalid characters found
kwvg May 15, 2025
e5e8974
evo: make `netInfo` a shared pointer
kwvg May 12, 2025
89c89d3
evo: introduce `NetInfoInterface`, make `MnNetInfo` an implementation
kwvg May 11, 2025
59a5e75
evo: use interface shared ptr for `netInfo` instead of implementation
kwvg May 15, 2025
1f3afb3
evo: allow deciding `NetInfoInterface` impl based on object version
kwvg May 11, 2025
227b428
evo: introduce new ProTx version for extended addresses (`ExtNetInfo`)
kwvg May 12, 2025
341f049
evo: introduce `ExtNetInfo`, limit to 32 entries per purpose code
kwvg May 16, 2025
c9b2f8f
evo: prohibit partial duplicates in `ExtNetInfo`
kwvg May 16, 2025
0a2ef81
evo: introduce versioning for `ExtNetInfo`
kwvg Apr 10, 2025
d896ea2
evo: require the primary (i.e. first) entry to use IPv4
kwvg May 11, 2025
2263e6c
evo: introduce the ability to store multiple lists of addresses
kwvg May 16, 2025
a11c6a1
evo: allow partial duplicates across entry lists
kwvg May 15, 2025
b15f5e9
evo: allow storing platform p2p and http addresses in `ExtNetAddr`
kwvg May 16, 2025
e825694
evo: allow and recognize CJDNS addresses
kwvg May 16, 2025
3459c64
evo: recognize and store I2P and onion domains in `ExtNetInfo`
kwvg May 16, 2025
e2f1a8f
evo: introduce purpose-based port restrictions
kwvg May 16, 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
1 change: 1 addition & 0 deletions src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@ BITCOIN_CORE_H = \
evo/dmn_types.h \
evo/cbtx.h \
evo/chainhelper.h \
evo/common.h \
evo/creditpool.h \
evo/deterministicmns.h \
evo/dmnstate.h \
Expand Down
12 changes: 6 additions & 6 deletions src/coinjoin/client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ void CCoinJoinClientSession::ProcessMessage(CNode& peer, CChainState& active_cha
if (!m_mn_sync.IsBlockchainSynced()) return;

if (!mixingMasternode) return;
if (mixingMasternode->pdmnState->netInfo.GetPrimary() != peer.addr) return;
if (mixingMasternode->pdmnState->netInfo->GetPrimary() != peer.addr) return;

if (msg_type == NetMsgType::DSSTATUSUPDATE) {
CCoinJoinStatusUpdate psssup;
Expand Down Expand Up @@ -1106,7 +1106,7 @@ bool CCoinJoinClientSession::JoinExistingQueue(CAmount nBalanceNeedsAnonymized,

m_clientman.AddUsedMasternode(dsq.masternodeOutpoint);

if (connman.IsMasternodeOrDisconnectRequested(dmn->pdmnState->netInfo.GetPrimary())) {
if (connman.IsMasternodeOrDisconnectRequested(dmn->pdmnState->netInfo->GetPrimary())) {
WalletCJLogPrint(m_wallet, /* Continued */
"CCoinJoinClientSession::JoinExistingQueue -- skipping connection, masternode=%s\n", dmn->proTxHash.ToString());
continue;
Expand Down Expand Up @@ -1178,7 +1178,7 @@ bool CCoinJoinClientSession::StartNewQueue(CAmount nBalanceNeedsAnonymized, CCon
continue;
}

if (connman.IsMasternodeOrDisconnectRequested(dmn->pdmnState->netInfo.GetPrimary())) {
if (connman.IsMasternodeOrDisconnectRequested(dmn->pdmnState->netInfo->GetPrimary())) {
WalletCJLogPrint(m_wallet, "CCoinJoinClientSession::StartNewQueue -- skipping connection, masternode=%s\n",
dmn->proTxHash.ToString());
nTries++;
Expand Down Expand Up @@ -1218,7 +1218,7 @@ bool CCoinJoinClientSession::ProcessPendingDsaRequest(CConnman& connman)

CService mn_addr;
if (auto dmn = m_dmnman.GetListAtChainTip().GetMN(pendingDsaRequest.GetProTxHash())) {
mn_addr = Assert(dmn->pdmnState)->netInfo.GetPrimary();
mn_addr = Assert(dmn->pdmnState)->netInfo->GetPrimary();
} else {
WalletCJLogPrint(m_wallet, "CCoinJoinClientSession::%s -- cannot find address to connect, masternode=%s\n", __func__,
pendingDsaRequest.GetProTxHash().ToString());
Expand Down Expand Up @@ -1820,7 +1820,7 @@ void CCoinJoinClientSession::RelayIn(const CCoinJoinEntry& entry, CConnman& conn
{
if (!mixingMasternode) return;

connman.ForNode(mixingMasternode->pdmnState->netInfo.GetPrimary(), [&entry, &connman, this](CNode* pnode) {
connman.ForNode(mixingMasternode->pdmnState->netInfo->GetPrimary(), [&entry, &connman, this](CNode* pnode) {
WalletCJLogPrint(m_wallet, "CCoinJoinClientSession::RelayIn -- found master, relaying message to %s\n",
pnode->addr.ToStringAddrPort());
CNetMsgMaker msgMaker(pnode->GetCommonVersion());
Expand Down Expand Up @@ -1876,7 +1876,7 @@ void CCoinJoinClientSession::GetJsonInfo(UniValue& obj) const
assert(mixingMasternode->pdmnState);
obj.pushKV("protxhash", mixingMasternode->proTxHash.ToString());
obj.pushKV("outpoint", mixingMasternode->collateralOutpoint.ToStringShort());
obj.pushKV("service", mixingMasternode->pdmnState->netInfo.GetPrimary().ToStringAddrPort());
obj.pushKV("service", mixingMasternode->pdmnState->netInfo->GetPrimary().ToStringAddrPort());
}
obj.pushKV("denomination", ValueFromAmount(CoinJoin::DenominationToAmount(nSessionDenom)));
obj.pushKV("state", GetStateString());
Expand Down
18 changes: 18 additions & 0 deletions src/evo/common.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Copyright (c) 2025 The Dash Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#ifndef BITCOIN_EVO_COMMON_H
#define BITCOIN_EVO_COMMON_H

#include <cstdint>

namespace ProTxVersion {
enum : uint16_t {
LegacyBLS = 1,
BasicBLS = 2,
ExtAddr = 3,
};
} // namespace ProTxVersion

#endif // BITCOIN_EVO_COMMON_H
4 changes: 2 additions & 2 deletions src/evo/core_write.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@
ret.pushKV("type", ToUnderlying(nType));
ret.pushKV("collateralHash", collateralOutpoint.hash.ToString());
ret.pushKV("collateralIndex", (int)collateralOutpoint.n);
ret.pushKV("service", netInfo.GetPrimary().ToStringAddrPort());
ret.pushKV("service", netInfo->GetPrimary().ToStringAddrPort());
ret.pushKV("ownerAddress", EncodeDestination(PKHash(keyIDOwner)));
ret.pushKV("votingAddress", EncodeDestination(PKHash(keyIDVoting)));
if (CTxDestination dest; ExtractDestination(scriptPayout, dest)) {
Expand Down Expand Up @@ -114,7 +114,7 @@
ret.pushKV("version", nVersion);
ret.pushKV("type", ToUnderlying(nType));
ret.pushKV("proTxHash", proTxHash.ToString());
ret.pushKV("service", netInfo.GetPrimary().ToStringAddrPort());
ret.pushKV("service", netInfo->GetPrimary().ToStringAddrPort());
if (CTxDestination dest; ExtractDestination(scriptOperatorPayout, dest)) {
ret.pushKV("operatorPayoutAddress", EncodeDestination(dest));
}
Expand Down
141 changes: 101 additions & 40 deletions src/evo/deterministicmns.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -470,11 +470,17 @@ 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 CService& entry : dmn->pdmnState->netInfo.GetEntries()) {
if (!AddUniqueProperty(*dmn, entry)) {
mnUniquePropertyMap = mnUniquePropertyMapSaved;
throw(std::runtime_error(strprintf("%s: Can't add a masternode %s with a duplicate address=%s", __func__,
dmn->proTxHash.ToString(), entry.ToStringAddrPort())));
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)) {
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()));
}
} else {
throw std::runtime_error(
strprintf("%s: Can't add a masternode %s with invalid address", __func__, dmn->proTxHash.ToString()));
}
}
if (!AddUniqueProperty(*dmn, dmn->pdmnState->keyIDOwner)) {
Expand Down Expand Up @@ -518,14 +524,24 @@ 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 CService& old_entry : oldState->netInfo.GetEntries()) {
if (!DeleteUniqueProperty(*dmn, old_entry)) {
return strprintf("internal error"); // This shouldn't be possible
for (const NetInfoEntry& old_entry : oldState->netInfo->GetEntries()) {
if (const auto& service_opt{old_entry.GetAddrPort()}; service_opt.has_value()) {
const CService& service{service_opt.value()};
if (!DeleteUniqueProperty(*dmn, service)) {
return strprintf("internal error"); // This shouldn't be possible
}
} else {
return strprintf("invalid address");
}
}
for (const CService& new_entry : pdmnState->netInfo.GetEntries()) {
if (!AddUniqueProperty(*dmn, new_entry)) {
return strprintf("duplicate (%s)", new_entry.ToStringAddrPort());
for (const NetInfoEntry& new_entry : pdmnState->netInfo->GetEntries()) {
if (const auto& service_opt{new_entry.GetAddrPort()}; service_opt.has_value()) {
const CService& service{service_opt.value()};
if (!AddUniqueProperty(*dmn, service)) {
return strprintf("duplicate (%s)", service.ToStringAddrPort());
}
} else {
return strprintf("invalid address");
}
}
}
Expand Down Expand Up @@ -591,11 +607,17 @@ 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 CService& entry : dmn->pdmnState->netInfo.GetEntries()) {
if (!DeleteUniqueProperty(*dmn, entry)) {
mnUniquePropertyMap = mnUniquePropertyMapSaved;
throw(std::runtime_error(strprintf("%s: Can't delete a masternode %s with an address=%s", __func__,
proTxHash.ToString(), entry.ToStringAddrPort())));
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)) {
mnUniquePropertyMap = mnUniquePropertyMapSaved;
throw std::runtime_error(strprintf("%s: Can't delete a masternode %s with an address=%s", __func__,
proTxHash.ToString(), service.ToStringAddrPort()));
}
} else {
throw std::runtime_error(strprintf("%s: Can't delete a masternode %s with invalid address", __func__,
dmn->proTxHash.ToString()));
}
}
if (!DeleteUniqueProperty(*dmn, dmn->pdmnState->keyIDOwner)) {
Expand Down Expand Up @@ -811,9 +833,14 @@ bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, gsl::no
}
}

for (const CService& entry : proTx.netInfo.GetEntries()) {
if (newList.HasUniqueProperty(entry)) {
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-protx-dup-netinfo-entry");
for (const NetInfoEntry& entry : proTx.netInfo->GetEntries()) {
if (const auto& service_opt{entry.GetAddrPort()}; service_opt.has_value()) {
const CService& service{service_opt.value()};
if (newList.HasUniqueProperty(service)) {
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-protx-dup-netinfo-entry");
}
} else {
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-protx-netinfo-entry");
}
}
if (newList.HasUniqueProperty(proTx.keyIDOwner) || newList.HasUniqueProperty(proTx.pubKeyOperator)) {
Expand All @@ -824,7 +851,7 @@ bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, gsl::no

auto dmnState = std::make_shared<CDeterministicMNState>(proTx);
dmnState->nRegisteredHeight = nHeight;
if (proTx.netInfo.IsEmpty()) {
if (proTx.netInfo->IsEmpty()) {
// start in banned pdmnState as we need to wait for a ProUpServTx
dmnState->BanIfNotBanned(nHeight);
}
Expand All @@ -842,10 +869,15 @@ bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, gsl::no
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-protx-payload");
}

for (const CService& entry : opt_proTx->netInfo.GetEntries()) {
if (newList.HasUniqueProperty(entry) &&
newList.GetUniquePropertyMN(entry)->proTxHash != opt_proTx->proTxHash) {
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-protx-dup-netinfo-entry");
for (const NetInfoEntry& entry : opt_proTx->netInfo->GetEntries()) {
if (const auto& service_opt{entry.GetAddrPort()}; service_opt.has_value()) {
const CService& service{service_opt.value()};
if (newList.HasUniqueProperty(service) &&
newList.GetUniquePropertyMN(service)->proTxHash != opt_proTx->proTxHash) {
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-protx-dup-netinfo-entry");
}
} else {
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-protx-netinfo-entry");
}
}

Expand Down Expand Up @@ -902,6 +934,7 @@ bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, gsl::no
newState->BanIfNotBanned(nHeight);
// we update pubKeyOperator here, make sure state version matches
newState->nVersion = opt_proTx->nVersion;
newState->netInfo = MakeNetInfo(*newState);
newState->pubKeyOperator = opt_proTx->pubKeyOperator;
}
newState->keyIDVoting = opt_proTx->keyIDVoting;
Expand Down Expand Up @@ -1202,15 +1235,30 @@ void CDeterministicMNManager::CleanupCache(int nHeight)
}

template <typename ProTx>
static bool CheckService(const ProTx& proTx, TxValidationState& state)
static bool CheckService(const ProTx& proTx, bool is_extended_addr, TxValidationState& state)
{
switch (proTx.netInfo.Validate()) {
case NetInfoStatus::BadInput:
return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-netinfo");
if (!IsNetInfoTriviallyValid(proTx, is_extended_addr, state)) {
// pass the state returned by the function above
return false;
}
switch (proTx.netInfo->Validate()) {
case NetInfoStatus::BadAddress:
return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-netinfo-addr");
case NetInfoStatus::BadPort:
return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-netinfo-port");
case NetInfoStatus::BadType:
return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-netinfo-addr-type");
case NetInfoStatus::NotRoutable:
return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-netinfo-addr-unroutable");
case NetInfoStatus::Malformed:
return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-netinfo-bad");
case NetInfoStatus::Success:
return true;
// Shouldn't be possible during self-checks
case NetInfoStatus::BadInput:
case NetInfoStatus::Duplicate:
case NetInfoStatus::MaxLimit:
ASSERT_IF_DEBUG(false);
} // no default case, so the compiler can warn about missing cases
assert(false);
}
Expand Down Expand Up @@ -1247,8 +1295,8 @@ static bool CheckPlatformFields(const ProTx& proTx, TxValidationState& state)
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()) {
if (proTx.platformP2PPort == proTx.platformHTTPPort || proTx.platformP2PPort == proTx.netInfo->GetPrimary().GetPort() ||
proTx.platformHTTPPort == proTx.netInfo->GetPrimary().GetPort()) {
return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-platform-dup-ports");
}

Expand Down Expand Up @@ -1296,7 +1344,8 @@ static std::optional<ProTx> GetValidatedPayload(const CTransaction& tx, gsl::not
return std::nullopt;
}
const bool is_basic_scheme_active{DeploymentActiveAfter(pindexPrev, Params().GetConsensus(), Consensus::DEPLOYMENT_V19)};
if (!opt_ptx->IsTriviallyValid(is_basic_scheme_active, state)) {
const bool is_extended_addr{DeploymentActiveAfter(pindexPrev, Params().GetConsensus(), Consensus::DEPLOYMENT_V23)};
if (!opt_ptx->IsTriviallyValid(is_basic_scheme_active, is_extended_addr, state)) {
// pass the state returned by the function above
return std::nullopt;
}
Expand All @@ -1313,7 +1362,8 @@ bool CheckProRegTx(CDeterministicMNManager& dmnman, const CTransaction& tx, gsl:

// It's allowed to set addr to 0, which will put the MN into PoSe-banned state and require a ProUpServTx to be issues later
// If any of both is set, it must be valid however
if (!opt_ptx->netInfo.IsEmpty() && !CheckService(*opt_ptx, state)) {
const bool is_extended_addr{DeploymentActiveAfter(pindexPrev, Params().GetConsensus(), Consensus::DEPLOYMENT_V23)};
if (!opt_ptx->netInfo->IsEmpty() && !CheckService(*opt_ptx, is_extended_addr, state)) {
// pass the state returned by the function above
return false;
}
Expand Down Expand Up @@ -1373,10 +1423,15 @@ 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 CService& entry : opt_ptx->netInfo.GetEntries()) {
if (mnList.HasUniqueProperty(entry) &&
mnList.GetUniquePropertyMN(entry)->collateralOutpoint != collateralOutpoint) {
return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-dup-netinfo-entry");
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) {
return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-dup-netinfo-entry");
}
} else {
return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-netinfo-entry");
}
}

Expand Down Expand Up @@ -1428,7 +1483,8 @@ bool CheckProUpServTx(CDeterministicMNManager& dmnman, const CTransaction& tx, g
return false;
}

if (!CheckService(*opt_ptx, state)) {
const bool is_extended_addr{DeploymentActiveAfter(pindexPrev, Params().GetConsensus(), Consensus::DEPLOYMENT_V23)};
if (!CheckService(*opt_ptx, is_extended_addr, state)) {
// pass the state returned by the function above
return false;
}
Expand All @@ -1446,9 +1502,14 @@ bool CheckProUpServTx(CDeterministicMNManager& dmnman, const CTransaction& tx, g
}

// don't allow updating to addresses already used by other MNs
for (const CService& entry : opt_ptx->netInfo.GetEntries()) {
if (mnList.HasUniqueProperty(entry) && mnList.GetUniquePropertyMN(entry)->proTxHash != opt_ptx->proTxHash) {
return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-dup-netinfo-entry");
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) {
return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-dup-netinfo-entry");
}
} else {
return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-netinfo-entry");
}
}

Expand Down
4 changes: 4 additions & 0 deletions src/evo/deterministicmns.h
Original file line number Diff line number Diff line change
Expand Up @@ -397,7 +397,11 @@ 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);
DMNL_NO_TEMPLATE(std::shared_ptr<NetInfoInterface>);
#undef DMNL_NO_TEMPLATE
return ::SerializeHash(v);
}
Expand Down
Loading
Loading