mirror of
https://github.com/dashpay/dash.git
synced 2024-12-28 13:32:47 +01:00
317 lines
13 KiB
C++
317 lines
13 KiB
C++
// Copyright (c) 2014-2017 The Dash Core developers
|
|
// Distributed under the MIT software license, see the accompanying
|
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
|
|
#include "activemasternode.h"
|
|
#include "masternode.h"
|
|
#include "masternode-sync.h"
|
|
#include "masternodeman.h"
|
|
#include "protocol.h"
|
|
|
|
extern CWallet* pwalletMain;
|
|
|
|
// Keep track of the active Masternode
|
|
CActiveMasternode activeMasternode;
|
|
|
|
void CActiveMasternode::ManageState()
|
|
{
|
|
LogPrint("masternode", "CActiveMasternode::ManageState -- Start\n");
|
|
if(!fMasterNode) {
|
|
LogPrint("masternode", "CActiveMasternode::ManageState -- Not a masternode, returning\n");
|
|
return;
|
|
}
|
|
|
|
if(Params().NetworkIDString() != CBaseChainParams::REGTEST && !masternodeSync.IsBlockchainSynced()) {
|
|
nState = ACTIVE_MASTERNODE_SYNC_IN_PROCESS;
|
|
LogPrintf("CActiveMasternode::ManageState -- %s: %s\n", GetStateString(), GetStatus());
|
|
return;
|
|
}
|
|
|
|
if(nState == ACTIVE_MASTERNODE_SYNC_IN_PROCESS) {
|
|
nState = ACTIVE_MASTERNODE_INITIAL;
|
|
}
|
|
|
|
LogPrint("masternode", "CActiveMasternode::ManageState -- status = %s, type = %s, pinger enabled = %d\n", GetStatus(), GetTypeString(), fPingerEnabled);
|
|
|
|
if(eType == MASTERNODE_UNKNOWN) {
|
|
ManageStateInitial();
|
|
}
|
|
|
|
if(eType == MASTERNODE_REMOTE) {
|
|
ManageStateRemote();
|
|
} else if(eType == MASTERNODE_LOCAL) {
|
|
// Try Remote Start first so the started local masternode can be restarted without recreate masternode broadcast.
|
|
ManageStateRemote();
|
|
if(nState != ACTIVE_MASTERNODE_STARTED)
|
|
ManageStateLocal();
|
|
}
|
|
|
|
SendMasternodePing();
|
|
}
|
|
|
|
std::string CActiveMasternode::GetStateString() const
|
|
{
|
|
switch (nState) {
|
|
case ACTIVE_MASTERNODE_INITIAL: return "INITIAL";
|
|
case ACTIVE_MASTERNODE_SYNC_IN_PROCESS: return "SYNC_IN_PROCESS";
|
|
case ACTIVE_MASTERNODE_INPUT_TOO_NEW: return "INPUT_TOO_NEW";
|
|
case ACTIVE_MASTERNODE_NOT_CAPABLE: return "NOT_CAPABLE";
|
|
case ACTIVE_MASTERNODE_STARTED: return "STARTED";
|
|
default: return "UNKNOWN";
|
|
}
|
|
}
|
|
|
|
std::string CActiveMasternode::GetStatus() const
|
|
{
|
|
switch (nState) {
|
|
case ACTIVE_MASTERNODE_INITIAL: return "Node just started, not yet activated";
|
|
case ACTIVE_MASTERNODE_SYNC_IN_PROCESS: return "Sync in progress. Must wait until sync is complete to start Masternode";
|
|
case ACTIVE_MASTERNODE_INPUT_TOO_NEW: return strprintf("Masternode input must have at least %d confirmations", Params().GetConsensus().nMasternodeMinimumConfirmations);
|
|
case ACTIVE_MASTERNODE_NOT_CAPABLE: return "Not capable masternode: " + strNotCapableReason;
|
|
case ACTIVE_MASTERNODE_STARTED: return "Masternode successfully started";
|
|
default: return "Unknown";
|
|
}
|
|
}
|
|
|
|
std::string CActiveMasternode::GetTypeString() const
|
|
{
|
|
std::string strType;
|
|
switch(eType) {
|
|
case MASTERNODE_UNKNOWN:
|
|
strType = "UNKNOWN";
|
|
break;
|
|
case MASTERNODE_REMOTE:
|
|
strType = "REMOTE";
|
|
break;
|
|
case MASTERNODE_LOCAL:
|
|
strType = "LOCAL";
|
|
break;
|
|
default:
|
|
strType = "UNKNOWN";
|
|
break;
|
|
}
|
|
return strType;
|
|
}
|
|
|
|
bool CActiveMasternode::SendMasternodePing()
|
|
{
|
|
if(!fPingerEnabled) {
|
|
LogPrint("masternode", "CActiveMasternode::SendMasternodePing -- %s: masternode ping service is disabled, skipping...\n", GetStateString());
|
|
return false;
|
|
}
|
|
|
|
if(!mnodeman.Has(vin)) {
|
|
strNotCapableReason = "Masternode not in masternode list";
|
|
nState = ACTIVE_MASTERNODE_NOT_CAPABLE;
|
|
LogPrintf("CActiveMasternode::SendMasternodePing -- %s: %s\n", GetStateString(), strNotCapableReason);
|
|
return false;
|
|
}
|
|
|
|
CMasternodePing mnp(vin);
|
|
if(!mnp.Sign(keyMasternode, pubKeyMasternode)) {
|
|
LogPrintf("CActiveMasternode::SendMasternodePing -- ERROR: Couldn't sign Masternode Ping\n");
|
|
return false;
|
|
}
|
|
|
|
// Update lastPing for our masternode in Masternode list
|
|
if(mnodeman.IsMasternodePingedWithin(vin, MASTERNODE_MIN_MNP_SECONDS, mnp.sigTime)) {
|
|
LogPrintf("CActiveMasternode::SendMasternodePing -- Too early to send Masternode Ping\n");
|
|
return false;
|
|
}
|
|
|
|
mnodeman.SetMasternodeLastPing(vin, mnp);
|
|
|
|
LogPrintf("CActiveMasternode::SendMasternodePing -- Relaying ping, collateral=%s\n", vin.ToString());
|
|
mnp.Relay();
|
|
|
|
return true;
|
|
}
|
|
|
|
void CActiveMasternode::ManageStateInitial()
|
|
{
|
|
LogPrint("masternode", "CActiveMasternode::ManageStateInitial -- status = %s, type = %s, pinger enabled = %d\n", GetStatus(), GetTypeString(), fPingerEnabled);
|
|
|
|
// Check that our local network configuration is correct
|
|
if (!fListen) {
|
|
// listen option is probably overwritten by smth else, no good
|
|
nState = ACTIVE_MASTERNODE_NOT_CAPABLE;
|
|
strNotCapableReason = "Masternode must accept connections from outside. Make sure listen configuration option is not overwritten by some another parameter.";
|
|
LogPrintf("CActiveMasternode::ManageStateInitial -- %s: %s\n", GetStateString(), strNotCapableReason);
|
|
return;
|
|
}
|
|
|
|
bool fFoundLocal = false;
|
|
{
|
|
LOCK(cs_vNodes);
|
|
|
|
// First try to find whatever local address is specified by externalip option
|
|
fFoundLocal = GetLocal(service) && CMasternode::IsValidNetAddr(service);
|
|
if(!fFoundLocal) {
|
|
// nothing and no live connections, can't do anything for now
|
|
if (vNodes.empty()) {
|
|
nState = ACTIVE_MASTERNODE_NOT_CAPABLE;
|
|
strNotCapableReason = "Can't detect valid external address. Will retry when there are some connections available.";
|
|
LogPrintf("CActiveMasternode::ManageStateInitial -- %s: %s\n", GetStateString(), strNotCapableReason);
|
|
return;
|
|
}
|
|
// We have some peers, let's try to find our local address from one of them
|
|
BOOST_FOREACH(CNode* pnode, vNodes) {
|
|
if (pnode->fSuccessfullyConnected && pnode->addr.IsIPv4()) {
|
|
fFoundLocal = GetLocal(service, &pnode->addr) && CMasternode::IsValidNetAddr(service);
|
|
if(fFoundLocal) break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if(!fFoundLocal) {
|
|
nState = ACTIVE_MASTERNODE_NOT_CAPABLE;
|
|
strNotCapableReason = "Can't detect valid external address. Please consider using the externalip configuration option if problem persists. Make sure to use IPv4 address only.";
|
|
LogPrintf("CActiveMasternode::ManageStateInitial -- %s: %s\n", GetStateString(), strNotCapableReason);
|
|
return;
|
|
}
|
|
|
|
int mainnetDefaultPort = Params(CBaseChainParams::MAIN).GetDefaultPort();
|
|
if(Params().NetworkIDString() == CBaseChainParams::MAIN) {
|
|
if(service.GetPort() != mainnetDefaultPort) {
|
|
nState = ACTIVE_MASTERNODE_NOT_CAPABLE;
|
|
strNotCapableReason = strprintf("Invalid port: %u - only %d is supported on mainnet.", service.GetPort(), mainnetDefaultPort);
|
|
LogPrintf("CActiveMasternode::ManageStateInitial -- %s: %s\n", GetStateString(), strNotCapableReason);
|
|
return;
|
|
}
|
|
} else if(service.GetPort() == mainnetDefaultPort) {
|
|
nState = ACTIVE_MASTERNODE_NOT_CAPABLE;
|
|
strNotCapableReason = strprintf("Invalid port: %u - %d is only supported on mainnet.", service.GetPort(), mainnetDefaultPort);
|
|
LogPrintf("CActiveMasternode::ManageStateInitial -- %s: %s\n", GetStateString(), strNotCapableReason);
|
|
return;
|
|
}
|
|
|
|
LogPrintf("CActiveMasternode::ManageStateInitial -- Checking inbound connection to '%s'\n", service.ToString());
|
|
|
|
if(!ConnectNode((CAddress)service, NULL, true)) {
|
|
nState = ACTIVE_MASTERNODE_NOT_CAPABLE;
|
|
strNotCapableReason = "Could not connect to " + service.ToString();
|
|
LogPrintf("CActiveMasternode::ManageStateInitial -- %s: %s\n", GetStateString(), strNotCapableReason);
|
|
return;
|
|
}
|
|
|
|
// Default to REMOTE
|
|
eType = MASTERNODE_REMOTE;
|
|
|
|
// Check if wallet funds are available
|
|
if(!pwalletMain) {
|
|
LogPrintf("CActiveMasternode::ManageStateInitial -- %s: Wallet not available\n", GetStateString());
|
|
return;
|
|
}
|
|
|
|
if(pwalletMain->IsLocked()) {
|
|
LogPrintf("CActiveMasternode::ManageStateInitial -- %s: Wallet is locked\n", GetStateString());
|
|
return;
|
|
}
|
|
|
|
if(pwalletMain->GetBalance() < 1000*COIN) {
|
|
LogPrintf("CActiveMasternode::ManageStateInitial -- %s: Wallet balance is < 1000 DASH\n", GetStateString());
|
|
return;
|
|
}
|
|
|
|
// Choose coins to use
|
|
CPubKey pubKeyCollateral;
|
|
CKey keyCollateral;
|
|
|
|
// If collateral is found switch to LOCAL mode
|
|
if(pwalletMain->GetMasternodeVinAndKeys(vin, pubKeyCollateral, keyCollateral)) {
|
|
eType = MASTERNODE_LOCAL;
|
|
}
|
|
|
|
LogPrint("masternode", "CActiveMasternode::ManageStateInitial -- End status = %s, type = %s, pinger enabled = %d\n", GetStatus(), GetTypeString(), fPingerEnabled);
|
|
}
|
|
|
|
void CActiveMasternode::ManageStateRemote()
|
|
{
|
|
LogPrint("masternode", "CActiveMasternode::ManageStateRemote -- Start status = %s, type = %s, pinger enabled = %d, pubKeyMasternode.GetID() = %s\n",
|
|
GetStatus(), fPingerEnabled, GetTypeString(), pubKeyMasternode.GetID().ToString());
|
|
|
|
mnodeman.CheckMasternode(pubKeyMasternode);
|
|
masternode_info_t infoMn = mnodeman.GetMasternodeInfo(pubKeyMasternode);
|
|
if(infoMn.fInfoValid) {
|
|
if(infoMn.nProtocolVersion != PROTOCOL_VERSION) {
|
|
nState = ACTIVE_MASTERNODE_NOT_CAPABLE;
|
|
strNotCapableReason = "Invalid protocol version";
|
|
LogPrintf("CActiveMasternode::ManageStateRemote -- %s: %s\n", GetStateString(), strNotCapableReason);
|
|
return;
|
|
}
|
|
if(service != infoMn.addr) {
|
|
nState = ACTIVE_MASTERNODE_NOT_CAPABLE;
|
|
strNotCapableReason = "Broadcasted IP doesn't match our external address. Make sure you issued a new broadcast if IP of this masternode changed recently.";
|
|
LogPrintf("CActiveMasternode::ManageStateRemote -- %s: %s\n", GetStateString(), strNotCapableReason);
|
|
return;
|
|
}
|
|
if(!CMasternode::IsValidStateForAutoStart(infoMn.nActiveState)) {
|
|
nState = ACTIVE_MASTERNODE_NOT_CAPABLE;
|
|
strNotCapableReason = strprintf("Masternode in %s state", CMasternode::StateToString(infoMn.nActiveState));
|
|
LogPrintf("CActiveMasternode::ManageStateRemote -- %s: %s\n", GetStateString(), strNotCapableReason);
|
|
return;
|
|
}
|
|
if(nState != ACTIVE_MASTERNODE_STARTED) {
|
|
LogPrintf("CActiveMasternode::ManageStateRemote -- STARTED!\n");
|
|
vin = infoMn.vin;
|
|
service = infoMn.addr;
|
|
fPingerEnabled = true;
|
|
nState = ACTIVE_MASTERNODE_STARTED;
|
|
}
|
|
}
|
|
else {
|
|
nState = ACTIVE_MASTERNODE_NOT_CAPABLE;
|
|
strNotCapableReason = "Masternode not in masternode list";
|
|
LogPrintf("CActiveMasternode::ManageStateRemote -- %s: %s\n", GetStateString(), strNotCapableReason);
|
|
}
|
|
}
|
|
|
|
void CActiveMasternode::ManageStateLocal()
|
|
{
|
|
LogPrint("masternode", "CActiveMasternode::ManageStateLocal -- status = %s, type = %s, pinger enabled = %d\n", GetStatus(), GetTypeString(), fPingerEnabled);
|
|
if(nState == ACTIVE_MASTERNODE_STARTED) {
|
|
return;
|
|
}
|
|
|
|
// Choose coins to use
|
|
CPubKey pubKeyCollateral;
|
|
CKey keyCollateral;
|
|
|
|
if(pwalletMain->GetMasternodeVinAndKeys(vin, pubKeyCollateral, keyCollateral)) {
|
|
int nInputAge = GetInputAge(vin);
|
|
if(nInputAge < Params().GetConsensus().nMasternodeMinimumConfirmations){
|
|
nState = ACTIVE_MASTERNODE_INPUT_TOO_NEW;
|
|
strNotCapableReason = strprintf(_("%s - %d confirmations"), GetStatus(), nInputAge);
|
|
LogPrintf("CActiveMasternode::ManageStateLocal -- %s: %s\n", GetStateString(), strNotCapableReason);
|
|
return;
|
|
}
|
|
|
|
{
|
|
LOCK(pwalletMain->cs_wallet);
|
|
pwalletMain->LockCoin(vin.prevout);
|
|
}
|
|
|
|
CMasternodeBroadcast mnb;
|
|
std::string strError;
|
|
if(!CMasternodeBroadcast::Create(vin, service, keyCollateral, pubKeyCollateral, keyMasternode, pubKeyMasternode, strError, mnb)) {
|
|
nState = ACTIVE_MASTERNODE_NOT_CAPABLE;
|
|
strNotCapableReason = "Error creating mastenode broadcast: " + strError;
|
|
LogPrintf("CActiveMasternode::ManageStateLocal -- %s: %s\n", GetStateString(), strNotCapableReason);
|
|
return;
|
|
}
|
|
|
|
fPingerEnabled = true;
|
|
nState = ACTIVE_MASTERNODE_STARTED;
|
|
|
|
//update to masternode list
|
|
LogPrintf("CActiveMasternode::ManageStateLocal -- Update Masternode List\n");
|
|
mnodeman.UpdateMasternodeList(mnb);
|
|
mnodeman.NotifyMasternodeUpdates();
|
|
|
|
//send to all peers
|
|
LogPrintf("CActiveMasternode::ManageStateLocal -- Relay broadcast, vin=%s\n", vin.ToString());
|
|
mnb.Relay();
|
|
}
|
|
}
|