@@ -466,10 +466,12 @@ void CDeterministicMNList::AddMN(const CDeterministicMNCPtr& dmn, bool fBumpTota
466466 throw (std::runtime_error (strprintf (" %s: Can't add a masternode %s with a duplicate collateralOutpoint=%s" , __func__,
467467 dmn->proTxHash .ToString (), dmn->collateralOutpoint .ToStringShort ())));
468468 }
469- if (!dmn->pdmnState ->netInfo .IsEmpty () && !AddUniqueProperty (*dmn, dmn->pdmnState ->netInfo )) {
470- mnUniquePropertyMap = mnUniquePropertyMapSaved;
471- throw (std::runtime_error (strprintf (" %s: Can't add a masternode %s with a duplicate address=%s" , __func__,
472- dmn->proTxHash .ToString (), dmn->pdmnState ->netInfo .GetPrimary ().ToStringAddrPort ())));
469+ for (const CService& entry : dmn->pdmnState ->netInfo .GetEntries ()) {
470+ if (!AddUniqueProperty (*dmn, entry)) {
471+ mnUniquePropertyMap = mnUniquePropertyMapSaved;
472+ throw (std::runtime_error (strprintf (" %s: Can't add a masternode %s with a duplicate address=%s" , __func__,
473+ dmn->proTxHash .ToString (), entry.ToStringAddrPort ())));
474+ }
473475 }
474476 if (!AddUniqueProperty (*dmn, dmn->pdmnState ->keyIDOwner )) {
475477 mnUniquePropertyMap = mnUniquePropertyMapSaved;
@@ -507,10 +509,28 @@ void CDeterministicMNList::UpdateMN(const CDeterministicMN& oldDmn, const std::s
507509 // Using this temporary map as a checkpoint to roll back to in case of any issues.
508510 decltype (mnUniquePropertyMap) mnUniquePropertyMapSaved = mnUniquePropertyMap;
509511
510- if (!UpdateUniqueProperty (*dmn, oldState->netInfo , pdmnState->netInfo )) {
512+ const auto updateNetInfo = [&]() {
513+ if (oldState->netInfo != pdmnState->netInfo ) {
514+ // We track each individual entry in netInfo as opposed to netInfo itself (preventing us from
515+ // using UpdateUniqueProperty()), so we need to successfully purge all old entries and insert
516+ // new entries to successfully update.
517+ for (const CService& old_entry : oldState->netInfo .GetEntries ()) {
518+ if (old_entry != CService () && !DeleteUniqueProperty (*dmn, old_entry)) {
519+ return strprintf (" internal error" ); // This shouldn't be possible
520+ }
521+ }
522+ for (const CService& new_entry : pdmnState->netInfo .GetEntries ()) {
523+ if (new_entry != CService () && !AddUniqueProperty (*dmn, new_entry)) {
524+ return strprintf (" duplicate (%d)" , new_entry.ToStringAddrPort ());
525+ }
526+ }
527+ }
528+ return strprintf (" " );
529+ }();
530+ if (!updateNetInfo.empty ()) {
511531 mnUniquePropertyMap = mnUniquePropertyMapSaved;
512- throw (std::runtime_error (strprintf (" %s: Can't update a masternode %s with a duplicate address =%s" , __func__,
513- oldDmn.proTxHash .ToString (), pdmnState-> netInfo . GetPrimary (). ToStringAddrPort () )));
532+ throw (std::runtime_error (strprintf (" %s: Can't update masternode %s with addresses, reason =%s" , __func__,
533+ oldDmn.proTxHash .ToString (), updateNetInfo )));
514534 }
515535 if (!UpdateUniqueProperty (*dmn, oldState->keyIDOwner , pdmnState->keyIDOwner )) {
516536 mnUniquePropertyMap = mnUniquePropertyMapSaved;
@@ -567,10 +587,12 @@ void CDeterministicMNList::RemoveMN(const uint256& proTxHash)
567587 throw (std::runtime_error (strprintf (" %s: Can't delete a masternode %s with a collateralOutpoint=%s" , __func__,
568588 proTxHash.ToString (), dmn->collateralOutpoint .ToStringShort ())));
569589 }
570- if (!dmn->pdmnState ->netInfo .IsEmpty () && !DeleteUniqueProperty (*dmn, dmn->pdmnState ->netInfo )) {
571- mnUniquePropertyMap = mnUniquePropertyMapSaved;
572- throw (std::runtime_error (strprintf (" %s: Can't delete a masternode %s with a address=%s" , __func__,
573- proTxHash.ToString (), dmn->pdmnState ->netInfo .GetPrimary ().ToStringAddrPort ())));
590+ for (const CService& entry : dmn->pdmnState ->netInfo .GetEntries ()) {
591+ if (!DeleteUniqueProperty (*dmn, entry)) {
592+ mnUniquePropertyMap = mnUniquePropertyMapSaved;
593+ throw (std::runtime_error (strprintf (" %s: Can't delete a masternode %s with an address=%s" , __func__,
594+ proTxHash.ToString (), entry.ToStringAddrPort ())));
595+ }
574596 }
575597 if (!DeleteUniqueProperty (*dmn, dmn->pdmnState ->keyIDOwner )) {
576598 mnUniquePropertyMap = mnUniquePropertyMapSaved;
@@ -786,8 +808,10 @@ bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, gsl::no
786808 }
787809 }
788810
789- if (newList.HasUniqueProperty (proTx.netInfo )) {
790- return state.Invalid (BlockValidationResult::BLOCK_CONSENSUS, " bad-protx-dup-addr" );
811+ for (const CService& entry : proTx.netInfo .GetEntries ()) {
812+ if (newList.HasUniqueProperty (entry)) {
813+ return state.Invalid (BlockValidationResult::BLOCK_CONSENSUS, " bad-protx-dup-netinfo-entry" );
814+ }
791815 }
792816 if (newList.HasUniqueProperty (proTx.keyIDOwner ) || newList.HasUniqueProperty (proTx.pubKeyOperator )) {
793817 return state.Invalid (BlockValidationResult::BLOCK_CONSENSUS, " bad-protx-dup-key" );
@@ -815,8 +839,10 @@ bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, gsl::no
815839 return state.Invalid (BlockValidationResult::BLOCK_CONSENSUS, " bad-protx-payload" );
816840 }
817841
818- if (newList.HasUniqueProperty (opt_proTx->netInfo ) && newList.GetUniquePropertyMN (opt_proTx->netInfo )->proTxHash != opt_proTx->proTxHash ) {
819- return state.Invalid (BlockValidationResult::BLOCK_CONSENSUS, " bad-protx-dup-addr" );
842+ for (const CService& entry : opt_proTx->netInfo .GetEntries ()) {
843+ if (newList.HasUniqueProperty (entry) && newList.GetUniquePropertyMN (entry)->proTxHash != opt_proTx->proTxHash ) {
844+ return state.Invalid (BlockValidationResult::BLOCK_CONSENSUS, " bad-protx-dup-netinfo-entry" );
845+ }
820846 }
821847
822848 auto dmn = newList.GetMN (opt_proTx->proTxHash );
@@ -1344,8 +1370,10 @@ bool CheckProRegTx(CDeterministicMNManager& dmnman, const CTransaction& tx, gsl:
13441370 auto mnList = dmnman.GetListForBlock (pindexPrev);
13451371
13461372 // only allow reusing of addresses when it's for the same collateral (which replaces the old MN)
1347- if (mnList.HasUniqueProperty (opt_ptx->netInfo ) && mnList.GetUniquePropertyMN (opt_ptx->netInfo )->collateralOutpoint != collateralOutpoint) {
1348- return state.Invalid (TxValidationResult::TX_BAD_SPECIAL, " bad-protx-dup-addr" );
1373+ for (const CService& entry : opt_ptx->netInfo .GetEntries ()) {
1374+ if (mnList.HasUniqueProperty (entry) && mnList.GetUniquePropertyMN (entry)->collateralOutpoint != collateralOutpoint) {
1375+ return state.Invalid (TxValidationResult::TX_BAD_SPECIAL, " bad-protx-dup-netinfo-entry" );
1376+ }
13491377 }
13501378
13511379 // never allow duplicate keys, even if this ProTx would replace an existing MN
@@ -1414,8 +1442,10 @@ bool CheckProUpServTx(CDeterministicMNManager& dmnman, const CTransaction& tx, g
14141442 }
14151443
14161444 // don't allow updating to addresses already used by other MNs
1417- if (mnList.HasUniqueProperty (opt_ptx->netInfo ) && mnList.GetUniquePropertyMN (opt_ptx->netInfo )->proTxHash != opt_ptx->proTxHash ) {
1418- return state.Invalid (TxValidationResult::TX_BAD_SPECIAL, " bad-protx-dup-addr" );
1445+ for (const CService& entry : opt_ptx->netInfo .GetEntries ()) {
1446+ if (mnList.HasUniqueProperty (entry) && mnList.GetUniquePropertyMN (entry)->proTxHash != opt_ptx->proTxHash ) {
1447+ return state.Invalid (TxValidationResult::TX_BAD_SPECIAL, " bad-protx-dup-netinfo-entry" );
1448+ }
14191449 }
14201450
14211451 // don't allow updating to platformNodeIds already used by other EvoNodes
0 commit comments