From 55cae78c3b1898a83c498ca323dbfdbf23e9f233 Mon Sep 17 00:00:00 2001 From: Francis Reynders Date: Sat, 6 Dec 2014 20:41:53 +0100 Subject: [PATCH] Improve support for start-many: - refactored CActiveMasternode - added masternodeconfig to handle remote masternode configuration - read masternodeconfig upon init - new masternode rpc commands: stop-many, start-alias, stop-alias, list-conf - added notCapableReason field for better handling not capable issues --- doc/masternode_conf.md | 26 ++ src/Makefile.am | 2 + src/activemasternode.cpp | 496 +++++++++++++++++++++++---------------- src/activemasternode.h | 49 ++-- src/darkcoind.cpp | 4 + src/darksend.cpp | 16 +- src/darksend.h | 2 +- src/init.cpp | 2 +- src/instantx.cpp | 8 +- src/masternode.cpp | 17 +- src/masternodeconfig.cpp | 32 +++ src/masternodeconfig.h | 102 ++++++++ src/miner.cpp | 1 + src/net.cpp | 19 +- src/net.h | 2 + src/qt/darkcoin.cpp | 3 + src/rpcdarksend.cpp | 301 ++++++++++++++++++++---- src/util.cpp | 7 + src/util.h | 1 + src/wallet.cpp | 21 +- src/wallet.h | 1 - 21 files changed, 804 insertions(+), 308 deletions(-) create mode 100644 doc/masternode_conf.md create mode 100644 src/masternodeconfig.cpp create mode 100644 src/masternodeconfig.h diff --git a/doc/masternode_conf.md b/doc/masternode_conf.md new file mode 100644 index 000000000..8376bef5d --- /dev/null +++ b/doc/masternode_conf.md @@ -0,0 +1,26 @@ +Multi masternode config +======================= + +The multi masternode config allows to control multiple masternodes from a single wallet. The wallet needs to have a valid collaral input of 1000 coins for each masternode. To use this, place a file named masternode.conf in the data directory of your install. + +The new masternode.conf format consists of a space seperated text file. Each line consisting of an alias, address, private key, collateral output transaction and collateral output index. + +Example: +``` +mn1 127.0.0.2:19999 93HaYBVUCYjEMeeH1Y4sBGLALQZE1Yc1K64xiqgX37tGBDQL8Xg 2bcd3c84c84f87eaa86e4e56834c92927a07f9e18718810b92e0d0324456a67c 0 +mn2 127.0.0.3:19999 93WaAb3htPJEV8E9aQcN23Jt97bPex7YvWfgMDTUdWJvzmrMqey aa9f1034d973377a5e733272c3d0eced1de22555ad45d6b24abadff8087948d4 0 +mn3 127.0.0.4:19999 92Da1aYg6sbenP6uwskJgEY2XWB5LwJ7bXRqc3UPeShtHWJDjDv db478e78e3aefaa8c12d12ddd0aeace48c3b451a8b41c570d0ee375e2a02dfd9 1 +``` + +In the example above, the collateral for mn1 consists of transaction: +http://test.explorer.darkcoin.fr/tx/2bcd3c84c84f87eaa86e4e56834c92927a07f9e18718810b92e0d0324456a67c +output index 0 has amount 1000 + +The following new RPC commands are supported: +* list-conf: shows the parsed masternode.conf +* start-alias \ +* stop-alias \ +* start-many +* stop-many + +When using the multi masternode setup, it is advised to run the wallet with 'masternode=0' as it is not needed anymore. diff --git a/src/Makefile.am b/src/Makefile.am index e3c779377..e8b3185b3 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -51,6 +51,7 @@ BITCOIN_CORE_H = \ limitedmap.h \ main.h \ masternode.h \ + masternodeconfig.h \ miner.h \ mruset.h \ netbase.h \ @@ -147,6 +148,7 @@ libdarkcoin_common_a_SOURCES = \ core.cpp \ darksend.cpp \ masternode.cpp \ + masternodeconfig.cpp \ instantx.cpp \ hash.cpp \ key.cpp \ diff --git a/src/activemasternode.cpp b/src/activemasternode.cpp index 63cce768d..769d1c006 100644 --- a/src/activemasternode.cpp +++ b/src/activemasternode.cpp @@ -4,287 +4,335 @@ #include "activemasternode.h" #include -using namespace std; -using namespace boost; - // // Bootup the masternode, look for a 1000DRK input and register on the network // -void CActiveMasternode::RegisterAsMasterNode(bool stop) +void CActiveMasternode::ManageStatus() { - if(!fMasterNode) return; + std::string errorMessage; + + LogPrintf("CActiveMasternode::ManageStatus() - Begin\n"); + + if(!fMasterNode) return; //need correct adjusted time to send ping bool fIsInitialDownload = IsInitialBlockDownload(); if(fIsInitialDownload) { - isCapableMasterNode = MASTERNODE_SYNC_IN_PROCESS; - LogPrintf("CActiveMasternode::RegisterAsMasterNode() - Sync in progress. Must wait until sync is complete to start masternode.\n"); + status = MASTERNODE_SYNC_IN_PROCESS; + LogPrintf("CActiveMasternode::ManageStatus() - Sync in progress. Must wait until sync is complete to start masternode.\n"); return; } - std::string errorMessage; - - CKey key2; - CPubKey pubkey2; - - if(!darkSendSigner.SetKey(strMasterNodePrivKey, errorMessage, key2, pubkey2)) - { - LogPrintf("CActiveMasternode::RegisterAsMasterNode() - Invalid masternodeprivkey: '%s'\n", errorMessage.c_str()); - exit(0); + if(status == MASTERNODE_INPUT_TOO_NEW || status == MASTERNODE_NOT_CAPABLE || status == MASTERNODE_SYNC_IN_PROCESS){ + status = MASTERNODE_NOT_PROCESSED; } - if(isCapableMasterNode == MASTERNODE_INPUT_TOO_NEW || isCapableMasterNode == MASTERNODE_NOT_CAPABLE || isCapableMasterNode == MASTERNODE_SYNC_IN_PROCESS){ - isCapableMasterNode = MASTERNODE_NOT_PROCESSED; - } - - if(isCapableMasterNode == MASTERNODE_NOT_PROCESSED) { + if(status == MASTERNODE_NOT_PROCESSED) { if(strMasterNodeAddr.empty()) { - if(!GetLocal(masterNodeSignAddr)) { - LogPrintf("CActiveMasternode::RegisterAsMasterNode() - Can't detect external address. Please use the masternodeaddr configuration option.\n"); - isCapableMasterNode = MASTERNODE_NOT_CAPABLE; + 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 { - masterNodeSignAddr = CService(strMasterNodeAddr); + service = CService(strMasterNodeAddr); } - if((Params().NetworkID() == CChainParams::TESTNET && masterNodeSignAddr.GetPort() != 19999) || (!(Params().NetworkID() == CChainParams::TESTNET) && masterNodeSignAddr.GetPort() != 9999)) { - LogPrintf("CActiveMasternode::RegisterAsMasterNode() - Invalid port\n"); - isCapableMasterNode = MASTERNODE_NOT_CAPABLE; + 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::RegisterAsMasterNode() - Checking inbound connection to '%s'\n", masterNodeSignAddr.ToString().c_str()); + LogPrintf("CActiveMasternode::ManageStatus() - Checking inbound connection to '%s'\n", service.ToString().c_str()); - if(ConnectNode((CAddress)masterNodeSignAddr, masterNodeSignAddr.ToString().c_str())){ - masternodePortOpen = MASTERNODE_PORT_OPEN; - } else { - masternodePortOpen = MASTERNODE_PORT_NOT_OPEN; - isCapableMasterNode = MASTERNODE_NOT_CAPABLE; - LogPrintf("CActiveMasternode::RegisterAsMasterNode() - Port not open.\n"); + 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()){ - isCapableMasterNode = MASTERNODE_NOT_CAPABLE; - LogPrintf("CActiveMasternode::RegisterAsMasterNode() - Not capable.\n"); + notCapableReason = "Wallet is locked."; + status = MASTERNODE_NOT_CAPABLE; + LogPrintf("CActiveMasternode::ManageStatus() - not capable: %s\n", notCapableReason.c_str()); return; } - isCapableMasterNode = MASTERNODE_NOT_CAPABLE; + // Set defaults + status = MASTERNODE_NOT_CAPABLE; + notCapableReason = "Unknown."; - CKey SecretKey; // Choose coins to use - if(GetMasterNodeVin(vinMasternode, pubkeyMasterNode, SecretKey)) { + CPubKey pubKeyCollateralAddress; + CKey keyCollateralAddress; - if(GetInputAge(vinMasternode) < MASTERNODE_MIN_CONFIRMATIONS){ - LogPrintf("CActiveMasternode::RegisterAsMasterNode() - Input must have least %d confirmations - %d confirmations\n", MASTERNODE_MIN_CONFIRMATIONS, GetInputAge(vinMasternode)); - isCapableMasterNode = MASTERNODE_INPUT_TOO_NEW; + 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; } - int protocolVersion = PROTOCOL_VERSION; + LogPrintf("CActiveMasternode::ManageStatus() - Is capable master node!\n"); - masterNodeSignatureTime = GetAdjustedTime(); + status = MASTERNODE_IS_CAPABLE; + notCapableReason = ""; - std::string vchPubKey(pubkeyMasterNode.begin(), pubkeyMasterNode.end()); - std::string vchPubKey2(pubkey2.begin(), pubkey2.end()); - std::string strMessage = masterNodeSignAddr.ToString() + boost::lexical_cast(masterNodeSignatureTime) + vchPubKey + vchPubKey2 + boost::lexical_cast(protocolVersion); + pwalletMain->LockCoin(vin.prevout); - if(!darkSendSigner.SignMessage(strMessage, errorMessage, vchMasterNodeSignature, SecretKey)) { - LogPrintf("CActiveMasternode::RegisterAsMasterNode() - Sign message failed\n"); - return; - } + // send to all nodes + CPubKey pubKeyMasternode; + CKey keyMasternode; - if(!darkSendSigner.VerifyMessage(pubkeyMasterNode, vchMasterNodeSignature, strMessage, errorMessage)) { - LogPrintf("CActiveMasternode::RegisterAsMasterNode() - Verify message failed\n"); - return; - } - - LogPrintf("CActiveMasternode::RegisterAsMasterNode() - Is capable master node!\n"); - - isCapableMasterNode = MASTERNODE_IS_CAPABLE; - - pwalletMain->LockCoin(vinMasternode.prevout); - - bool found = false; - BOOST_FOREACH(CMasterNode& mn, darkSendMasterNodes) - if(mn.vin == vinMasternode) - found = true; - - if(!found) { - LogPrintf("CActiveMasternode::RegisterAsMasterNode() - Adding myself to masternode list %s - %s\n", masterNodeSignAddr.ToString().c_str(), vinMasternode.ToString().c_str()); - CMasterNode mn(masterNodeSignAddr, vinMasternode, pubkeyMasterNode, vchMasterNodeSignature, masterNodeSignatureTime, pubkey2, PROTOCOL_VERSION); - mn.UpdateLastSeen(masterNodeSignatureTime); - darkSendMasterNodes.push_back(mn); - LogPrintf("CActiveMasternode::RegisterAsMasterNode() - Masternode input = %s\n", vinMasternode.ToString().c_str()); - } - - //relay to all - LOCK(cs_vNodes); - BOOST_FOREACH(CNode* pnode, vNodes) + if(!darkSendSigner.SetKey(strMasterNodePrivKey, errorMessage, keyMasternode, pubKeyMasternode)) { - pnode->PushMessage("dsee", vinMasternode, masterNodeSignAddr, vchMasterNodeSignature, masterNodeSignatureTime, pubkeyMasterNode, pubkey2, -1, -1, masterNodeSignatureTime, protocolVersion); + 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"); } } - if(isCapableMasterNode != MASTERNODE_IS_CAPABLE && isCapableMasterNode != MASTERNODE_REMOTELY_ENABLED) return; + //send to all peers + if(!Dseep(errorMessage)) { + LogPrintf("CActiveMasternode::ManageStatus() - Error on Ping: %s", errorMessage.c_str()); + } +} - masterNodeSignatureTime = GetAdjustedTime(); +// 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; - std::string strMessage = masterNodeSignAddr.ToString() + boost::lexical_cast(masterNodeSignatureTime) + boost::lexical_cast(stop); + if(!darkSendSigner.SetKey(strKeyMasternode, errorMessage, keyMasternode, pubKeyMasternode)) { + LogPrintf("CActiveMasternode::StopMasterNode() - Error: %s\n", errorMessage.c_str()); + return false; + } - if(!darkSendSigner.SignMessage(strMessage, errorMessage, vchMasterNodeSignature, key2)) { - LogPrintf("CActiveMasternode::RegisterAsMasterNode() - Sign message failed\n"); - return; + 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; } - if(!darkSendSigner.VerifyMessage(pubkey2, vchMasterNodeSignature, strMessage, errorMessage)) { - LogPrintf("CActiveMasternode::RegisterAsMasterNode() - Verify message failed\n"); - return; + 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 == vinMasternode) { + if(mn.vin == vin) { found = true; mn.UpdateLastSeen(); } } + if(!found){ - LogPrintf("CActiveMasternode::RegisterAsMasterNode() - Darksend Masternode List doesn't include our masternode, Shutting down masternode pinging service! %s\n", vinMasternode.ToString().c_str()); - isCapableMasterNode = MASTERNODE_STOPPED; - return; + // 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; } - LogPrintf("CActiveMasternode::RegisterAsMasterNode() - Masternode input = %s\n", vinMasternode.ToString().c_str()); + //send to all peers + LogPrintf("CActiveMasternode::Dseep() - SendDarkSendElectionEntryPing vin = %s\n", vin.ToString().c_str()); + SendDarkSendElectionEntryPing(vin, vchMasterNodeSignature, masterNodeSignatureTime, stop); - if (stop) isCapableMasterNode = MASTERNODE_STOPPED; - - //relay to all peers - LOCK(cs_vNodes); - BOOST_FOREACH(CNode* pnode, vNodes) - { - pnode->PushMessage("dseep", vinMasternode, vchMasterNodeSignature, masterNodeSignatureTime, stop); - } + return true; } -// -// Bootup the masternode, look for a 1000DRK input and register on the network -// Takes 2 parameters to start a remote masternode -// -bool CActiveMasternode::RegisterAsMasterNodeRemoteOnly(std::string strMasterNodeAddr, std::string strMasterNodePrivKey) -{ - if(!fMasterNode) return false; +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; - LogPrintf("CActiveMasternode::RegisterAsMasterNodeRemoteOnly() - Address %s MasterNodePrivKey %s\n", strMasterNodeAddr.c_str(), strMasterNodePrivKey.c_str()); + 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(); - CKey key2; - CPubKey pubkey2; + 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.SetKey(strMasterNodePrivKey, errorMessage, key2, pubkey2)) - { - LogPrintf("CActiveMasternode::RegisterAsMasterNodeRemoteOnly() - Invalid masternodeprivkey: '%s'\n", errorMessage.c_str()); - return false; + if(!darkSendSigner.SignMessage(strMessage, errorMessage, vchMasterNodeSignature, keyCollateralAddress)) { + retErrorMessage = "sign message failed: " + errorMessage; + LogPrintf("CActiveMasternode::Register() - Error: %s\n", retErrorMessage.c_str()); + return false; } - CService masterNodeSignAddr = CService(strMasterNodeAddr); - BOOST_FOREACH(CMasterNode& mn, darkSendMasterNodes){ - if(mn.addr == masterNodeSignAddr){ - LogPrintf("CActiveMasternode::RegisterAsMasterNodeRemoteOnly() - Address in use\n"); - 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); } - if((Params().NetworkID() == CChainParams::TESTNET && masterNodeSignAddr.GetPort() != 19999) || (!(Params().NetworkID() == CChainParams::TESTNET) && masterNodeSignAddr.GetPort() != 9999)) { - LogPrintf("CActiveMasternode::RegisterAsMasterNodeRemoteOnly() - Invalid port\n"); - return false; - } + //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); - LogPrintf("CActiveMasternode::RegisterAsMasterNodeRemoteOnly() - Checking inbound connection to '%s'\n", masterNodeSignAddr.ToString().c_str()); - - if(!ConnectNode((CAddress)masterNodeSignAddr, masterNodeSignAddr.ToString().c_str())){ - LogPrintf("CActiveMasternode::RegisterAsMasterNodeRemoteOnly() - Error connecting to port\n"); - return false; - } - - if(pwalletMain->IsLocked()){ - LogPrintf("CActiveMasternode::RegisterAsMasterNodeRemoteOnly() - Wallet is locked\n"); - return false; - } - - CKey SecretKey; - CTxIn vinMasternode; - CPubKey pubkeyMasterNode; - int masterNodeSignatureTime = 0; - - // Choose coins to use - while (GetMasterNodeVin(vinMasternode, pubkeyMasterNode, SecretKey)) { - // don't use a vin that's registered - BOOST_FOREACH(CMasterNode& mn, darkSendMasterNodes) - if(mn.vin == vinMasternode) - continue; - - if(GetInputAge(vinMasternode) < MASTERNODE_MIN_CONFIRMATIONS) - continue; - - masterNodeSignatureTime = GetAdjustedTime(); - - std::string vchPubKey(pubkeyMasterNode.begin(), pubkeyMasterNode.end()); - std::string vchPubKey2(pubkey2.begin(), pubkey2.end()); - std::string strMessage = masterNodeSignAddr.ToString() + boost::lexical_cast(masterNodeSignatureTime) + vchPubKey + vchPubKey2 + boost::lexical_cast(PROTOCOL_VERSION); - - if(!darkSendSigner.SignMessage(strMessage, errorMessage, vchMasterNodeSignature, SecretKey)) { - LogPrintf("CActiveMasternode::RegisterAsMasterNodeRemoteOnly() - Sign message failed\n"); - return false; - } - - if(!darkSendSigner.VerifyMessage(pubkeyMasterNode, vchMasterNodeSignature, strMessage, errorMessage)) { - LogPrintf("CActiveMasternode::RegisterAsMasterNodeRemoteOnly() - Verify message failed\n"); - return false; - } - - LogPrintf("CActiveMasternode::RegisterAsMasterNodeRemoteOnly() - Is capable master node!\n"); - - pwalletMain->LockCoin(vinMasternode.prevout); - - int protocolVersion = PROTOCOL_VERSION; - //relay to all - LOCK(cs_vNodes); - BOOST_FOREACH(CNode* pnode, vNodes) - { - pnode->PushMessage("dsee", vinMasternode, masterNodeSignAddr, vchMasterNodeSignature, masterNodeSignatureTime, pubkeyMasterNode, pubkey2, -1, -1, masterNodeSignatureTime, protocolVersion); - } - - return true; - } - - LogPrintf("CActiveMasternode::RegisterAsMasterNodeRemoteOnly() - No suitable vin found\n"); - return 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) -{ - int64_t nValueIn = 0; +bool CActiveMasternode::GetMasterNodeVin(CTxIn& vin, CPubKey& pubkey, CKey& secretKey, std::string strTxHash, std::string strOutputIndex) { CScript pubScript; - // try once before we try to denominate - if (!pwalletMain->SelectCoinsMasternode(vin, nValueIn, pubScript)) - { - if(fDebug) LogPrintf("CActiveMasternode::GetMasterNodeVin - I'm not a capable masternode\n"); - return false; + // 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(outputIndex); + bool found = false; + BOOST_FOREACH(COutput& out, possibleCoins) { + if(true) { + 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; + } } - CTxDestination address1; + // 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); @@ -303,16 +351,62 @@ bool CActiveMasternode::GetMasterNodeVin(CTxIn& vin, CPubKey& pubkey, CKey& secr 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& vin, int64_t sigTime, CService& addr) +bool CActiveMasternode::EnableHotColdMasterNode(CTxIn& newVin, CService& newService) { if(!fMasterNode) return false; - isCapableMasterNode = MASTERNODE_REMOTELY_ENABLED; + status = MASTERNODE_REMOTELY_ENABLED; - vinMasternode = vin; - masterNodeSignatureTime = sigTime; - masterNodeSignAddr = addr; + //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"); diff --git a/src/activemasternode.h b/src/activemasternode.h index 1b4cc3b40..2b118f4d7 100644 --- a/src/activemasternode.h +++ b/src/activemasternode.h @@ -1,4 +1,3 @@ - // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2012 The Bitcoin developers // Distributed under the MIT/X11 software license, see the accompanying @@ -19,36 +18,44 @@ class CActiveMasternode { public: - CTxIn vinMasternode; - CPubKey pubkeyMasterNode; - CPubKey pubkeyMasterNode2; + // Initialized by init.cpp + // Keys for the main masternode + CPubKey pubKeyMasternode; - std::string strMasterNodeSignMessage; - std::vector vchMasterNodeSignature; + // Initialized while registering masternode + CTxIn vin; + CService service; - std::string masterNodeAddr; - CService masterNodeSignAddr; - - int isCapableMasterNode; - int64_t masterNodeSignatureTime; - int masternodePortOpen; + int status; + std::string notCapableReason; CActiveMasternode() - { - isCapableMasterNode = MASTERNODE_NOT_PROCESSED; - masternodePortOpen = 0; + { + status = MASTERNODE_NOT_PROCESSED; } + void ManageStatus(); // manage status of main masternode + + bool Dseep(std::string& errorMessage); // ping for main masternode + bool Dseep(CTxIn vin, CService service, CKey key, CPubKey pubKey, std::string &retErrorMessage, bool stop); // ping for any masternode + + bool StopMasterNode(std::string& errorMessage); // stop main masternode + bool StopMasterNode(std::string strService, std::string strKeyMasternode, std::string& errorMessage); // stop remote masternode + bool StopMasterNode(CTxIn vin, CService service, CKey key, CPubKey pubKey, std::string& errorMessage); // stop any masternode + + bool Register(std::string strService, std::string strKey, std::string txHash, std::string strOutputIndex, std::string& errorMessage); // register remote masternode + bool Register(CTxIn vin, CService service, CKey key, CPubKey pubKey, CKey keyMasternode, CPubKey pubKeyMasternode, std::string &retErrorMessage); // register any masternode + // get 1000DRK input that can be used for the masternode bool GetMasterNodeVin(CTxIn& vin, CPubKey& pubkey, CKey& secretKey); + bool GetMasterNodeVin(CTxIn& vin, CPubKey& pubkey, CKey& secretKey, std::string strTxHash, std::string strOutputIndex); + vector SelectCoinsMasternode(); + bool GetVinFromOutput(COutput out, CTxIn& vin, CPubKey& pubkey, CKey& secretKey); - // start the masternode and register with the network - void RegisterAsMasterNode(bool stop); - // start a remote masternode - bool RegisterAsMasterNodeRemoteOnly(std::string strMasterNodeAddr, std::string strMasterNodePrivKey); + //bool SelectCoinsMasternode(CTxIn& vin, int64& nValueIn, CScript& pubScript, std::string strTxHash, std::string strOutputIndex); // enable hot wallet mode (run a masternode with no funds) - bool EnableHotColdMasterNode(CTxIn& vin, int64_t sigTime, CService& addr); + bool EnableHotColdMasterNode(CTxIn& vin, CService& addr); }; -#endif \ No newline at end of file +#endif diff --git a/src/darkcoind.cpp b/src/darkcoind.cpp index f8e92301c..7065742a5 100644 --- a/src/darkcoind.cpp +++ b/src/darkcoind.cpp @@ -11,6 +11,7 @@ #include "noui.h" #include "ui_interface.h" #include "util.h" +#include "masternodeconfig.h" #include #include @@ -78,6 +79,9 @@ bool AppInit(int argc, char* argv[]) fprintf(stderr,"Error reading configuration file: %s\n", e.what()); return false; } + + masternodeConfig.read(GetMasternodeConfigFile()); + // Check for -testnet or -regtest parameter (TestNet() calls are only valid after this clause) if (!SelectParamsFromCommandLine()) { fprintf(stderr, "Error: Invalid combination of -regtest and -testnet.\n"); diff --git a/src/darksend.cpp b/src/darksend.cpp index cd72d2e68..a66de0536 100644 --- a/src/darksend.cpp +++ b/src/darksend.cpp @@ -110,7 +110,7 @@ void ProcessMessageDarksend(CNode* pfrom, std::string& strCommand, CDataStream& vRecv >> nDenom >> txCollateral; std::string error = ""; - int mn = GetMasternodeByVin(activeMasternode.vinMasternode); + int mn = GetMasternodeByVin(activeMasternode.vin); if(mn == -1){ std::string strError = "Not in the masternode list"; pfrom->PushMessage("dssu", darkSendPool.sessionID, darkSendPool.GetState(), darkSendPool.GetEntriesCount(), MASTERNODE_REJECTED, strError); @@ -591,7 +591,7 @@ void CDarkSendPool::Check() if(!mapDarksendBroadcastTxes.count(txNew.GetHash())){ CDarksendBroadcastTx dstx; dstx.tx = txNew; - dstx.vin = activeMasternode.vinMasternode; + dstx.vin = activeMasternode.vin; dstx.vchSig = vchSig; dstx.sigTime = sigTime; @@ -798,7 +798,7 @@ void CDarkSendPool::CheckTimeout(){ if(state == POOL_STATUS_QUEUE && sessionUsers == GetMaxPoolTransactions()) { CDarksendQueue dsq; dsq.nDenom = sessionDenom; - dsq.vin = activeMasternode.vinMasternode; + dsq.vin = activeMasternode.vin; dsq.time = GetTime(); dsq.ready = true; dsq.Sign(); @@ -1850,7 +1850,7 @@ bool CDarkSendPool::IsCompatibleWithSession(int64_t nDenom, CTransaction txColla //broadcast that I'm accepting entries, only if it's the first entry though CDarksendQueue dsq; dsq.nDenom = nDenom; - dsq.vin = activeMasternode.vinMasternode; + dsq.vin = activeMasternode.vin; dsq.time = GetTime(); dsq.Sign(); dsq.Relay(); @@ -2102,6 +2102,8 @@ void ThreadCheckDarkSendPool() RenameThread("bitcoin-darksend"); unsigned int c = 0; + std::string errorMessage; + while (true) { c++; @@ -2150,16 +2152,14 @@ void ThreadCheckDarkSendPool() } } - /* if(c % MASTERNODE_PING_SECONDS == 0){ - activeMasternode.RegisterAsMasterNode(false); - }*/ + activeMasternode.ManageStatus(); + } if(c % 60 == 0){ //if we've used 1/5 of the masternode list, then clear the list. if((int)vecMasternodesUsed.size() > (int)darkSendMasterNodes.size() / 5) vecMasternodesUsed.clear(); - } //auto denom every 2.5 minutes (liquidity provides try less often) diff --git a/src/darksend.h b/src/darksend.h index 1b7af9a97..ecfe2e34f 100644 --- a/src/darksend.h +++ b/src/darksend.h @@ -7,8 +7,8 @@ #define DARKSEND_H #include "core.h" -#include "masternode.h" #include "main.h" +#include "masternode.h" #include "activemasternode.h" class CTxIn; diff --git a/src/init.cpp b/src/init.cpp index f0cc65ae0..839ae8cb1 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1113,7 +1113,7 @@ bool AppInit2(boost::thread_group& threadGroup) return InitError(_("Invalid masternodeprivkey. Please see documenation.")); } - activeMasternode.pubkeyMasterNode2 = pubkey; + activeMasternode.pubKeyMasternode = pubkey; } else { return InitError(_("You must specify a masternodeprivkey in the configuration. Please see documentation for help.")); diff --git a/src/instantx.cpp b/src/instantx.cpp index 0316c25de..4ae914e15 100644 --- a/src/instantx.cpp +++ b/src/instantx.cpp @@ -210,7 +210,7 @@ void DoConsensusVote(CTransaction& tx, bool approved, int64_t nBlockHeight) } int winner = GetCurrentMasterNode(1, nBlockHeight); - int n = GetMasternodeRank(activeMasternode.vinMasternode, nBlockHeight, MIN_INSTANTX_PROTO_VERSION); + int n = GetMasternodeRank(activeMasternode.vin, nBlockHeight, MIN_INSTANTX_PROTO_VERSION); if(n == -1 || winner == -1) { @@ -228,7 +228,7 @@ void DoConsensusVote(CTransaction& tx, bool approved, int64_t nBlockHeight) } CConsensusVote ctx; - ctx.vinMasternode = activeMasternode.vinMasternode; + ctx.vinMasternode = activeMasternode.vin; ctx.approved = approved; ctx.txHash = tx.GetHash(); ctx.nBlockHeight = nBlockHeight; @@ -277,7 +277,7 @@ void ProcessConsensusVote(CConsensusVote& ctx) } //We're not the winning masternode - if(darkSendMasterNodes[winner].vin != activeMasternode.vinMasternode) { + if(darkSendMasterNodes[winner].vin != activeMasternode.vin) { LogPrintf("InstantX::ProcessConsensusVote - I'm not the winning masternode\n"); return; } @@ -456,4 +456,4 @@ void CTransactionLock::AddSignature(CConsensusVote cv) int CTransactionLock::CountSignatures() { return vecConsensusVotes.size(); -} \ No newline at end of file +} diff --git a/src/masternode.cpp b/src/masternode.cpp index fb84e8724..774f7500d 100644 --- a/src/masternode.cpp +++ b/src/masternode.cpp @@ -1,5 +1,3 @@ - - #include "masternode.h" #include "activemasternode.h" #include "darksend.h" @@ -164,10 +162,10 @@ void ProcessMessageMasternode(CNode* pfrom, std::string& strCommand, CDataStream mn.UpdateLastSeen(lastUpdated); darkSendMasterNodes.push_back(mn); - /*// if it matches our masternodeprivkey, then we've been remotely activated - if(pubkey2 == activeMasternode.pubkeyMasterNode2 && protocolVersion == PROTOCOL_VERSION){ - activeMasternode.EnableHotColdMasterNode(vin, sigTime, addr); - }*/ + // if it matches our masternodeprivkey, then we've been remotely activated + if(pubkey2 == activeMasternode.pubKeyMasternode && protocolVersion == PROTOCOL_VERSION){ + activeMasternode.EnableHotColdMasterNode(vin, addr); + } if(count == -1 && !isLocal) RelayDarkSendElectionEntry(vin, addr, vchSig, sigTime, pubkey, pubkey2, count, current, lastUpdated, protocolVersion); @@ -196,6 +194,8 @@ void ProcessMessageMasternode(CNode* pfrom, std::string& strCommand, CDataStream bool stop; vRecv >> vin >> vchSig >> sigTime >> stop; + //LogPrintf("dseep - Received: vin: %s sigTime: %lld stop: %s\n", vin.ToString().c_str(), sigTime, stop ? "true" : "false"); + if (sigTime > GetAdjustedTime() + 60 * 60) { LogPrintf("dseep - Signature rejected, too far into the future %s\n", vin.ToString().c_str()); return; @@ -210,8 +210,9 @@ void ProcessMessageMasternode(CNode* pfrom, std::string& strCommand, CDataStream BOOST_FOREACH(CMasterNode& mn, darkSendMasterNodes) { if(mn.vin.prevout == vin.prevout) { - // take this only if it's newer - if(mn.lastDseep < sigTime){ + // LogPrintf("dseep - Found corresponding mn for vin: %s\n", vin.ToString().c_str()); + // take this only if it's newer + if(mn.lastDseep < sigTime){ std::string strMessage = mn.addr.ToString() + boost::lexical_cast(sigTime) + boost::lexical_cast(stop); std::string errorMessage = ""; diff --git a/src/masternodeconfig.cpp b/src/masternodeconfig.cpp new file mode 100644 index 000000000..173c39045 --- /dev/null +++ b/src/masternodeconfig.cpp @@ -0,0 +1,32 @@ +#include "masternodeconfig.h" +#include "util.h" + +CMasternodeConfig masternodeConfig; + +void CMasternodeConfig::add(std::string alias, std::string ip, std::string privKey, std::string txHash, std::string outputIndex) { + CMasternodeEntry cme(alias, ip, privKey, txHash, outputIndex); + entries.push_back(cme); +} + +void CMasternodeConfig::read(boost::filesystem::path path) { + boost::filesystem::ifstream streamConfig(GetMasternodeConfigFile()); + if (!streamConfig.good()) { + return; // No masternode.conf file is OK + } + + for(std::string line; std::getline(streamConfig, line); ) + { + if(line.empty()) { + continue; + } + std::istringstream iss(line); + std::string alias, ip, privKey, txHash, outputIndex; + if (!(iss >> alias >> ip >> privKey >> txHash >> outputIndex)) { + LogPrintf("CMasternodeConfig::read - Could not parse masternode.conf. Line: %s\n", line.c_str()); + continue; + } + add(alias, ip, privKey, txHash, outputIndex); + } + + streamConfig.close(); +} diff --git a/src/masternodeconfig.h b/src/masternodeconfig.h new file mode 100644 index 000000000..c5e95c410 --- /dev/null +++ b/src/masternodeconfig.h @@ -0,0 +1,102 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2012 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef SRC_MASTERNODECONFIG_H_ +#define SRC_MASTERNODECONFIG_H_ + +#include +#include + +#include +#include + +class CMasternodeConfig; +extern CMasternodeConfig masternodeConfig; + +class CMasternodeConfig +{ + +public: + class CMasternodeEntry { + + private: + std::string alias; + std::string ip; + std::string privKey; + std::string txHash; + std::string outputIndex; + + public: + + CMasternodeEntry(std::string alias, std::string ip, std::string privKey, std::string txHash, std::string outputIndex) { + this->alias = alias; + this->ip = ip; + this->privKey = privKey; + this->txHash = txHash; + this->outputIndex = outputIndex; + } + + const std::string& getAlias() const { + return alias; + } + + void setAlias(const std::string& alias) { + this->alias = alias; + } + + const std::string& getOutputIndex() const { + return outputIndex; + } + + void setOutputIndex(const std::string& outputIndex) { + this->outputIndex = outputIndex; + } + + const std::string& getPrivKey() const { + return privKey; + } + + void setPrivKey(const std::string& privKey) { + this->privKey = privKey; + } + + const std::string& getTxHash() const { + return txHash; + } + + void setTxHash(const std::string& txHash) { + this->txHash = txHash; + } + + const std::string& getIp() const { + return ip; + } + + void setIp(const std::string& ip) { + this->ip = ip; + } + }; + + CMasternodeConfig() { + entries = std::vector(); + } + + void clear(); + void read(boost::filesystem::path path); + void add(std::string alias, std::string ip, std::string privKey, std::string txHash, std::string outputIndex); + + std::vector& getEntries() { + return entries; + } + +private: + std::vector entries; + + +}; + + +#endif /* SRC_MASTERNODECONFIG_H_ */ + diff --git a/src/miner.cpp b/src/miner.cpp index 7af8ed364..a00c48e08 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -12,6 +12,7 @@ #ifdef ENABLE_WALLET #include "wallet.h" #endif +#include "masternode.h" ////////////////////////////////////////////////////////////////////////////// // diff --git a/src/net.cpp b/src/net.cpp index c485892f8..e2383547e 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1911,6 +1911,15 @@ void RelayDarkSendElectionEntry(const CTxIn vin, const CService addr, const std: } } +void SendDarkSendElectionEntry(const CTxIn vin, const CService addr, const std::vector vchSig, const int64_t nNow, const CPubKey pubkey, const CPubKey pubkey2, const int count, const int current, const int64_t lastUpdated, const int protocolVersion) +{ + LOCK(cs_vNodes); + BOOST_FOREACH(CNode* pnode, vNodes) + { + pnode->PushMessage("dsee", vin, addr, vchSig, nNow, pubkey, pubkey2, count, current, lastUpdated, protocolVersion); + } +} + void RelayDarkSendElectionEntryPing(const CTxIn vin, const std::vector vchSig, const int64_t nNow, const bool stop) { LOCK(cs_vNodes); @@ -1922,6 +1931,15 @@ void RelayDarkSendElectionEntryPing(const CTxIn vin, const std::vector vchSig, const int64_t nNow, const bool stop) +{ + LOCK(cs_vNodes); + BOOST_FOREACH(CNode* pnode, vNodes) + { + pnode->PushMessage("dseep", vin, vchSig, nNow, stop); + } +} + void RelayDarkSendCompletedTransaction(const int sessionID, const bool error, const std::string errorMessage) { LOCK(cs_vNodes); @@ -1931,7 +1949,6 @@ void RelayDarkSendCompletedTransaction(const int sessionID, const bool error, co } } - void CNode::RecordBytesRecv(uint64_t bytes) { LOCK(cs_totalBytesRecv); diff --git a/src/net.h b/src/net.h index fcd5bfa85..eeacf98d4 100644 --- a/src/net.h +++ b/src/net.h @@ -764,7 +764,9 @@ void RelayDarkSendFinalTransaction(const int sessionID, const CTransaction& txNe void RelayDarkSendIn(const std::vector& in, const int64_t& nAmount, const CTransaction& txCollateral, const std::vector& out); void RelayDarkSendStatus(const int sessionID, const int newState, const int newEntriesCount, const int newAccepted, const std::string error=""); void RelayDarkSendElectionEntry(const CTxIn vin, const CService addr, const std::vector vchSig, const int64_t nNow, const CPubKey pubkey, const CPubKey pubkey2, const int count, const int current, const int64_t lastUpdated, const int protocolVersion); +void SendDarkSendElectionEntry(const CTxIn vin, const CService addr, const std::vector vchSig, const int64_t nNow, const CPubKey pubkey, const CPubKey pubkey2, const int count, const int current, const int64_t lastUpdated, const int protocolVersion); void RelayDarkSendElectionEntryPing(const CTxIn vin, const std::vector vchSig, const int64_t nNow, const bool stop); +void SendDarkSendElectionEntryPing(const CTxIn vin, const std::vector vchSig, const int64_t nNow, const bool stop); void RelayDarkSendCompletedTransaction(const int sessionID, const bool error, const std::string errorMessage); void RelayDarkSendMasterNodeContestant(); diff --git a/src/qt/darkcoin.cpp b/src/qt/darkcoin.cpp index c1e9ac0ac..4fb815bc1 100644 --- a/src/qt/darkcoin.cpp +++ b/src/qt/darkcoin.cpp @@ -21,6 +21,7 @@ #include "paymentserver.h" #include "walletmodel.h" #endif +#include "masternodeconfig.h" #include "init.h" #include "main.h" @@ -533,6 +534,8 @@ int main(int argc, char *argv[]) return false; } + masternodeConfig.read(GetMasternodeConfigFile()); + /// 7. Determine network (and switch to network specific options) // - Do not call Params() before this step // - Do this after parsing the configuration file, as the network can be switched there diff --git a/src/rpcdarksend.cpp b/src/rpcdarksend.cpp index c3e3857e8..a703668cc 100644 --- a/src/rpcdarksend.cpp +++ b/src/rpcdarksend.cpp @@ -9,6 +9,7 @@ #include "init.h" #include "masternode.h" #include "activemasternode.h" +#include "masternodeconfig.h" #include "rpcserver.h" #include @@ -83,6 +84,7 @@ Value getpoolinfo(const Array& params, bool fHelp) return obj; } + Value masternode(const Array& params, bool fHelp) { string strCommand; @@ -90,10 +92,10 @@ Value masternode(const Array& params, bool fHelp) strCommand = params[0].get_str(); if (fHelp || - (strCommand != "start" && strCommand != "start-many" && strCommand != "stop" && strCommand != "list" && strCommand != "count" && strCommand != "enforce" + (strCommand != "start" && strCommand != "start-alias" && strCommand != "start-many" && strCommand != "stop" && strCommand != "stop-alias" && strCommand != "stop-many" && strCommand != "list" && strCommand != "list-conf" && strCommand != "count" && strCommand != "enforce" && strCommand != "debug" && strCommand != "current" && strCommand != "winners" && strCommand != "genkey" && strCommand != "connect")) throw runtime_error( - "masternode passphrase\n"); + "masternode passphrase\n"); if (strCommand == "stop") { @@ -115,15 +117,126 @@ Value masternode(const Array& params, bool fHelp) } } - activeMasternode.RegisterAsMasterNode(true); + std::string errorMessage; + if(!activeMasternode.StopMasterNode(errorMessage)) { + return "stop failed: " + errorMessage; + } pwalletMain->Lock(); - - if(activeMasternode.isCapableMasterNode == MASTERNODE_STOPPED) return "successfully stopped masternode"; - if(activeMasternode.isCapableMasterNode == MASTERNODE_NOT_CAPABLE) return "not capable masternode"; - + + if(activeMasternode.status == MASTERNODE_STOPPED) return "successfully stopped masternode"; + if(activeMasternode.status == MASTERNODE_NOT_CAPABLE) return "not capable masternode"; + return "unknown"; } + if (strCommand == "stop-alias") + { + if (params.size() < 2){ + throw runtime_error( + "command needs at least 2 parameters\n"); + } + + std::string alias = params[1].get_str().c_str(); + + if(pwalletMain->IsLocked()) { + SecureString strWalletPass; + strWalletPass.reserve(100); + + if (params.size() == 3){ + strWalletPass = params[2].get_str().c_str(); + } else { + throw runtime_error( + "Your wallet is locked, passphrase is required\n"); + } + + if(!pwalletMain->Unlock(strWalletPass)){ + return "incorrect passphrase"; + } + } + + bool found = false; + + Object statusObj; + statusObj.push_back(Pair("alias", alias)); + + BOOST_FOREACH(CMasternodeConfig::CMasternodeEntry mne, masternodeConfig.getEntries()) { + if(mne.getAlias() == alias) { + found = true; + std::string errorMessage; + bool result = activeMasternode.StopMasterNode(mne.getIp(), mne.getPrivKey(), errorMessage); + + statusObj.push_back(Pair("result", result ? "successful" : "failed")); + if(!result) { + statusObj.push_back(Pair("errorMessage", errorMessage)); + } + break; + } + } + + if(!found) { + statusObj.push_back(Pair("result", "failed")); + statusObj.push_back(Pair("errorMessage", "could not find alias in config. Verify with list-conf.")); + } + + pwalletMain->Lock(); + return statusObj; + } + + if (strCommand == "stop-many") + { + if(pwalletMain->IsLocked()) { + SecureString strWalletPass; + strWalletPass.reserve(100); + + if (params.size() == 2){ + strWalletPass = params[1].get_str().c_str(); + } else { + throw runtime_error( + "Your wallet is locked, passphrase is required\n"); + } + + if(!pwalletMain->Unlock(strWalletPass)){ + return "incorrect passphrase"; + } + } + + int total = 0; + int successful = 0; + int fail = 0; + + + Object resultsObj; + + BOOST_FOREACH(CMasternodeConfig::CMasternodeEntry mne, masternodeConfig.getEntries()) { + total++; + + std::string errorMessage; + bool result = activeMasternode.StopMasterNode(mne.getIp(), mne.getPrivKey(), errorMessage); + + Object statusObj; + statusObj.push_back(Pair("alias", mne.getAlias())); + statusObj.push_back(Pair("result", result ? "successful" : "failed")); + + if(result) { + successful++; + } else { + fail++; + statusObj.push_back(Pair("errorMessage", errorMessage)); + } + + resultsObj.push_back(Pair("status", statusObj)); + } + pwalletMain->Lock(); + + Object returnObj; + returnObj.push_back(Pair("overall", "Successfully stopped " + boost::lexical_cast(successful) + " masternodes, failed to stop " + + boost::lexical_cast(fail) + ", total " + boost::lexical_cast(total))); + returnObj.push_back(Pair("detail", resultsObj)); + + return returnObj; + + } + if (strCommand == "list") { std::string strCommand = "active"; @@ -187,57 +300,139 @@ Value masternode(const Array& params, bool fHelp) } } - activeMasternode.RegisterAsMasterNode(false); + activeMasternode.status = MASTERNODE_NOT_PROCESSED; // TODO: consider better way + std::string errorMessage; + activeMasternode.ManageStatus(); pwalletMain->Lock(); - - if(activeMasternode.isCapableMasterNode == MASTERNODE_REMOTELY_ENABLED) return "masternode started remotely"; - if(activeMasternode.isCapableMasterNode == MASTERNODE_INPUT_TOO_NEW) return "masternode input must have at least 15 confirmations"; - if(activeMasternode.isCapableMasterNode == MASTERNODE_STOPPED) return "masternode is stopped"; - if(activeMasternode.isCapableMasterNode == MASTERNODE_IS_CAPABLE) return "successfully started masternode"; - if(activeMasternode.masternodePortOpen == MASTERNODE_PORT_NOT_OPEN) return "inbound port is not open. Please open it and try again. (19999 for testnet and 9999 for mainnet)"; - if(activeMasternode.isCapableMasterNode == MASTERNODE_NOT_CAPABLE) return "not capable masternode"; - if(activeMasternode.isCapableMasterNode == MASTERNODE_SYNC_IN_PROCESS) return "sync in process. Must wait until client is synced to start."; + + if(activeMasternode.status == MASTERNODE_REMOTELY_ENABLED) return "masternode started remotely"; + if(activeMasternode.status == MASTERNODE_INPUT_TOO_NEW) return "masternode input must have at least 15 confirmations"; + if(activeMasternode.status == MASTERNODE_STOPPED) return "masternode is stopped"; + if(activeMasternode.status == MASTERNODE_IS_CAPABLE) return "successfully started masternode"; + if(activeMasternode.status == MASTERNODE_NOT_CAPABLE) return "not capable masternode: " + activeMasternode.notCapableReason; + if(activeMasternode.status == MASTERNODE_SYNC_IN_PROCESS) return "sync in process. Must wait until client is synced to start."; return "unknown"; } - if (strCommand == "start-many") + if (strCommand == "start-alias") { - boost::filesystem::path pathDebug = GetDataDir() / "masternode.conf"; - std::ifstream infile(pathDebug.string().c_str()); + if (params.size() < 2){ + throw runtime_error( + "command needs at least 2 parameters\n"); + } - std::string line; - int total = 0; - int successful = 0; - int fail = 0; - while (std::getline(infile, line)) - { - std::istringstream iss(line); - std::string a, b; - if (!(iss >> a >> b)) { break; } // error + std::string alias = params[1].get_str().c_str(); - total++; - if(activeMasternode.RegisterAsMasterNodeRemoteOnly(a, b)){ - successful++; - } else { - fail++; - } + if(pwalletMain->IsLocked()) { + SecureString strWalletPass; + strWalletPass.reserve(100); + + if (params.size() == 3){ + strWalletPass = params[2].get_str().c_str(); + } else { + throw runtime_error( + "Your wallet is locked, passphrase is required\n"); + } + + if(!pwalletMain->Unlock(strWalletPass)){ + return "incorrect passphrase"; + } } - printf(" Successfully started %d masternodes, failed to start %d, total %d\n", successful, fail, total); - return ""; + bool found = false; + Object statusObj; + statusObj.push_back(Pair("alias", alias)); + + BOOST_FOREACH(CMasternodeConfig::CMasternodeEntry mne, masternodeConfig.getEntries()) { + if(mne.getAlias() == alias) { + found = true; + std::string errorMessage; + bool result = activeMasternode.Register(mne.getIp(), mne.getPrivKey(), mne.getTxHash(), mne.getOutputIndex(), errorMessage); + + statusObj.push_back(Pair("result", result ? "successful" : "failed")); + if(!result) { + statusObj.push_back(Pair("errorMessage", errorMessage)); + } + break; + } + } + + if(!found) { + statusObj.push_back(Pair("result", "failed")); + statusObj.push_back(Pair("errorMessage", "could not find alias in config. Verify with list-conf.")); + } + + pwalletMain->Lock(); + return statusObj; + + } + + if (strCommand == "start-many") + { + if(pwalletMain->IsLocked()) { + SecureString strWalletPass; + strWalletPass.reserve(100); + + if (params.size() == 2){ + strWalletPass = params[1].get_str().c_str(); + } else { + throw runtime_error( + "Your wallet is locked, passphrase is required\n"); + } + + if(!pwalletMain->Unlock(strWalletPass)){ + return "incorrect passphrase"; + } + } + + std::vector mnEntries; + mnEntries = masternodeConfig.getEntries(); + + int total = 0; + int successful = 0; + int fail = 0; + + Object resultsObj; + + BOOST_FOREACH(CMasternodeConfig::CMasternodeEntry mne, masternodeConfig.getEntries()) { + total++; + + std::string errorMessage; + bool result = activeMasternode.Register(mne.getIp(), mne.getPrivKey(), mne.getTxHash(), mne.getOutputIndex(), errorMessage); + + Object statusObj; + statusObj.push_back(Pair("alias", mne.getAlias())); + statusObj.push_back(Pair("result", result ? "succesful" : "failed")); + + if(result) { + successful++; + } else { + fail++; + statusObj.push_back(Pair("errorMessage", errorMessage)); + } + + resultsObj.push_back(Pair("status", statusObj)); + } + pwalletMain->Lock(); + + Object returnObj; + returnObj.push_back(Pair("overall", "Successfully started " + boost::lexical_cast(successful) + " masternodes, failed to start " + + boost::lexical_cast(fail) + ", total " + boost::lexical_cast(total))); + returnObj.push_back(Pair("detail", resultsObj)); + + return returnObj; } if (strCommand == "debug") { - if(activeMasternode.isCapableMasterNode == MASTERNODE_REMOTELY_ENABLED) return "masternode started remotely"; - if(activeMasternode.isCapableMasterNode == MASTERNODE_INPUT_TOO_NEW) return "masternode input must have at least 15 confirmations"; - if(activeMasternode.isCapableMasterNode == MASTERNODE_IS_CAPABLE) return "successfully started masternode"; - if(activeMasternode.isCapableMasterNode == MASTERNODE_STOPPED) return "masternode is stopped"; - if(activeMasternode.masternodePortOpen == MASTERNODE_PORT_NOT_OPEN) return "inbound port is not open. Please open it and try again. (19999 for testnet and 9999 for mainnet)"; - if(activeMasternode.isCapableMasterNode == MASTERNODE_NOT_CAPABLE) return "not capable masternode"; - if(activeMasternode.isCapableMasterNode == MASTERNODE_SYNC_IN_PROCESS) return "sync in process. Must wait until client is synced to start."; + if(activeMasternode.status == MASTERNODE_REMOTELY_ENABLED) return "masternode started remotely"; + if(activeMasternode.status == MASTERNODE_INPUT_TOO_NEW) return "masternode input must have at least 15 confirmations"; + if(activeMasternode.status == MASTERNODE_IS_CAPABLE) return "successfully started masternode"; + if(activeMasternode.status == MASTERNODE_STOPPED) return "masternode is stopped"; + if(activeMasternode.status == MASTERNODE_NOT_CAPABLE) return "not capable masternode: " + activeMasternode.notCapableReason; + if(activeMasternode.status == MASTERNODE_SYNC_IN_PROCESS) return "sync in process. Must wait until client is synced to start."; CTxIn vin = CTxIn(); CPubKey pubkey = CScript(); @@ -318,6 +513,26 @@ Value masternode(const Array& params, bool fHelp) } } + if(strCommand == "list-conf") + { + std::vector mnEntries; + mnEntries = masternodeConfig.getEntries(); + + Object resultObj; + + BOOST_FOREACH(CMasternodeConfig::CMasternodeEntry mne, masternodeConfig.getEntries()) { + Object mnObj; + mnObj.push_back(Pair("alias", mne.getAlias())); + mnObj.push_back(Pair("address", mne.getIp())); + mnObj.push_back(Pair("privateKey", mne.getPrivKey())); + mnObj.push_back(Pair("txHash", mne.getTxHash())); + mnObj.push_back(Pair("outputIndex", mne.getOutputIndex())); + resultObj.push_back(Pair("masternode", mnObj)); + } + + return resultObj; + } + return Value::null; } diff --git a/src/util.cpp b/src/util.cpp index 87940ff32..4ff1a9db7 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -1033,6 +1033,13 @@ boost::filesystem::path GetConfigFile() return pathConfigFile; } +boost::filesystem::path GetMasternodeConfigFile() +{ + boost::filesystem::path pathConfigFile(GetArg("-mnconf", "masternode.conf")); + if (!pathConfigFile.is_complete()) pathConfigFile = GetDataDir(false) / pathConfigFile; + return pathConfigFile; +} + void ReadConfigFile(map& mapSettingsRet, map >& mapMultiSettingsRet) { diff --git a/src/util.h b/src/util.h index 5823fb326..746242262 100644 --- a/src/util.h +++ b/src/util.h @@ -195,6 +195,7 @@ bool TryCreateDirectory(const boost::filesystem::path& p); boost::filesystem::path GetDefaultDataDir(); const boost::filesystem::path &GetDataDir(bool fNetSpecific = true); boost::filesystem::path GetConfigFile(); +boost::filesystem::path GetMasternodeConfigFile(); boost::filesystem::path GetPidFile(); #ifndef WIN32 void CreatePidFile(const boost::filesystem::path &path, pid_t pid); diff --git a/src/wallet.cpp b/src/wallet.cpp index 6f421dad3..46bbe0b6d 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -10,10 +10,12 @@ #include "checkpoints.h" #include "coincontrol.h" #include "net.h" +#include "darksend.h" #include #include + using namespace std; // Settings @@ -1246,25 +1248,6 @@ static void ApproximateBestSubset(vector vCoins; - AvailableCoins(vCoins, true, coinControl, ALL_COINS); - - BOOST_FOREACH(const COutput& out, vCoins) - { - if(out.tx->vout[out.i].nValue == 1000*COIN){ //exactly - vin = CTxIn(out.tx->GetHash(),out.i); - pubScript = out.tx->vout[out.i].scriptPubKey; // the inputs PubKey - nValueRet = out.tx->vout[out.i].nValue; - return true; - } - } - - return false; -} bool CWallet::SelectCoinsMinConf(int64_t nTargetValue, int nConfMine, int nConfTheirs, vector vCoins, set >& setCoinsRet, int64_t& nValueRet) const diff --git a/src/wallet.h b/src/wallet.h index f3d3066e8..36ba01fe1 100644 --- a/src/wallet.h +++ b/src/wallet.h @@ -7,7 +7,6 @@ #define BITCOIN_WALLET_H #include "core.h" -#include "darksend.h" #include "crypter.h" #include "key.h" #include "keystore.h"