#include "protocol.h" #include "activemasternode.h" #include "masternodeman.h" #include "masternode.h" #include "masternodeconfig.h" #include // // Bootup the Masternode, look for a 1000DRK input and register on the network // void CActiveMasternode::ManageStatus() { std::string errorMessage; if(!fMasterNode) return; if (fDebug) LogPrintf("CActiveMasternode::ManageStatus() - Begin\n"); //need correct adjusted time to send ping bool fIsInitialDownload = IsInitialBlockDownload(); if(fIsInitialDownload) { status = MASTERNODE_SYNC_IN_PROCESS; LogPrintf("CActiveMasternode::ManageStatus() - Sync in progress. Must wait until sync is complete to start Masternode.\n"); return; } if(status == MASTERNODE_INPUT_TOO_NEW || status == MASTERNODE_NOT_CAPABLE || status == MASTERNODE_SYNC_IN_PROCESS){ status = MASTERNODE_NOT_PROCESSED; } if(status == MASTERNODE_NOT_PROCESSED) { if(strMasterNodeAddr.empty()) { if(!GetLocal(service)) { notCapableReason = "Can't detect external address. Please use the Masternodeaddr configuration option."; status = MASTERNODE_NOT_CAPABLE; LogPrintf("CActiveMasternode::ManageStatus() - not capable: %s\n", notCapableReason.c_str()); return; } } else { service = CService(strMasterNodeAddr); } LogPrintf("CActiveMasternode::ManageStatus() - Checking inbound connection to '%s'\n", service.ToString().c_str()); if(Params().NetworkID() == CBaseChainParams::MAIN) { if(service.GetPort() != 9999) { notCapableReason = "Invalid port: " + boost::lexical_cast(service.GetPort()) + " - only 9999 is supported on mainnet."; status = MASTERNODE_NOT_CAPABLE; LogPrintf("CActiveMasternode::ManageStatus() - not capable: %s\n", notCapableReason.c_str()); return; } } else if(service.GetPort() == 9999) { notCapableReason = "Invalid port: " + boost::lexical_cast(service.GetPort()) + " - 9999 is only supported on mainnet."; status = MASTERNODE_NOT_CAPABLE; LogPrintf("CActiveMasternode::ManageStatus() - not capable: %s\n", notCapableReason.c_str()); return; } if(!ConnectNode((CAddress)service, service.ToString().c_str())){ notCapableReason = "Could not connect to " + service.ToString(); status = MASTERNODE_NOT_CAPABLE; LogPrintf("CActiveMasternode::ManageStatus() - not capable: %s\n", notCapableReason.c_str()); return; } if(pwalletMain->IsLocked()){ notCapableReason = "Wallet is locked."; status = MASTERNODE_NOT_CAPABLE; LogPrintf("CActiveMasternode::ManageStatus() - not capable: %s\n", notCapableReason.c_str()); return; } // Set defaults status = MASTERNODE_NOT_CAPABLE; notCapableReason = "Unknown. Check debug.log for more information."; // Choose coins to use CPubKey pubKeyCollateralAddress; CKey keyCollateralAddress; if(GetMasterNodeVin(vin, pubKeyCollateralAddress, keyCollateralAddress)) { if(GetInputAge(vin) < MASTERNODE_MIN_CONFIRMATIONS){ notCapableReason = "Input must have least " + boost::lexical_cast(MASTERNODE_MIN_CONFIRMATIONS) + " confirmations - " + boost::lexical_cast(GetInputAge(vin)) + " confirmations"; LogPrintf("CActiveMasternode::ManageStatus() - %s\n", notCapableReason.c_str()); status = MASTERNODE_INPUT_TOO_NEW; return; } LogPrintf("CActiveMasternode::ManageStatus() - Is capable master node!\n"); status = MASTERNODE_IS_CAPABLE; notCapableReason = ""; pwalletMain->LockCoin(vin.prevout); // send to all nodes CPubKey pubKeyMasternode; CKey keyMasternode; if(!darkSendSigner.SetKey(strMasterNodePrivKey, errorMessage, keyMasternode, pubKeyMasternode)) { LogPrintf("Register::ManageStatus() - Error upon calling SetKey: %s\n", errorMessage.c_str()); return; } if(!Register(vin, service, keyCollateralAddress, pubKeyCollateralAddress, keyMasternode, pubKeyMasternode, errorMessage)) { LogPrintf("CActiveMasternode::ManageStatus() - Error on Register: %s\n", errorMessage.c_str()); } return; } else { notCapableReason = "Could not find suitable coins!"; LogPrintf("CActiveMasternode::ManageStatus() - %s\n", notCapableReason.c_str()); } } //send to all peers if(!Mnping(errorMessage)) { LogPrintf("CActiveMasternode::ManageStatus() - Error on Ping: %s\n", errorMessage.c_str()); } } bool CActiveMasternode::Mnping(std::string& errorMessage) { if(status != MASTERNODE_IS_CAPABLE && status != MASTERNODE_REMOTELY_ENABLED) { errorMessage = "Masternode is not in a running status"; LogPrintf("CActiveMasternode::Mnping() - Error: %s\n", errorMessage.c_str()); return false; } CPubKey pubKeyMasternode; CKey keyMasternode; if(!darkSendSigner.SetKey(strMasterNodePrivKey, errorMessage, keyMasternode, pubKeyMasternode)) { LogPrintf("CActiveMasternode::Mnping() - Error upon calling SetKey: %s\n", errorMessage.c_str()); return false; } return Mnping(vin, service, keyMasternode, pubKeyMasternode, errorMessage); } bool CActiveMasternode::Mnping(CTxIn vin, CService service, CKey keyMasternode, CPubKey pubKeyMasternode, std::string &retErrorMessage) { //send to all peers LogPrintf("CActiveMasternode::Mnping() - RelayMasternodeEntryPing vin = %s\n", vin.ToString().c_str()); CMasternodePing mnp(vin); if(!mnp.Sign(keyMasternode, pubKeyMasternode)) { return false; } // Update Last Seen timestamp in Masternode list CMasternode* pmn = mnodeman.Find(vin); if(pmn != NULL) { pmn->UpdateLastSeen(); } else { // Seems like we are trying to send a ping while the Masternode is not registered in the network retErrorMessage = "Darksend Masternode List doesn't include our Masternode, shutting down Masternode pinging service! " + vin.ToString(); LogPrintf("CActiveMasternode::Mnping() - Error: %s\n", retErrorMessage.c_str()); status = MASTERNODE_NOT_CAPABLE; notCapableReason = retErrorMessage; return false; } mapSeenMasternodePing[mnp.GetHash()] = mnp; mnp.Relay(); return true; } bool CActiveMasternode::Register(std::string strService, std::string strKeyMasternode, std::string txHash, std::string strOutputIndex, std::string& errorMessage) { CTxIn vin; CPubKey pubKeyCollateralAddress; CKey keyCollateralAddress; CPubKey pubKeyMasternode; CKey keyMasternode; if(!darkSendSigner.SetKey(strKeyMasternode, errorMessage, keyMasternode, pubKeyMasternode)) { LogPrintf("CActiveMasternode::Register() - Error upon calling SetKey: %s\n", errorMessage.c_str()); return false; } if(!GetMasterNodeVin(vin, pubKeyCollateralAddress, keyCollateralAddress, txHash, strOutputIndex)) { errorMessage = "could not allocate vin"; LogPrintf("CActiveMasternode::Register() - Error: %s\n", errorMessage.c_str()); return false; } return Register(vin, CService(strService), keyCollateralAddress, pubKeyCollateralAddress, keyMasternode, pubKeyMasternode, errorMessage); } bool CActiveMasternode::Register(CTxIn vin, CService service, CKey keyCollateralAddress, CPubKey pubKeyCollateralAddress, CKey keyMasternode, CPubKey pubKeyMasternode, std::string &retErrorMessage) { CMasternode* pmn = mnodeman.Find(vin); if(pmn == NULL) { LogPrintf("CActiveMasternode::Register() - Adding to Masternode list service: %s - vin: %s\n", service.ToString().c_str(), vin.ToString().c_str()); CMasternodeBroadcast mnb(service, vin, pubKeyCollateralAddress, pubKeyMasternode, PROTOCOL_VERSION); if(!mnb.Sign(keyCollateralAddress)){ //send to all peers LogPrintf("CActiveMasternode::Register() - Failed to sign %s\n", vin.ToString().c_str()); return false; } CMasternode mn(mnb); mn.UpdateLastSeen(); mnodeman.Add(mn); } if(pmn == NULL) pmn = mnodeman.Find(vin); if(pmn != NULL) { CMasternodeBroadcast mnb(*pmn); mapSeenMasternodeBroadcast[mnb.GetHash()] = mnb; //send to all peers LogPrintf("CActiveMasternode::Register() - RelayElectionEntry vin = %s\n", vin.ToString().c_str()); mnb.Relay(false); } return true; } bool CActiveMasternode::GetMasterNodeVin(CTxIn& vin, CPubKey& pubkey, CKey& secretKey) { return GetMasterNodeVin(vin, pubkey, secretKey, "", ""); } bool CActiveMasternode::GetMasterNodeVin(CTxIn& vin, CPubKey& pubkey, CKey& secretKey, std::string strTxHash, std::string strOutputIndex) { CScript pubScript; // Find possible candidates vector possibleCoins = SelectCoinsMasternode(); COutput *selectedOutput; // Find the vin if(!strTxHash.empty()) { // Let's find it uint256 txHash(strTxHash); int outputIndex = boost::lexical_cast(strOutputIndex); bool found = false; BOOST_FOREACH(COutput& out, possibleCoins) { if(out.tx->GetHash() == txHash && out.i == outputIndex) { selectedOutput = &out; found = true; break; } } if(!found) { LogPrintf("CActiveMasternode::GetMasterNodeVin - Could not locate valid vin\n"); return false; } } else { // No output specified, Select the first one if(possibleCoins.size() > 0) { selectedOutput = &possibleCoins[0]; } else { LogPrintf("CActiveMasternode::GetMasterNodeVin - Could not locate specified vin from possible list\n"); return false; } } // At this point we have a selected output, retrieve the associated info return GetVinFromOutput(*selectedOutput, vin, pubkey, secretKey); } // Extract Masternode vin information from output bool CActiveMasternode::GetVinFromOutput(COutput out, CTxIn& vin, CPubKey& pubkey, CKey& secretKey) { CScript pubScript; vin = CTxIn(out.tx->GetHash(),out.i); pubScript = out.tx->vout[out.i].scriptPubKey; // the inputs PubKey CTxDestination address1; ExtractDestination(pubScript, address1); CBitcoinAddress address2(address1); CKeyID keyID; if (!address2.GetKeyID(keyID)) { LogPrintf("CActiveMasternode::GetMasterNodeVin - Address does not refer to a key\n"); return false; } if (!pwalletMain->GetKey(keyID, secretKey)) { LogPrintf ("CActiveMasternode::GetMasterNodeVin - Private key for address is not known\n"); return false; } pubkey = secretKey.GetPubKey(); return true; } // get all possible outputs for running Masternode vector CActiveMasternode::SelectCoinsMasternode() { vector vCoins; vector filteredCoins; vector confLockedCoins; // Temporary unlock MN coins from masternode.conf if(GetBoolArg("-mnconflock", true)) { uint256 mnTxHash; BOOST_FOREACH(CMasternodeConfig::CMasternodeEntry mne, masternodeConfig.getEntries()) { mnTxHash.SetHex(mne.getTxHash()); COutPoint outpoint = COutPoint(mnTxHash, boost::lexical_cast(mne.getOutputIndex())); confLockedCoins.push_back(outpoint); pwalletMain->UnlockCoin(outpoint); } } // Retrieve all possible outputs pwalletMain->AvailableCoins(vCoins); // Lock MN coins from masternode.conf back if they where temporary unlocked if(!confLockedCoins.empty()) { BOOST_FOREACH(COutPoint outpoint, confLockedCoins) pwalletMain->LockCoin(outpoint); } // Filter BOOST_FOREACH(const COutput& out, vCoins) { if(out.tx->vout[out.i].nValue == 1000*COIN) { //exactly filteredCoins.push_back(out); } } return filteredCoins; } // when starting a Masternode, this can enable to run as a hot wallet with no funds bool CActiveMasternode::EnableHotColdMasterNode(CTxIn& newVin, CService& newService) { if(!fMasterNode) return false; status = MASTERNODE_REMOTELY_ENABLED; //The values below are needed for signing mnping messages going forward this->vin = newVin; this->service = newService; LogPrintf("CActiveMasternode::EnableHotColdMasterNode() - Enabled! You may shut down the cold daemon.\n"); return true; }