Merge pull request #2255 from codablock/pr_dip3_logic

DIP3 compatibility code
This commit is contained in:
UdjinM6 2018-09-03 22:05:34 +03:00 committed by GitHub
commit 794921b7b5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 615 additions and 52 deletions

View File

@ -9,13 +9,144 @@
#include "netbase.h"
#include "protocol.h"
#include "netbase.h"
#include "warnings.h"
#include "init.h"
#include "evo/deterministicmns.h"
// Keep track of the active Masternode
CActiveMasternodeInfo activeMasternodeInfo;
CActiveLegacyMasternodeManager legacyActiveMasternodeManager;
CActiveDeterministicMasternodeManager* activeMasternodeManager;
std::string CActiveDeterministicMasternodeManager::GetStateString() const
{
switch (state) {
case MASTERNODE_WAITING_FOR_PROTX: return "WAITING_FOR_PROTX";
case MASTERNODE_POSE_BANNED: return "POSE_BANNED";
case MASTERNODE_REMOVED: return "REMOVED";
case MASTERNODE_READY: return "READY";
case MASTERNODE_ERROR: return "ERROR";
default: return "UNKNOWN";
}
}
std::string CActiveDeterministicMasternodeManager::GetStatus() const
{
switch (state) {
case MASTERNODE_WAITING_FOR_PROTX: return "Waiting for ProTx to appear on-chain";
case MASTERNODE_POSE_BANNED: return "Masternode was PoSe banned";
case MASTERNODE_REMOVED: return "Masternode removed from list";
case MASTERNODE_READY: return "Ready";
case MASTERNODE_ERROR: return "Error. " + strError;
default: return "Unknown";
}
}
void CActiveDeterministicMasternodeManager::Init()
{
LOCK(cs_main);
if (!fMasternodeMode)
return;
if (!deterministicMNManager->IsDeterministicMNsSporkActive())
return;
if (!GetLocalAddress(activeMasternodeInfo.service)) {
state = MASTERNODE_ERROR;
return;
}
CDeterministicMNList mnList = deterministicMNManager->GetListAtChainTip();
CDeterministicMNCPtr dmn = mnList.GetMNByOperatorKey(activeMasternodeInfo.keyIDOperator);
if (!dmn) {
// MN not appeared on the chain yet
return;
}
if (!mnList.IsMNValid(dmn->proTxHash)) {
if (mnList.IsMNPoSeBanned(dmn->proTxHash)) {
state = MASTERNODE_POSE_BANNED;
} else {
state = MASTERNODE_REMOVED;
}
return;
}
mnListEntry = dmn;
LogPrintf("CActiveDeterministicMasternodeManager::Init -- proTxHash=%s, proTx=%s\n", mnListEntry->proTxHash.ToString(), mnListEntry->ToString());
if (activeMasternodeInfo.service != mnListEntry->pdmnState->addr) {
state = MASTERNODE_ERROR;
strError = "Local address does not match the address from ProTx";
LogPrintf("CActiveDeterministicMasternodeManager::Init -- ERROR: %s", strError);
return;
}
if (mnListEntry->pdmnState->nProtocolVersion != PROTOCOL_VERSION) {
state = MASTERNODE_ERROR;
strError = "Local protocol version does not match version from ProTx. You may need to update the ProTx";
LogPrintf("CActiveDeterministicMasternodeManager::Init -- ERROR: %s", strError);
return;
}
activeMasternodeInfo.outpoint = COutPoint(mnListEntry->proTxHash, mnListEntry->nCollateralIndex);
state = MASTERNODE_READY;
}
void CActiveDeterministicMasternodeManager::UpdatedBlockTip(const CBlockIndex* pindexNew, const CBlockIndex* pindexFork, bool fInitialDownload)
{
LOCK(cs_main);
if (!fMasternodeMode)
return;
if (!deterministicMNManager->IsDeterministicMNsSporkActive(pindexNew->nHeight)) {
return;
}
if (state == MASTERNODE_WAITING_FOR_PROTX) {
Init();
} else if (state == MASTERNODE_READY) {
if (!deterministicMNManager->HasValidMNAtBlock(pindexNew->GetBlockHash(), mnListEntry->proTxHash)) {
// MN disappeared from MN list
state = MASTERNODE_REMOVED;
activeMasternodeInfo.outpoint.SetNull();
// MN might have reappeared in same block with a new ProTx (with same masternode key)
Init();
}
} else if (state == MASTERNODE_REMOVED || state == MASTERNODE_POSE_BANNED) {
// MN might have reappeared with a new ProTx (with same masternode key)
Init();
}
}
bool CActiveDeterministicMasternodeManager::GetLocalAddress(CService &addrRet)
{
// First try to find whatever local address is specified by externalip option
bool fFoundLocal = GetLocal(addrRet) && CMasternode::IsValidNetAddr(addrRet);
if (!fFoundLocal && Params().NetworkIDString() == CBaseChainParams::REGTEST) {
if (Lookup("127.0.0.1", addrRet, GetListenPort(), false)) {
fFoundLocal = true;
}
}
if(!fFoundLocal) {
strError = "Can't detect valid external address. Please consider using the externalip configuration option if problem persists. Make sure to use IPv4 address only.";
LogPrintf("CActiveDeterministicMasternodeManager::GetLocalAddress -- ERROR: %s\n", strError);
return false;
}
return true;
}
/********* LEGACY *********/
void CActiveLegacyMasternodeManager::ManageState(CConnman& connman)
{
if (deterministicMNManager->IsDeterministicMNsSporkActive())
return;
LogPrint("masternode", "CActiveLegacyMasternodeManager::ManageState -- Start\n");
if(!fMasternodeMode) {
LogPrint("masternode", "CActiveLegacyMasternodeManager::ManageState -- Not a masternode, returning\n");
@ -84,6 +215,9 @@ std::string CActiveLegacyMasternodeManager::GetTypeString() const
bool CActiveLegacyMasternodeManager::SendMasternodePing(CConnman& connman)
{
if (deterministicMNManager->IsDeterministicMNsSporkActive())
return false;
if(!fPingerEnabled) {
LogPrint("masternode", "CActiveLegacyMasternodeManager::SendMasternodePing -- %s: masternode ping service is disabled, skipping...\n", GetStateString());
return false;
@ -129,6 +263,9 @@ bool CActiveLegacyMasternodeManager::UpdateSentinelPing(int version)
void CActiveLegacyMasternodeManager::ManageStateInitial(CConnman& connman)
{
if (deterministicMNManager->IsDeterministicMNsSporkActive())
return;
LogPrint("masternode", "CActiveLegacyMasternodeManager::ManageStateInitial -- status = %s, type = %s, pinger enabled = %d\n", GetStatus(), GetTypeString(), fPingerEnabled);
// Check that our local network configuration is correct
@ -210,6 +347,9 @@ void CActiveLegacyMasternodeManager::ManageStateInitial(CConnman& connman)
void CActiveLegacyMasternodeManager::ManageStateRemote()
{
if (deterministicMNManager->IsDeterministicMNsSporkActive())
return;
LogPrint("masternode", "CActiveLegacyMasternodeManager::ManageStateRemote -- Start status = %s, type = %s, pinger enabled = %d, keyIDOperator = %s\n",
GetStatus(), GetTypeString(), fPingerEnabled, activeMasternodeInfo.keyIDOperator.ToString());
@ -234,6 +374,22 @@ void CActiveLegacyMasternodeManager::ManageStateRemote()
LogPrintf("CActiveLegacyMasternodeManager::ManageStateRemote -- %s: %s\n", GetStateString(), strNotCapableReason);
return;
}
auto dmn = deterministicMNManager->GetListAtChainTip().GetMN(infoMn.outpoint.hash);
if (dmn) {
if (dmn->pdmnState->keyIDOperator != infoMn.keyIDOperator) {
nState = ACTIVE_MASTERNODE_NOT_CAPABLE;
strNotCapableReason = strprintf("Masternode collateral is a ProTx and masternode key does not match key from -masternodeprivkey");
LogPrintf("CActiveLegacyMasternodeManager::ManageStateRemote -- %s: %s\n", GetStateString(), strNotCapableReason);
return;
}
if (dmn->pdmnState->addr != infoMn.addr) {
nState = ACTIVE_MASTERNODE_NOT_CAPABLE;
strNotCapableReason = strprintf("Masternode collateral is a ProTx and ProTx address does not match local address");
LogPrintf("CActiveLegacyMasternodeManager::ManageStateRemote -- %s: %s\n", GetStateString(), strNotCapableReason);
return;
}
LogPrintf("CActiveLegacyMasternodeManager::ManageStateRemote -- Collateral is a ProTx\n");
}
if(nState != ACTIVE_MASTERNODE_STARTED) {
LogPrintf("CActiveLegacyMasternodeManager::ManageStateRemote -- STARTED!\n");
activeMasternodeInfo.outpoint = infoMn.outpoint;

View File

@ -9,9 +9,14 @@
#include "key.h"
#include "net.h"
#include "primitives/transaction.h"
#include "validationinterface.h"
#include "evo/providertx.h"
#include "evo/deterministicmns.h"
struct CActiveMasternodeInfo;
class CActiveLegacyMasternodeManager;
class CActiveDeterministicMasternodeManager;
static const int ACTIVE_MASTERNODE_INITIAL = 0; // initial state
static const int ACTIVE_MASTERNODE_SYNC_IN_PROCESS = 1;
@ -21,6 +26,7 @@ static const int ACTIVE_MASTERNODE_STARTED = 4;
extern CActiveMasternodeInfo activeMasternodeInfo;
extern CActiveLegacyMasternodeManager legacyActiveMasternodeManager;
extern CActiveDeterministicMasternodeManager* activeMasternodeManager;
struct CActiveMasternodeInfo {
// Keys for the active Masternode
@ -32,7 +38,39 @@ struct CActiveMasternodeInfo {
CService service;
};
// Responsible for activating the Masternode and pinging the network
class CActiveDeterministicMasternodeManager : public CValidationInterface
{
public:
enum masternode_state_t {
MASTERNODE_WAITING_FOR_PROTX,
MASTERNODE_POSE_BANNED,
MASTERNODE_REMOVED,
MASTERNODE_READY,
MASTERNODE_ERROR,
};
private:
CDeterministicMNCPtr mnListEntry;
masternode_state_t state{MASTERNODE_WAITING_FOR_PROTX};
std::string strError;
public:
virtual void UpdatedBlockTip(const CBlockIndex* pindexNew, const CBlockIndex* pindexFork, bool fInitialDownload);
void Init();
CDeterministicMNCPtr GetDMN() const { return mnListEntry; }
masternode_state_t GetState() const { return state; }
std::string GetStateString() const;
std::string GetStatus() const;
private:
bool GetLocalAddress(CService &addrRet);
};
// Responsible for activating the Masternode and pinging the network (legacy MN list)
class CActiveLegacyMasternodeManager
{
public:

View File

@ -318,6 +318,9 @@ void PrepareShutdown()
delete pdsNotificationInterface;
pdsNotificationInterface = NULL;
}
if (fMasternodeMode) {
UnregisterValidationInterface(activeMasternodeManager);
}
#ifndef WIN32
try {
@ -1880,6 +1883,10 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
} else {
return InitError(_("You must specify a masternodeprivkey in the configuration. Please see documentation for help."));
}
// init and register activeMasternodeManager
activeMasternodeManager = new CActiveDeterministicMasternodeManager();
RegisterValidationInterface(activeMasternodeManager);
}
#ifdef ENABLE_WALLET
@ -1996,6 +2003,9 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
// GetMainSignals().UpdatedBlockTip(chainActive.Tip());
pdsNotificationInterface->InitializeCurrentBlockTip();
if (activeMasternodeManager && fDIP0003ActiveAtTip)
activeMasternodeManager->Init();
// ********************************************************* Step 11d: schedule Dash-specific tasks
if (!fLiteMode) {

View File

@ -15,6 +15,7 @@
#include "spork.h"
#include "ui_interface.h"
#include "util.h"
#include "evo/deterministicmns.h"
class CMasternodeSync;
CMasternodeSync masternodeSync;
@ -69,12 +70,20 @@ void CMasternodeSync::SwitchToNextAsset(CConnman& connman)
break;
case(MASTERNODE_SYNC_WAITING):
LogPrintf("CMasternodeSync::SwitchToNextAsset -- Completed %s in %llds\n", GetAssetName(), GetTime() - nTimeAssetSyncStarted);
if (deterministicMNManager->IsDeterministicMNsSporkActive()) {
nRequestedMasternodeAssets = MASTERNODE_SYNC_GOVERNANCE;
} else {
nRequestedMasternodeAssets = MASTERNODE_SYNC_LIST;
}
LogPrintf("CMasternodeSync::SwitchToNextAsset -- Starting %s\n", GetAssetName());
break;
case(MASTERNODE_SYNC_LIST):
LogPrintf("CMasternodeSync::SwitchToNextAsset -- Completed %s in %llds\n", GetAssetName(), GetTime() - nTimeAssetSyncStarted);
if (deterministicMNManager->IsDeterministicMNsSporkActive()) {
nRequestedMasternodeAssets = MASTERNODE_SYNC_GOVERNANCE;
} else {
nRequestedMasternodeAssets = MASTERNODE_SYNC_MNW;
}
LogPrintf("CMasternodeSync::SwitchToNextAsset -- Starting %s\n", GetAssetName());
break;
case(MASTERNODE_SYNC_MNW):
@ -188,15 +197,19 @@ void CMasternodeSync::ProcessTick(CConnman& connman)
connman.PushMessage(pnode, msgMaker.Make(NetMsgType::GETSPORKS)); //get current network sporks
SwitchToNextAsset(connman);
} else if (nRequestedMasternodeAssets == MASTERNODE_SYNC_LIST) {
if (!deterministicMNManager->IsDeterministicMNsSporkActive()) {
mnodeman.DsegUpdate(pnode, connman);
}
SwitchToNextAsset(connman);
} else if (nRequestedMasternodeAssets == MASTERNODE_SYNC_MNW) {
if (!deterministicMNManager->IsDeterministicMNsSporkActive()) {
//sync payment votes
if(pnode->nVersion == 70208) {
connman.PushMessage(pnode, msgMaker.Make(NetMsgType::MASTERNODEPAYMENTSYNC, mnpayments.GetStorageLimit())); //sync payment votes
} else {
connman.PushMessage(pnode, msgMaker.Make(NetMsgType::MASTERNODEPAYMENTSYNC)); //sync payment votes
}
}
SwitchToNextAsset(connman);
} else if (nRequestedMasternodeAssets == MASTERNODE_SYNC_GOVERNANCE) {
SendGovernanceSyncRequest(pnode, connman);
@ -245,6 +258,12 @@ void CMasternodeSync::ProcessTick(CConnman& connman)
// MNLIST : SYNC MASTERNODE LIST FROM OTHER CONNECTED CLIENTS
if(nRequestedMasternodeAssets == MASTERNODE_SYNC_LIST) {
if (deterministicMNManager->IsDeterministicMNsSporkActive()) {
SwitchToNextAsset(connman);
connman.ReleaseNodeVector(vNodesCopy);
return;
}
LogPrint("masternode", "CMasternodeSync::ProcessTick -- nTick %d nRequestedMasternodeAssets %d nTimeLastBumped %lld GetTime() %lld diff %lld\n", nTick, nRequestedMasternodeAssets, nTimeLastBumped, GetTime(), GetTime() - nTimeLastBumped);
// check for timeout first
if(GetTime() - nTimeLastBumped > MASTERNODE_SYNC_TIMEOUT_SECONDS) {
@ -283,6 +302,12 @@ void CMasternodeSync::ProcessTick(CConnman& connman)
// MNW : SYNC MASTERNODE PAYMENT VOTES FROM OTHER CONNECTED CLIENTS
if(nRequestedMasternodeAssets == MASTERNODE_SYNC_MNW) {
if (deterministicMNManager->IsDeterministicMNsSporkActive()) {
SwitchToNextAsset(connman);
connman.ReleaseNodeVector(vNodesCopy);
return;
}
LogPrint("mnpayments", "CMasternodeSync::ProcessTick -- nTick %d nRequestedMasternodeAssets %d nTimeLastBumped %lld GetTime() %lld diff %lld\n", nTick, nRequestedMasternodeAssets, nTimeLastBumped, GetTime(), GetTime() - nTimeLastBumped);
// check for timeout first
// This might take a lot longer than MASTERNODE_SYNC_TIMEOUT_SECONDS due to new blocks,

View File

@ -52,6 +52,17 @@ CMasternode::CMasternode(const CMasternodeBroadcast& mnb) :
fAllowMixingTx(true)
{}
CMasternode::CMasternode(const uint256 &proTxHash, const CDeterministicMNCPtr& dmn) :
masternode_info_t{ MASTERNODE_ENABLED, dmn->pdmnState->nProtocolVersion, GetAdjustedTime(),
COutPoint(proTxHash, dmn->nCollateralIndex), dmn->pdmnState->addr, CKeyID(), dmn->pdmnState->keyIDOwner, dmn->pdmnState->keyIDOperator, dmn->pdmnState->keyIDVoting},
fAllowMixingTx(true)
{
CTxDestination dest;
if (!ExtractDestination(dmn->pdmnState->scriptPayout, dest) || !boost::get<CKeyID>(&dest))
assert(false); // should not happen (previous verification forbids non p2pkh/p2pk
keyIDCollateralAddress = *boost::get<CKeyID>(&dest);
}
//
// When a new masternode broadcast is sent, update our information
//

View File

@ -9,6 +9,8 @@
#include "validation.h"
#include "spork.h"
#include "evo/deterministicmns.h"
class CMasternode;
class CMasternodeBroadcast;
class CConnman;
@ -214,6 +216,7 @@ public:
CMasternode(const CMasternode& other);
CMasternode(const CMasternodeBroadcast& mnb);
CMasternode(CService addrNew, COutPoint outpointNew, CPubKey pubKeyCollateralAddressNew, CPubKey pubKeyMasternodeNew, int nProtocolVersionIn);
CMasternode(const uint256 &proTxHash, const CDeterministicMNCPtr& dmn);
ADD_SERIALIZE_METHODS;

View File

@ -22,6 +22,9 @@
#include "util.h"
#include "warnings.h"
#include "evo/deterministicmns.h"
#include "evo/providertx.h"
/** Masternode manager */
CMasternodeMan mnodeman;
@ -79,6 +82,9 @@ bool CMasternodeMan::Add(CMasternode &mn)
{
LOCK(cs);
if (deterministicMNManager->IsDeterministicMNsSporkActive())
return false;
if (Has(mn.outpoint)) return false;
LogPrint("masternode", "CMasternodeMan::Add -- Adding new Masternode: addr=%s, %i now\n", mn.addr.ToString(), size() + 1);
@ -94,6 +100,9 @@ void CMasternodeMan::AskForMN(CNode* pnode, const COutPoint& outpoint, CConnman&
CNetMsgMaker msgMaker(pnode->GetSendVersion());
LOCK(cs);
if (deterministicMNManager->IsDeterministicMNsSporkActive())
return;
CService addrSquashed = Params().AllowMultiplePorts() ? (CService)pnode->addr : CService(pnode->addr, 0);
auto it1 = mWeAskedForMasternodeListEntry.find(outpoint);
if (it1 != mWeAskedForMasternodeListEntry.end()) {
@ -151,6 +160,10 @@ bool CMasternodeMan::DisallowMixing(const COutPoint &outpoint)
bool CMasternodeMan::PoSeBan(const COutPoint &outpoint)
{
LOCK(cs);
if (deterministicMNManager->IsDeterministicMNsSporkActive())
return true;
CMasternode* pmn = Find(outpoint);
if (!pmn) {
return false;
@ -164,6 +177,9 @@ void CMasternodeMan::Check()
{
LOCK2(cs_main, cs);
if (deterministicMNManager->IsDeterministicMNsSporkActive())
return;
for (auto& mnpair : mapMasternodes) {
// NOTE: internally it checks only every MASTERNODE_CHECK_SECONDS seconds
// since the last time, so expect some MNs to skip this
@ -173,6 +189,9 @@ void CMasternodeMan::Check()
void CMasternodeMan::CheckAndRemove(CConnman& connman)
{
if (deterministicMNManager->IsDeterministicMNsSporkActive())
return;
if(!masternodeSync.IsMasternodeListSynced()) return;
LogPrintf("CMasternodeMan::CheckAndRemove\n");
@ -355,6 +374,69 @@ void CMasternodeMan::CheckAndRemove(CConnman& connman)
}
}
void CMasternodeMan::AddDeterministicMasternodes()
{
if (!deterministicMNManager->IsDeterministicMNsSporkActive())
return;
bool added = false;
{
LOCK(cs);
unsigned int oldMnCount = mapMasternodes.size();
auto mnList = deterministicMNManager->GetListAtChainTip();
for (const auto& dmn : mnList.valid_range()) {
// call Find() on each deterministic MN to force creation of CMasternode object
auto mn = Find(COutPoint(dmn->proTxHash, dmn->nCollateralIndex));
assert(mn);
// make sure we use the splitted keys from now on
mn->keyIDOwner = dmn->pdmnState->keyIDOwner;
mn->keyIDOperator = dmn->pdmnState->keyIDOperator;
mn->keyIDVoting = dmn->pdmnState->keyIDVoting;
mn->addr = dmn->pdmnState->addr;
mn->nProtocolVersion = dmn->pdmnState->nProtocolVersion;
// If it appeared in the valid list, it is enabled no matter what
mn->nActiveState = CMasternode::MASTERNODE_ENABLED;
}
added = oldMnCount != mapMasternodes.size();
}
if (added) {
NotifyMasternodeUpdates(*g_connman, true, false);
}
}
void CMasternodeMan::RemoveNonDeterministicMasternodes()
{
if (!deterministicMNManager->IsDeterministicMNsSporkActive())
return;
bool erased = false;
{
LOCK(cs);
std::set<COutPoint> mnSet;
auto mnList = deterministicMNManager->GetListAtChainTip();
for (const auto& dmn : mnList.valid_range()) {
mnSet.insert(COutPoint(dmn->proTxHash, dmn->nCollateralIndex));
}
auto it = mapMasternodes.begin();
while (it != mapMasternodes.end()) {
if (!mnSet.count(it->second.outpoint)) {
mapMasternodes.erase(it++);
erased = true;
} else {
++it;
}
}
}
if (erased) {
NotifyMasternodeUpdates(*g_connman, false, true);
}
}
void CMasternodeMan::Clear()
{
LOCK(cs);
@ -371,20 +453,32 @@ void CMasternodeMan::Clear()
int CMasternodeMan::CountMasternodes(int nProtocolVersion)
{
LOCK(cs);
int nCount = 0;
nProtocolVersion = nProtocolVersion == -1 ? mnpayments.GetMinMasternodePaymentsProto() : nProtocolVersion;
if (deterministicMNManager->IsDeterministicMNsSporkActive()) {
auto mnList = deterministicMNManager->GetListAtChainTip();
for (const auto& dmn : mnList.valid_range()) {
if (dmn->pdmnState->nProtocolVersion < nProtocolVersion) continue;
nCount++;
}
} else {
for (const auto& mnpair : mapMasternodes) {
if(mnpair.second.nProtocolVersion < nProtocolVersion) continue;
nCount++;
}
}
return nCount;
}
int CMasternodeMan::CountEnabled(int nProtocolVersion)
{
LOCK(cs);
if (deterministicMNManager->IsDeterministicMNsSporkActive())
return CountMasternodes(nProtocolVersion);
int nCount = 0;
nProtocolVersion = nProtocolVersion == -1 ? mnpayments.GetMinMasternodePaymentsProto() : nProtocolVersion;
@ -418,6 +512,9 @@ void CMasternodeMan::DsegUpdate(CNode* pnode, CConnman& connman)
CNetMsgMaker msgMaker(pnode->GetSendVersion());
LOCK(cs);
if (deterministicMNManager->IsDeterministicMNsSporkActive())
return;
CService addrSquashed = Params().AllowMultiplePorts() ? (CService)pnode->addr : CService(pnode->addr, 0);
if(Params().NetworkIDString() == CBaseChainParams::MAIN) {
if(!(pnode->addr.IsRFC1918() || pnode->addr.IsLocal())) {
@ -443,36 +540,69 @@ void CMasternodeMan::DsegUpdate(CNode* pnode, CConnman& connman)
CMasternode* CMasternodeMan::Find(const COutPoint &outpoint)
{
LOCK(cs);
if (deterministicMNManager->IsDeterministicMNsSporkActive()) {
// This code keeps compatibility to old code depending on the non-deterministic MN lists
// When deterministic MN lists get activated, we stop relying on the MNs we encountered due to MNBs and start
// using the MNs found in the deterministic MN manager. To keep compatibility, we create CMasternode entries
// for these and return them here. This is needed because we also need to track some data per MN that is not
// on-chain, like vote counts
auto mnList = deterministicMNManager->GetListAtChainTip();
if (!mnList.IsMNValid(outpoint.hash)) {
return nullptr;
}
auto dmn = mnList.GetMN(outpoint.hash);
if (!dmn) {
return nullptr;
}
auto it = mapMasternodes.find(outpoint);
if (it != mapMasternodes.end()) {
return &(it->second);
} else {
// MN is not in mapMasternodes but in the deterministic list. Create an entry in mapMasternodes for compatibility with legacy code
CMasternode mn(outpoint.hash, dmn);
it = mapMasternodes.emplace(outpoint, mn).first;
return &(it->second);
}
} else {
auto it = mapMasternodes.find(outpoint);
return it == mapMasternodes.end() ? nullptr : &(it->second);
}
}
bool CMasternodeMan::Get(const COutPoint& outpoint, CMasternode& masternodeRet)
{
// Theses mutexes are recursive so double locking by the same thread is safe.
LOCK(cs);
auto it = mapMasternodes.find(outpoint);
if (it == mapMasternodes.end()) {
CMasternode* mn = Find(outpoint);
if (!mn)
return false;
}
masternodeRet = it->second;
masternodeRet = *mn;
return true;
}
bool CMasternodeMan::GetMasternodeInfo(const COutPoint& outpoint, masternode_info_t& mnInfoRet)
{
LOCK(cs);
auto it = mapMasternodes.find(outpoint);
if (it == mapMasternodes.end()) {
CMasternode* mn = Find(outpoint);
if (!mn)
return false;
}
mnInfoRet = it->second.GetInfo();
mnInfoRet = mn->GetInfo();
return true;
}
bool CMasternodeMan::GetMasternodeInfo(const CKeyID& keyIDOperator, masternode_info_t& mnInfoRet) {
LOCK(cs);
if (deterministicMNManager->IsDeterministicMNsSporkActive()) {
auto mnList = deterministicMNManager->GetListAtChainTip();
auto dmn = mnList.GetMNByOperatorKey(keyIDOperator);
if (dmn) {
return GetMasternodeInfo(COutPoint(dmn->proTxHash, dmn->nCollateralIndex), mnInfoRet);
}
return false;
} else {
for (const auto& mnpair : mapMasternodes) {
if (mnpair.second.keyIDOperator == keyIDOperator) {
mnInfoRet = mnpair.second.GetInfo();
@ -481,6 +611,7 @@ bool CMasternodeMan::GetMasternodeInfo(const CKeyID& keyIDOperator, masternode_i
}
return false;
}
}
bool CMasternodeMan::GetMasternodeInfo(const CPubKey& pubKeyOperator, masternode_info_t& mnInfoRet)
{
@ -506,8 +637,12 @@ bool CMasternodeMan::GetMasternodeInfo(const CScript& payee, masternode_info_t&
bool CMasternodeMan::Has(const COutPoint& outpoint)
{
LOCK(cs);
if (deterministicMNManager->IsDeterministicMNsSporkActive()) {
return deterministicMNManager->HasValidMNAtChainTip(outpoint.hash);
} else {
return mapMasternodes.find(outpoint) != mapMasternodes.end();
}
}
//
// Deterministically select the oldest/best masternode to pay on the network
@ -627,6 +762,8 @@ masternode_info_t CMasternodeMan::FindRandomNotInVec(const std::vector<COutPoint
}
}
if(fExclude) continue;
if (deterministicMNManager->IsDeterministicMNsSporkActive() && !deterministicMNManager->HasValidMNAtChainTip(pmn->outpoint.hash))
continue;
// found the one not in vecToExclude
LogPrint("masternode", "CMasternodeMan::FindRandomNotInVec -- found, masternode=%s\n", pmn->outpoint.ToStringShort());
return pmn->GetInfo();
@ -636,6 +773,23 @@ masternode_info_t CMasternodeMan::FindRandomNotInVec(const std::vector<COutPoint
return masternode_info_t();
}
std::map<COutPoint, CMasternode> CMasternodeMan::GetFullMasternodeMap()
{
LOCK(cs);
if (deterministicMNManager->IsDeterministicMNsSporkActive()) {
std::map<COutPoint, CMasternode> result;
for (const auto &p : mapMasternodes) {
if (deterministicMNManager->HasValidMNAtChainTip(p.first.hash)) {
result.emplace(p.first, p.second);
}
}
return result;
} else {
return mapMasternodes;
}
}
bool CMasternodeMan::GetMasternodeScores(const uint256& nBlockHash, CMasternodeMan::score_pair_vec_t& vecMasternodeScoresRet, int nMinProtocol)
{
vecMasternodeScoresRet.clear();
@ -650,6 +804,9 @@ bool CMasternodeMan::GetMasternodeScores(const uint256& nBlockHash, CMasternodeM
// calculate scores
for (const auto& mnpair : mapMasternodes) {
if (deterministicMNManager->IsDeterministicMNsSporkActive() && !deterministicMNManager->HasValidMNAtChainTip(mnpair.second.outpoint.hash))
continue;
if (mnpair.second.nProtocolVersion >= nMinProtocol) {
vecMasternodeScoresRet.push_back(std::make_pair(mnpair.second.CalculateScore(nBlockHash), &mnpair.second));
}
@ -740,6 +897,9 @@ void CMasternodeMan::ProcessMasternodeConnections(CConnman& connman)
std::pair<CService, std::set<uint256> > CMasternodeMan::PopScheduledMnbRequestConnection()
{
LOCK(cs);
if (deterministicMNManager->IsDeterministicMNsSporkActive()) {
return std::make_pair(CService(), std::set<uint256>());
}
if(listScheduledMnbRequestConnections.empty()) {
return std::make_pair(CService(), std::set<uint256>());
}
@ -766,6 +926,9 @@ std::pair<CService, std::set<uint256> > CMasternodeMan::PopScheduledMnbRequestCo
void CMasternodeMan::ProcessPendingMnbRequests(CConnman& connman)
{
if (deterministicMNManager->IsDeterministicMNsSporkActive())
return;
std::pair<CService, std::set<uint256> > p = PopScheduledMnbRequestConnection();
if (!(p.first == CService() || p.second.empty())) {
if (connman.IsMasternodeOrDisconnectRequested(p.first)) return;
@ -805,6 +968,9 @@ void CMasternodeMan::ProcessPendingMnbRequests(CConnman& connman)
void CMasternodeMan::ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, CConnman& connman)
{
if (deterministicMNManager->IsDeterministicMNsSporkActive())
return;
if(fLiteMode) return; // disable all Dash specific functionality
if (strCommand == NetMsgType::MNANNOUNCE) { //Masternode Broadcast
@ -1001,6 +1167,9 @@ void CMasternodeMan::PushDsegInvs(CNode* pnode, const CMasternode& mn)
void CMasternodeMan::DoFullVerificationStep(CConnman& connman)
{
if (deterministicMNManager->IsDeterministicMNsSporkActive())
return;
if(activeMasternodeInfo.outpoint.IsNull()) return;
if(!masternodeSync.IsSynced()) return;
@ -1078,6 +1247,9 @@ void CMasternodeMan::DoFullVerificationStep(CConnman& connman)
void CMasternodeMan::CheckSameAddr()
{
if (deterministicMNManager->IsDeterministicMNsSporkActive())
return;
if(!masternodeSync.IsSynced() || mapMasternodes.empty()) return;
std::vector<CMasternode*> vBan;
@ -1131,6 +1303,9 @@ void CMasternodeMan::CheckSameAddr()
bool CMasternodeMan::SendVerifyRequest(const CAddress& addr, const std::vector<const CMasternode*>& vSortedByAddr, CConnman& connman)
{
if (deterministicMNManager->IsDeterministicMNsSporkActive())
return false;
if(netfulfilledman.HasFulfilledRequest(addr, strprintf("%s", NetMsgType::MNVERIFY)+"-request")) {
// we already asked for verification, not a good idea to do this too often, skip it
LogPrint("masternode", "CMasternodeMan::SendVerifyRequest -- too many requests, skipping... addr=%s\n", addr.ToString());
@ -1152,6 +1327,9 @@ void CMasternodeMan::ProcessPendingMnvRequests(CConnman& connman)
{
LOCK(cs_mapPendingMNV);
if (deterministicMNManager->IsDeterministicMNsSporkActive())
return;
std::map<CService, std::pair<int64_t, CMasternodeVerification> >::iterator itPendingMNV = mapPendingMNV.begin();
while (itPendingMNV != mapPendingMNV.end()) {
@ -1181,6 +1359,9 @@ void CMasternodeMan::SendVerifyReply(CNode* pnode, CMasternodeVerification& mnv,
{
AssertLockHeld(cs_main);
if (deterministicMNManager->IsDeterministicMNsSporkActive())
return;
// only masternodes can sign this, why would someone ask regular node?
if(!fMasternodeMode) {
// do not ban, malicious node might be using my IP
@ -1238,6 +1419,9 @@ void CMasternodeMan::ProcessVerifyReply(CNode* pnode, CMasternodeVerification& m
{
AssertLockHeld(cs_main);
if (deterministicMNManager->IsDeterministicMNsSporkActive())
return;
std::string strError;
// did we even ask for it? if that's the case we should have matching fulfilled request
@ -1374,6 +1558,9 @@ void CMasternodeMan::ProcessVerifyBroadcast(CNode* pnode, const CMasternodeVerif
{
AssertLockHeld(cs_main);
if (deterministicMNManager->IsDeterministicMNsSporkActive())
return;
std::string strError;
if(mapSeenMasternodeVerification.find(mnv.GetHash()) != mapSeenMasternodeVerification.end()) {
@ -1495,12 +1682,17 @@ std::string CMasternodeMan::ToString() const
{
std::ostringstream info;
if (deterministicMNManager->IsDeterministicMNsSporkActive()) {
info << "Masternodes: masternode object count: " << (int)mapMasternodes.size() <<
", deterministic masternode count: " << deterministicMNManager->GetListAtChainTip().size() <<
", nDsqCount: " << (int)nDsqCount;
} else {
info << "Masternodes: " << (int)mapMasternodes.size() <<
", peers who asked us for Masternode list: " << (int)mAskedUsForMasternodeList.size() <<
", peers we asked for Masternode list: " << (int)mWeAskedForMasternodeList.size() <<
", entries in Masternode list we asked for: " << (int)mWeAskedForMasternodeListEntry.size() <<
", nDsqCount: " << (int)nDsqCount;
}
return info.str();
}
@ -1509,6 +1701,9 @@ bool CMasternodeMan::CheckMnbAndUpdateMasternodeList(CNode* pfrom, CMasternodeBr
// Need to lock cs_main here to ensure consistent locking order because the SimpleCheck call below locks cs_main
LOCK(cs_main);
if (deterministicMNManager->IsDeterministicMNsSporkActive())
return false;
{
LOCK(cs);
nDos = 0;
@ -1621,6 +1816,8 @@ void CMasternodeMan::UpdateLastPaid(const CBlockIndex* pindex)
void CMasternodeMan::UpdateLastSentinelPingTime()
{
LOCK(cs);
if (deterministicMNManager->IsDeterministicMNsSporkActive())
return;
nLastSentinelPingTime = GetTime();
}
@ -1653,6 +1850,8 @@ void CMasternodeMan::RemoveGovernanceObject(uint256 nGovernanceObjectHash)
void CMasternodeMan::CheckMasternode(const CKeyID& keyIDOperator, bool fForce)
{
LOCK2(cs_main, cs);
if (deterministicMNManager->IsDeterministicMNsSporkActive())
return;
for (auto& mnpair : mapMasternodes) {
if (mnpair.second.keyIDOperator == keyIDOperator) {
mnpair.second.Check(fForce);
@ -1671,6 +1870,8 @@ bool CMasternodeMan::IsMasternodePingedWithin(const COutPoint& outpoint, int nSe
void CMasternodeMan::SetMasternodeLastPing(const COutPoint& outpoint, const CMasternodePing& mnp)
{
LOCK(cs);
if (deterministicMNManager->IsDeterministicMNsSporkActive())
return;
CMasternode* pmn = Find(outpoint);
if(!pmn) {
return;
@ -1693,6 +1894,9 @@ void CMasternodeMan::UpdatedBlockTip(const CBlockIndex *pindex)
nCachedBlockHeight = pindex->nHeight;
LogPrint("masternode", "CMasternodeMan::UpdatedBlockTip -- nCachedBlockHeight=%d\n", nCachedBlockHeight);
AddDeterministicMasternodes();
RemoveNonDeterministicMasternodes();
CheckSameAddr();
if(fMasternodeMode) {
@ -1742,7 +1946,7 @@ void CMasternodeMan::WarnMasternodeDaemonUpdates()
fWarned = true;
}
void CMasternodeMan::NotifyMasternodeUpdates(CConnman& connman)
void CMasternodeMan::NotifyMasternodeUpdates(CConnman& connman, bool forceAddedChecks, bool forceRemovedChecks)
{
// Avoid double locking
bool fMasternodesAddedLocal = false;
@ -1753,11 +1957,11 @@ void CMasternodeMan::NotifyMasternodeUpdates(CConnman& connman)
fMasternodesRemovedLocal = fMasternodesRemoved;
}
if(fMasternodesAddedLocal) {
if(fMasternodesAddedLocal || forceAddedChecks) {
governance.CheckMasternodeOrphanObjects(connman);
governance.CheckMasternodeOrphanVotes(connman);
}
if(fMasternodesRemovedLocal) {
if(fMasternodesRemovedLocal || forceRemovedChecks) {
governance.UpdateCachesAndClean();
}

View File

@ -149,6 +149,9 @@ public:
/// This is dummy overload to be used for dumping/loading mncache.dat
void CheckAndRemove() {}
void AddDeterministicMasternodes();
void RemoveNonDeterministicMasternodes();
/// Clear Masternode vector
void Clear();
@ -181,7 +184,7 @@ public:
/// Find a random entry
masternode_info_t FindRandomNotInVec(const std::vector<COutPoint> &vecToExclude, int nProtocolVersion = -1);
std::map<COutPoint, CMasternode> GetFullMasternodeMap() { return mapMasternodes; }
std::map<COutPoint, CMasternode> GetFullMasternodeMap();
bool GetMasternodeRanks(rank_pair_vec_t& vecMasternodeRanksRet, int nBlockHeight = -1, int nMinProtocol = 0);
bool GetMasternodeRank(const COutPoint &outpoint, int& nRankRet, int nBlockHeight = -1, int nMinProtocol = 0);
@ -243,7 +246,7 @@ public:
* Called to notify CGovernanceManager that the masternode index has been updated.
* Must be called while not holding the CMasternodeMan::cs mutex
*/
void NotifyMasternodeUpdates(CConnman& connman);
void NotifyMasternodeUpdates(CConnman& connman, bool forceAddedChecks = false, bool forceRemovedChecks = false);
void DoMaintenance(CConnman &connman);
};

View File

@ -1201,18 +1201,22 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
}
if (!push && inv.type == MSG_MASTERNODE_ANNOUNCE) {
if (!deterministicMNManager->IsDeterministicMNsSporkActive()) {
if (mnodeman.mapSeenMasternodeBroadcast.count(inv.hash)) {
connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::MNANNOUNCE, mnodeman.mapSeenMasternodeBroadcast[inv.hash].second));
push = true;
}
}
}
if (!push && inv.type == MSG_MASTERNODE_PING) {
if (!deterministicMNManager->IsDeterministicMNsSporkActive()) {
if (mnodeman.mapSeenMasternodePing.count(inv.hash)) {
connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::MNPING, mnodeman.mapSeenMasternodePing[inv.hash]));
push = true;
}
}
}
if (!push && inv.type == MSG_DSTX) {
CDarksendBroadcastTx dstx = CPrivateSend::GetDSTX(inv.hash);

View File

@ -19,6 +19,10 @@
#include "rpc/server.h"
#include "util.h"
#include "utilmoneystr.h"
#include "txmempool.h"
#include "evo/specialtx.h"
#include "evo/deterministicmns.h"
#include <fstream>
#include <iomanip>
@ -327,6 +331,8 @@ UniValue masternode_start_alias(const JSONRPCRequest& request)
{
if(request.fHelp || request.params.size() < 2)
masternode_start_alias_help();
if (deterministicMNManager->IsDeterministicMNsSporkActive())
throw JSONRPCError(RPC_MISC_ERROR, "start-alias is not supported when deterministic masternode list is active (DIP3)");
if (!EnsureWalletIsAvailable(request.fHelp))
return NullUniValue;
@ -427,6 +433,8 @@ UniValue masternode_start_all(const JSONRPCRequest& request)
{
if(request.fHelp)
masternode_start_all_help();
if (deterministicMNManager->IsDeterministicMNsSporkActive())
throw JSONRPCError(RPC_MISC_ERROR, strprintf("start-all is not supported when deterministic masternode list is active (DIP3)"));
if (!EnsureWalletIsAvailable(request.fHelp))
return NullUniValue;
@ -569,6 +577,91 @@ UniValue masternode_genkey(const JSONRPCRequest& request)
return CBitcoinSecret(secret).ToString();
}
void masternode_info_help()
{
throw std::runtime_error(
"masternode info \"proTxHash\"\n"
"Print masternode information of specified masternode\n"
"\nArguments:\n"
"1. proTxHash (string, required) proTxHash of masternode\n"
);
}
UniValue masternode_info(const JSONRPCRequest& request)
{
if(request.fHelp || request.params.size() != 2)
masternode_info_help();
std::string strProTxHash = request.params[1].get_str();
if (!IsHex(strProTxHash) || strProTxHash.size() != 64)
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid \"proTxHash\"");
uint256 proTxHash;
proTxHash.SetHex(strProTxHash);
CTransactionRef tx;
uint256 hashBlock;
bool fromMempool = false;
auto dmn = deterministicMNManager->GetListAtChainTip().GetMN(proTxHash);
if (!dmn) {
tx = mempool.get(proTxHash);
if (tx) {
fromMempool = true;
if (tx->nVersion < 3 || tx->nType != TRANSACTION_PROVIDER_REGISTER)
throw JSONRPCError(RPC_INVALID_PARAMETER, "TX is not a ProTx");
CProRegTx tmpProTx;
if (!GetTxPayload(*tx, tmpProTx))
throw JSONRPCError(RPC_INVALID_PARAMETER, "TX is not a valid ProTx");
dmn = std::make_shared<CDeterministicMN>(tx->GetHash(), tmpProTx);
} else {
throw JSONRPCError(RPC_INVALID_PARAMETER, "ProTx not found");
}
} else {
if (!GetTransaction(proTxHash, tx, Params().GetConsensus(), hashBlock, true))
throw JSONRPCError(RPC_INVALID_PARAMETER, "Parent transaction of ProTx not found");
if (!mapBlockIndex.count(hashBlock))
throw JSONRPCError(RPC_INVALID_PARAMETER, "Parent transaction of ProTx not found");
}
UniValue obj(UniValue::VOBJ);
UniValue stateObj;
dmn->pdmnState->ToJson(stateObj);
obj.push_back(Pair("state", stateObj));
if (!hashBlock.IsNull()) {
UniValue blockObj(UniValue::VOBJ);
blockObj.push_back(Pair("blockhash", hashBlock.GetHex()));
LOCK(cs_main);
BlockMap::iterator mi = mapBlockIndex.find(hashBlock);
if (mi != mapBlockIndex.end() && (*mi).second) {
CBlockIndex *pindex = (*mi).second;
if (chainActive.Contains(pindex)) {
blockObj.push_back(Pair("height", pindex->nHeight));
blockObj.push_back(Pair("confirmations", 1 + chainActive.Height() - pindex->nHeight));
blockObj.push_back(Pair("time", pindex->GetBlockTime()));
blockObj.push_back(Pair("blocktime", pindex->GetBlockTime()));
} else {
blockObj.push_back(Pair("height", -1));
blockObj.push_back(Pair("confirmations", 0));
}
}
obj.push_back(Pair("block", blockObj));
if (GetUTXOHeight(COutPoint(proTxHash, dmn->nCollateralIndex)) < 0) {
obj.push_back(Pair("isSpent", true));
}
} else {
obj.push_back(Pair("fromMempool", true));
}
return obj;
}
void masternode_list_conf_help()
{
throw std::runtime_error(
@ -622,15 +715,29 @@ UniValue masternode_status(const JSONRPCRequest& request)
UniValue mnObj(UniValue::VOBJ);
// keep compatibility with legacy status for now (might get deprecated/removed later)
mnObj.push_back(Pair("outpoint", activeMasternodeInfo.outpoint.ToStringShort()));
mnObj.push_back(Pair("service", activeMasternodeInfo.service.ToString()));
if (deterministicMNManager->IsDeterministicMNsSporkActive()) {
auto dmn = activeMasternodeManager->GetDMN();
if (dmn) {
mnObj.push_back(Pair("proTxHash", dmn->proTxHash.ToString()));
mnObj.push_back(Pair("collateralIndex", (int)dmn->nCollateralIndex));
UniValue stateObj;
dmn->pdmnState->ToJson(stateObj);
mnObj.push_back(Pair("dmnState", stateObj));
}
mnObj.push_back(Pair("state", activeMasternodeManager->GetStateString()));
mnObj.push_back(Pair("status", activeMasternodeManager->GetStatus()));
} else {
CMasternode mn;
if(mnodeman.Get(activeMasternodeInfo.outpoint, mn)) {
mnObj.push_back(Pair("payee", CBitcoinAddress(mn.keyIDCollateralAddress).ToString()));
}
mnObj.push_back(Pair("status", legacyActiveMasternodeManager.GetStatus()));
}
return mnObj;
}
@ -786,6 +893,8 @@ UniValue masternode(const JSONRPCRequest& request)
#endif // ENABLE_WALLET
} else if (strCommand == "genkey") {
return masternode_genkey(request);
} else if (strCommand == "info") {
return masternode_info(request);
} else if (strCommand == "list-conf") {
return masternode_list_conf(request);
#ifdef ENABLE_WALLET