// Copyright (c) 2014-2016 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) { 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("masterndoe", "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(!GetLocal(service)) { nState = ACTIVE_MASTERNODE_NOT_CAPABLE; strNotCapableReason = "Can't detect external address. Please consider using the externalip configuration option if problem persists."; 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::ManageState -- 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", 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 = "Specified IP doesn't match our external address."; LogPrintf("CActiveMasternode::ManageStateRemote -- %s: %s\n", GetStateString(), strNotCapableReason); return; } vin = infoMn.vin; service = infoMn.addr; fPingerEnabled = true; if(((infoMn.nActiveState == CMasternode::MASTERNODE_ENABLED) || (infoMn.nActiveState == CMasternode::MASTERNODE_PRE_ENABLED) || (infoMn.nActiveState == CMasternode::MASTERNODE_WATCHDOG_EXPIRED))) { if(nState != ACTIVE_MASTERNODE_STARTED) { LogPrintf("CActiveMasternode::ManageStateRemote -- STARTED!\n"); } nState = ACTIVE_MASTERNODE_STARTED; } else { nState = ACTIVE_MASTERNODE_NOT_CAPABLE; strNotCapableReason = strprintf("Masternode in %s state", CMasternode::StateToString(infoMn.nActiveState)); LogPrintf("CActiveMasternode::ManageStateRemote -- %s: %s\n", GetStateString(), strNotCapableReason); } } 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; } //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(); fPingerEnabled = true; nState = ACTIVE_MASTERNODE_STARTED; } }