#include "core.h" #include "protocol.h" #include "activemasternode.h" #include // // Bootup the masternode, look for a 1000DRK input and register on the network // void CActiveMasternode::ManageStatus() { std::string errorMessage; LogPrintf("CActiveMasternode::ManageStatus() - Begin\n"); if(!fMasterNode) return; //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); } if((Params().NetworkID() == CChainParams::TESTNET && service.GetPort() != 19999) || (!(Params().NetworkID() == CChainParams::TESTNET) && service.GetPort() != 9999)) { notCapableReason = "Invalid port: " + boost::lexical_cast(service.GetPort()) + " -only 9999 or 19999 are supported."; status = MASTERNODE_NOT_CAPABLE; LogPrintf("CActiveMasternode::ManageStatus() - not capable: %s\n", notCapableReason.c_str()); return; } LogPrintf("CActiveMasternode::ManageStatus() - Checking inbound connection to '%s'\n", service.ToString().c_str()); 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."; // Choose coins to use CPubKey pubKeyCollateralAddress; CKey keyCollateralAddress; if(GetMasterNodeVin(vin, pubKeyCollateralAddress, keyCollateralAddress)) { if(GetInputAge(vin) < MASTERNODE_MIN_CONFIRMATIONS){ LogPrintf("CActiveMasternode::ManageStatus() - Input must have least %d confirmations - %d confirmations\n", MASTERNODE_MIN_CONFIRMATIONS, GetInputAge(vin)); 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", errorMessage.c_str()); } return; } else { LogPrintf("CActiveMasternode::ManageStatus() - Could not find suitable coins!\n"); } } //send to all peers if(!Dseep(errorMessage)) { LogPrintf("CActiveMasternode::ManageStatus() - Error on Ping: %s", errorMessage.c_str()); } } // Send stop dseep to network for remote masternode bool CActiveMasternode::StopMasterNode(std::string strService, std::string strKeyMasternode, std::string& errorMessage) { CTxIn vin; CKey keyMasternode; CPubKey pubKeyMasternode; if(!darkSendSigner.SetKey(strKeyMasternode, errorMessage, keyMasternode, pubKeyMasternode)) { LogPrintf("CActiveMasternode::StopMasterNode() - Error: %s\n", errorMessage.c_str()); return false; } return StopMasterNode(vin, CService(strService), keyMasternode, pubKeyMasternode, errorMessage); } // Send stop dseep to network for main masternode bool CActiveMasternode::StopMasterNode(std::string& errorMessage) { if(status != MASTERNODE_IS_CAPABLE && status != MASTERNODE_REMOTELY_ENABLED) { errorMessage = "masternode is not in a running status"; LogPrintf("CActiveMasternode::StopMasterNode() - Error: %s\n", errorMessage.c_str()); return false; } status = MASTERNODE_STOPPED; CPubKey pubKeyMasternode; CKey keyMasternode; if(!darkSendSigner.SetKey(strMasterNodePrivKey, errorMessage, keyMasternode, pubKeyMasternode)) { LogPrintf("Register::ManageStatus() - Error upon calling SetKey: %s\n", errorMessage.c_str()); return false; } return StopMasterNode(vin, service, keyMasternode, pubKeyMasternode, errorMessage); } // Send stop dseep to network for any masternode bool CActiveMasternode::StopMasterNode(CTxIn vin, CService service, CKey keyMasternode, CPubKey pubKeyMasternode, std::string& errorMessage) { pwalletMain->UnlockCoin(vin.prevout); return Dseep(vin, service, keyMasternode, pubKeyMasternode, errorMessage, true); } bool CActiveMasternode::Dseep(std::string& errorMessage) { if(status != MASTERNODE_IS_CAPABLE && status != MASTERNODE_REMOTELY_ENABLED) { errorMessage = "masternode is not in a running status"; LogPrintf("CActiveMasternode::Dseep() - Error: %s\n", errorMessage.c_str()); return false; } CPubKey pubKeyMasternode; CKey keyMasternode; if(!darkSendSigner.SetKey(strMasterNodePrivKey, errorMessage, keyMasternode, pubKeyMasternode)) { LogPrintf("Register::ManageStatus() - Error upon calling SetKey: %s\n", errorMessage.c_str()); return false; } return Dseep(vin, service, keyMasternode, pubKeyMasternode, errorMessage, false); } bool CActiveMasternode::Dseep(CTxIn vin, CService service, CKey keyMasternode, CPubKey pubKeyMasternode, std::string &retErrorMessage, bool stop) { std::string errorMessage; std::vector vchMasterNodeSignature; std::string strMasterNodeSignMessage; int64_t masterNodeSignatureTime = GetAdjustedTime(); std::string strMessage = service.ToString() + boost::lexical_cast(masterNodeSignatureTime) + boost::lexical_cast(stop); if(!darkSendSigner.SignMessage(strMessage, errorMessage, vchMasterNodeSignature, keyMasternode)) { retErrorMessage = "sign message failed: " + errorMessage; LogPrintf("CActiveMasternode::Dseep() - Error: %s\n", retErrorMessage.c_str()); return false; } if(!darkSendSigner.VerifyMessage(pubKeyMasternode, vchMasterNodeSignature, strMessage, errorMessage)) { retErrorMessage = "Verify message failed: " + errorMessage; LogPrintf("CActiveMasternode::Dseep() - Error: %s\n", retErrorMessage.c_str()); return false; } // Update Last Seen timestamp in masternode list bool found = false; BOOST_FOREACH(CMasterNode& mn, darkSendMasterNodes) { //LogPrintf(" -- %s\n", mn.vin.ToString().c_str()); if(mn.vin == vin) { found = true; mn.UpdateLastSeen(); } } if(!found){ // 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::Dseep() - Error: %s\n", retErrorMessage.c_str()); status = MASTERNODE_NOT_CAPABLE; notCapableReason = retErrorMessage; return false; } //send to all peers LogPrintf("CActiveMasternode::Dseep() - SendDarkSendElectionEntryPing vin = %s\n", vin.ToString().c_str()); SendDarkSendElectionEntryPing(vin, vchMasterNodeSignature, masterNodeSignatureTime, stop); 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("Register::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) { std::string errorMessage; std::vector vchMasterNodeSignature; std::string strMasterNodeSignMessage; int64_t masterNodeSignatureTime = GetAdjustedTime(); std::string vchPubKey(pubKeyCollateralAddress.begin(), pubKeyCollateralAddress.end()); std::string vchPubKey2(pubKeyMasternode.begin(), pubKeyMasternode.end()); std::string strMessage = service.ToString() + boost::lexical_cast(masterNodeSignatureTime) + vchPubKey + vchPubKey2 + boost::lexical_cast(PROTOCOL_VERSION); if(!darkSendSigner.SignMessage(strMessage, errorMessage, vchMasterNodeSignature, keyCollateralAddress)) { retErrorMessage = "sign message failed: " + errorMessage; LogPrintf("CActiveMasternode::Register() - Error: %s\n", retErrorMessage.c_str()); return false; } if(!darkSendSigner.VerifyMessage(pubKeyCollateralAddress, vchMasterNodeSignature, strMessage, errorMessage)) { retErrorMessage = "Verify message failed: " + errorMessage; LogPrintf("CActiveMasternode::Register() - Error: %s\n", retErrorMessage.c_str()); return false; } bool found = false; BOOST_FOREACH(CMasterNode& mn, darkSendMasterNodes) if(mn.vin == vin) found = true; if(!found) { LogPrintf("CActiveMasternode::Register() - Adding to masternode list service: %s - vin: %s\n", service.ToString().c_str(), vin.ToString().c_str()); CMasterNode mn(service, vin, pubKeyCollateralAddress, vchMasterNodeSignature, masterNodeSignatureTime, pubKeyMasternode, PROTOCOL_VERSION); mn.UpdateLastSeen(masterNodeSignatureTime); darkSendMasterNodes.push_back(mn); } //send to all peers LogPrintf("CActiveMasternode::Register() - SendDarkSendElectionEntry vin = %s\n", vin.ToString().c_str()); SendDarkSendElectionEntry(vin, service, vchMasterNodeSignature, masterNodeSignatureTime, pubKeyCollateralAddress, pubKeyMasternode, -1, -1, masterNodeSignatureTime, PROTOCOL_VERSION); 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 = 0; outputIndex = boost::lexical_cast(outputIndex); 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() { CCoinControl *coinControl=NULL; vector vCoins; vector filteredCoins; // Retrieve all possible outputs pwalletMain->AvailableCoins(vCoins, true, coinControl, ALL_COINS); // Filter BOOST_FOREACH(const COutput& out, vCoins) { if(out.tx->vout[out.i].nValue == 1000*COIN) { //exactly filteredCoins.push_back(out); } } return filteredCoins; } /* select coins with specified transaction hash and output index */ /* bool CActiveMasternode::SelectCoinsMasternode(CTxIn& vin, int64& nValueIn, CScript& pubScript, std::string strTxHash, std::string strOutputIndex) { CWalletTx ctx; // Convert configuration strings uint256 txHash; int outputIndex; txHash.SetHex(strTxHash); std::istringstream(strOutputIndex) >> outputIndex; if(pwalletMain->GetTransaction(txHash, ctx)) { if(ctx.vout[outputIndex].nValue == 1000*COIN) { //exactly vin = CTxIn(ctx.GetHash(), outputIndex); pubScript = ctx.vout[outputIndex].scriptPubKey; // the inputs PubKey nValueIn = ctx.vout[outputIndex].nValue; return true; } } return false; } */ // 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 dseep messages going forward this->vin = newVin; this->service = newService; LogPrintf("CActiveMasternode::EnableHotColdMasterNode() - Enabled! You may shut down the cold daemon.\n"); return true; }