Merge pull request #197 from UdjinM6/v0.11.2.x_masternodemanager

V0.11.2.x masternodemanager
This commit is contained in:
evan82 2015-02-25 18:26:05 -07:00
commit 97d88a6fa7
21 changed files with 1216 additions and 730 deletions

View File

@ -52,6 +52,7 @@ BITCOIN_CORE_H = \
limitedmap.h \
main.h \
masternode.h \
masternodeman.h \
masternodeconfig.h \
miner.h \
mruset.h \
@ -151,6 +152,7 @@ libdarkcoin_common_a_SOURCES = \
core.cpp \
darksend.cpp \
masternode.cpp \
masternodeman.cpp \
masternodeconfig.cpp \
instantx.cpp \
hash.cpp \

View File

@ -2,6 +2,7 @@
#include "core.h"
#include "protocol.h"
#include "activemasternode.h"
#include "masternodeman.h"
#include <boost/lexical_cast.hpp>
//
@ -200,16 +201,13 @@ bool CActiveMasternode::Dseep(CTxIn vin, CService service, CKey keyMasternode, C
}
// Update Last Seen timestamp in masternode list
bool found = false;
BOOST_FOREACH(CMasterNode& mn, vecMasternodes) {
//LogPrintf(" -- %s\n", mn.vin.ToString().c_str());
if(mn.vin == vin) {
found = true;
mn.UpdateLastSeen();
}
CMasternode* pmn = mnodeman.Find(vin);
if(pmn != NULL)
{
pmn->UpdateLastSeen();
}
if(!found){
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::Dseep() - Error: %s\n", retErrorMessage.c_str());
@ -269,16 +267,13 @@ bool CActiveMasternode::Register(CTxIn vin, CService service, CKey keyCollateral
return false;
}
bool found = false;
BOOST_FOREACH(CMasterNode& mn, vecMasternodes)
if(mn.vin == vin)
found = true;
if(!found) {
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());
CMasterNode mn(service, vin, pubKeyCollateralAddress, vchMasterNodeSignature, masterNodeSignatureTime, pubKeyMasternode, PROTOCOL_VERSION);
CMasternode mn(service, vin, pubKeyCollateralAddress, vchMasterNodeSignature, masterNodeSignatureTime, pubKeyMasternode, PROTOCOL_VERSION);
mn.UpdateLastSeen(masterNodeSignatureTime);
vecMasternodes.push_back(mn);
mnodeman.Add(mn);
}
//send to all peers
@ -378,32 +373,6 @@ vector<COutput> CActiveMasternode::SelectCoinsMasternode()
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)
{

View File

@ -52,8 +52,6 @@ public:
vector<COutput> SelectCoinsMasternode();
bool GetVinFromOutput(COutput out, CTxIn& vin, CPubKey& pubkey, CKey& secretKey);
//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, CService& addr);
};

View File

@ -10,7 +10,7 @@
#include "main.h"
#include "init.h"
#include "util.h"
#include "masternode.h"
#include "masternodeman.h"
#include "instantx.h"
#include "ui_interface.h"
@ -121,17 +121,18 @@ void ProcessMessageDarksend(CNode* pfrom, std::string& strCommand, CDataStream&
vRecv >> nDenom >> txCollateral;
std::string error = "";
int mn = GetMasternodeByVin(activeMasternode.vin);
if(mn == -1){
CMasternode* pmn = mnodeman.Find(activeMasternode.vin);
if(pmn == NULL)
{
std::string strError = _("Not in the masternode list.");
pfrom->PushMessage("dssu", darkSendPool.sessionID, darkSendPool.GetState(), darkSendPool.GetEntriesCount(), MASTERNODE_REJECTED, strError);
return;
}
if(darkSendPool.sessionUsers == 0) {
if(vecMasternodes[mn].nLastDsq != 0 &&
vecMasternodes[mn].nLastDsq + CountMasternodesAboveProtocol(darkSendPool.MIN_PEER_PROTO_VERSION)/5 > darkSendPool.nDsqCount){
//LogPrintf("dsa -- last dsq too recent, must wait. %s \n", vecMasternodes[mn].addr.ToString().c_str());
if(pmn->nLastDsq != 0 &&
pmn->nLastDsq + mnodeman.CountMasternodesAboveProtocol(darkSendPool.MIN_PEER_PROTO_VERSION)/5 > darkSendPool.nDsqCount){
LogPrintf("dsa -- last dsq too recent, must wait. %s \n", pmn->addr.ToString().c_str());
std::string strError = _("Last Darksend was too recent.");
pfrom->PushMessage("dssu", darkSendPool.sessionID, darkSendPool.GetState(), darkSendPool.GetEntriesCount(), MASTERNODE_REJECTED, strError);
return;
@ -164,8 +165,8 @@ void ProcessMessageDarksend(CNode* pfrom, std::string& strCommand, CDataStream&
if(dsq.IsExpired()) return;
int mn = GetMasternodeByVin(dsq.vin);
if(mn == -1) return;
CMasternode* pmn = mnodeman.Find(dsq.vin);
if(pmn == NULL) return;
// if the queue is ready, submit if we can
if(dsq.ready) {
@ -181,16 +182,16 @@ void ProcessMessageDarksend(CNode* pfrom, std::string& strCommand, CDataStream&
if(q.vin == dsq.vin) return;
}
if(fDebug) LogPrintf("dsq last %d last2 %d count %d\n", vecMasternodes[mn].nLastDsq, vecMasternodes[mn].nLastDsq + (int)vecMasternodes.size()/5, darkSendPool.nDsqCount);
if(fDebug) LogPrintf("dsq last %d last2 %d count %d\n", pmn->nLastDsq, pmn->nLastDsq + mnodeman.size()/5, darkSendPool.nDsqCount);
//don't allow a few nodes to dominate the queuing process
if(vecMasternodes[mn].nLastDsq != 0 &&
vecMasternodes[mn].nLastDsq + CountMasternodesAboveProtocol(darkSendPool.MIN_PEER_PROTO_VERSION)/5 > darkSendPool.nDsqCount){
if(fDebug) LogPrintf("dsq -- masternode sending too many dsq messages. %s \n", vecMasternodes[mn].addr.ToString().c_str());
if(pmn->nLastDsq != 0 &&
pmn->nLastDsq + mnodeman.CountMasternodesAboveProtocol(darkSendPool.MIN_PEER_PROTO_VERSION)/5 > darkSendPool.nDsqCount){
if(fDebug) LogPrintf("dsq -- masternode sending too many dsq messages. %s \n", pmn->addr.ToString().c_str());
return;
}
darkSendPool.nDsqCount++;
vecMasternodes[mn].nLastDsq = darkSendPool.nDsqCount;
vecMasternodes[mn].allowFreeTx = true;
pmn->nLastDsq = darkSendPool.nDsqCount;
pmn->allowFreeTx = true;
if(fDebug) LogPrintf("dsq - new darksend queue object - %s\n", addr.ToString().c_str());
vecDarksendQueue.push_back(dsq);
@ -484,6 +485,23 @@ int GetInputDarksendRounds(CTxIn in, int rounds)
return rounds-1;
}
// manage the masternode connections
void CDarkSendPool::ProcessMasternodeConnections()
{
LOCK(cs_vNodes);
BOOST_FOREACH(CNode* pnode, vNodes)
{
//if it's our masternode, let it be
if(submittedToMasternode == pnode->addr) continue;
if(pnode->fDarkSendMaster){
LogPrintf("Closing masternode connection %s \n", pnode->addr.ToString().c_str());
pnode->CloseSocketDisconnect();
}
}
}
void CDarkSendPool::Reset(){
cachedLastSuccess = 0;
vecMasternodesUsed.clear();
@ -1357,7 +1375,6 @@ void CDarkSendPool::NewBlock()
if(!fMasterNode){
//denominate all non-denominated inputs every 25 minutes.
if(chainActive.Tip()->nHeight % 10 == 0) UnlockCoins();
ProcessMasternodeConnections();
}
}
@ -1426,7 +1443,7 @@ bool CDarkSendPool::DoAutomaticDenominating(bool fDryRun, bool ready)
}
}
if(vecMasternodes.size() == 0){
if(mnodeman.size() == 0){
if(fDebug) LogPrintf("CDarkSendPool::DoAutomaticDenominating - No masternodes detected\n");
strAutoDenomResult = _("No masternodes detected.");
return false;
@ -1579,40 +1596,39 @@ bool CDarkSendPool::DoAutomaticDenominating(bool fDryRun, bool ready)
}
}
//shuffle masternodes around before we try to connect
std::random_shuffle ( vecMasternodes.begin(), vecMasternodes.end() );
int i = 0;
// otherwise, try one randomly
while(i < 10)
{
CMasternode* mn = mnodeman.FindRandom();
//don't reuse masternodes
BOOST_FOREACH(CTxIn usedVin, vecMasternodesUsed) {
if(vecMasternodes[i].vin == usedVin){
if(mn->vin == usedVin){
i++;
continue;
}
}
if(vecMasternodes[i].protocolVersion < MIN_PEER_PROTO_VERSION) {
if(mn->protocolVersion < darkSendPool.MIN_PEER_PROTO_VERSION) {
i++;
continue;
}
if(vecMasternodes[i].nLastDsq != 0 &&
vecMasternodes[i].nLastDsq + CountMasternodesAboveProtocol(darkSendPool.MIN_PEER_PROTO_VERSION)/5 > darkSendPool.nDsqCount){
if(mn->nLastDsq != 0 &&
mn->nLastDsq + mnodeman.CountMasternodesAboveProtocol(darkSendPool.MIN_PEER_PROTO_VERSION)/5 > darkSendPool.nDsqCount){
i++;
continue;
}
lastTimeChanged = GetTimeMillis();
LogPrintf("DoAutomaticDenominating -- attempt %d connection to masternode %s\n", i, vecMasternodes[i].addr.ToString().c_str());
if(ConnectNode((CAddress)vecMasternodes[i].addr, NULL, true)){
submittedToMasternode = vecMasternodes[i].addr;
submittedToMasternode = mn->addr;
LogPrintf("DoAutomaticDenominating -- attempt %d connection to masternode %s\n", i, mn->addr.ToString().c_str());
if(ConnectNode((CAddress)mn->addr, NULL, true)){
LOCK(cs_vNodes);
BOOST_FOREACH(CNode* pnode, vNodes)
{
if((CNetAddr)pnode->addr != (CNetAddr)vecMasternodes[i].addr) continue;
if((CNetAddr)pnode->addr != (CNetAddr)mn->addr) continue;
std::string strReason;
if(txCollateral == CTransaction()){
@ -1622,7 +1638,7 @@ bool CDarkSendPool::DoAutomaticDenominating(bool fDryRun, bool ready)
}
}
vecMasternodesUsed.push_back(vecMasternodes[i].vin);
vecMasternodesUsed.push_back(mn->vin);
std::vector<int64_t> vecAmounts;
pwalletMain->ConvertList(vCoins, vecAmounts);
@ -2115,18 +2131,18 @@ bool CDarksendQueue::Relay()
bool CDarksendQueue::CheckSignature()
{
BOOST_FOREACH(CMasterNode& mn, vecMasternodes) {
CMasternode* pmn = mnodeman.Find(vin);
if(mn.vin == vin) {
std::string strMessage = vin.ToString() + boost::lexical_cast<std::string>(nDenom) + boost::lexical_cast<std::string>(time) + boost::lexical_cast<std::string>(ready);
if(pmn != NULL)
{
std::string strMessage = vin.ToString() + boost::lexical_cast<std::string>(nDenom) + boost::lexical_cast<std::string>(time) + boost::lexical_cast<std::string>(ready);
std::string errorMessage = "";
if(!darkSendSigner.VerifyMessage(mn.pubkey2, vchSig, strMessage, errorMessage)){
return error("CDarksendQueue::CheckSignature() - Got bad masternode address signature %s \n", vin.ToString().c_str());
}
return true;
std::string errorMessage = "";
if(!darkSendSigner.VerifyMessage(pmn->pubkey2, vchSig, strMessage, errorMessage)){
return error("CDarksendQueue::CheckSignature() - Got bad masternode address signature %s \n", vin.ToString().c_str());
}
return true;
}
return false;
@ -2152,36 +2168,24 @@ void ThreadCheckDarkSendPool()
//LogPrintf("ThreadCheckDarkSendPool::check timeout\n");
darkSendPool.CheckTimeout();
if(c % 60 == 0){
if(c % 60 == 0)
{
LOCK(cs_main);
/*
cs_main is required for doing masternode.Check because something
cs_main is required for doing CMasternode.Check because something
is modifying the coins view without a mempool lock. It causes
segfaults from this code without the cs_main lock.
*/
vector<CMasterNode>::iterator it = vecMasternodes.begin();
//check them separately
while(it != vecMasternodes.end()){
(*it).Check();
++it;
}
//remove inactive
it = vecMasternodes.begin();
while(it != vecMasternodes.end()){
if((*it).enabled == 4 || (*it).enabled == 3){
LogPrintf("Removing inactive masternode %s\n", (*it).addr.ToString().c_str());
it = vecMasternodes.erase(it);
} else {
++it;
}
}
mnodeman.CheckAndRemove();
darkSendPool.ProcessMasternodeConnections();
masternodePayments.CleanPaymentList();
CleanTransactionLocksList();
}
if(c % MASTERNODE_PING_SECONDS == 0) activeMasternode.ManageStatus();
if(c % MASTERNODES_DUMP_SECONDS == 0) DumpMasternodes();
//try to sync the masternode list and payment list every 5 seconds from at least 3 nodes
if(c % 5 == 0 && RequestedMasterNodeList < 3){
bool fIsInitialDownload = IsInitialBlockDownload();
@ -2197,7 +2201,9 @@ void ThreadCheckDarkSendPool()
LogPrintf("Successfully synced, asking for Masternode list and payment list\n");
pnode->PushMessage("dseg", CTxIn()); //request full mn list
//request full mn list only if masternodes.dat was updated quite a long time ago
mnodeman.DsegUpdate(pnode);
pnode->PushMessage("mnget"); //sync payees
pnode->PushMessage("getsporks"); //get current network sporks
RequestedMasterNodeList++;
@ -2206,13 +2212,9 @@ void ThreadCheckDarkSendPool()
}
}
if(c % MASTERNODE_PING_SECONDS == 0){
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)vecMasternodes.size() / 5)
if((int)vecMasternodesUsed.size() > (int)mnodeman.size() / 5)
vecMasternodesUsed.clear();
}

View File

@ -7,8 +7,8 @@
#include "core.h"
#include "main.h"
#include "masternode.h"
#include "activemasternode.h"
#include "masternodeman.h"
class CTxIn;
class CDarkSendPool;
@ -157,22 +157,22 @@ public:
bool GetAddress(CService &addr)
{
BOOST_FOREACH(CMasterNode mn, vecMasternodes) {
if(mn.vin == vin){
addr = mn.addr;
return true;
}
CMasternode* pmn = mnodeman.Find(vin);
if(pmn != NULL)
{
addr = pmn->addr;
return true;
}
return false;
}
bool GetProtocolVersion(int &protocolVersion)
{
BOOST_FOREACH(CMasterNode mn, vecMasternodes) {
if(mn.vin == vin){
protocolVersion = mn.protocolVersion;
return true;
}
CMasternode* pmn = mnodeman.Find(vin);
if(pmn != NULL)
{
protocolVersion = pmn->protocolVersion;
return true;
}
return false;
}
@ -287,6 +287,8 @@ public:
SetNull();
}
void ProcessMasternodeConnections();
void InitCollateralAddress(){
std::string strAddress = "";
if(Params().NetworkID() == CChainParams::MAIN) {

View File

@ -21,6 +21,7 @@
#include "ui_interface.h"
#include "util.h"
#include "activemasternode.h"
#include "masternodeman.h"
#include "spork.h"
#ifdef ENABLE_WALLET
#include "db.h"
@ -147,6 +148,7 @@ void Shutdown()
GenerateBitcoins(false, NULL, 0);
#endif
StopNode();
DumpMasternodes();
UnregisterNodeSignals(GetNodeSignals());
{
LOCK(cs_main);
@ -1150,6 +1152,20 @@ bool AppInit2(boost::thread_group& threadGroup)
//CAddress addr;
//ConnectNode(addr, strNode.c_str(), true);
uiInterface.InitMessage(_("Loading masternode list..."));
nStart = GetTimeMillis();
{
CMasternodeDB mndb;
if (!mndb.Read(mnodeman))
LogPrintf("Invalid or missing masternodes.dat; recreating\n");
}
LogPrintf("Loaded %i masternodes from masternodes.dat %dms\n",
mnodeman.size(), GetTimeMillis() - nStart);
fMasterNode = GetBoolArg("-masternode", false);
if(fMasterNode) {
LogPrintf("IS DARKSEND MASTER NODE\n");

View File

@ -10,8 +10,8 @@
#include "base58.h"
#include "protocol.h"
#include "instantx.h"
#include "masternode.h"
#include "activemasternode.h"
#include "masternodeman.h"
#include "darksend.h"
#include "spork.h"
#include <boost/lexical_cast.hpp>
@ -259,7 +259,7 @@ void DoConsensusVote(CTransaction& tx, int64_t nBlockHeight)
{
if(!fMasterNode) return;
int n = GetMasternodeRank(activeMasternode.vin, nBlockHeight, MIN_INSTANTX_PROTO_VERSION);
int n = mnodeman.GetMasternodeRank(activeMasternode.vin, nBlockHeight, MIN_INSTANTX_PROTO_VERSION);
if(n == -1)
{
@ -307,11 +307,12 @@ void DoConsensusVote(CTransaction& tx, int64_t nBlockHeight)
//received a consensus vote
bool ProcessConsensusVote(CConsensusVote& ctx)
{
int n = GetMasternodeRank(ctx.vinMasternode, ctx.nBlockHeight, MIN_INSTANTX_PROTO_VERSION);
int n = mnodeman.GetMasternodeRank(ctx.vinMasternode, ctx.nBlockHeight, MIN_INSTANTX_PROTO_VERSION);
int x = GetMasternodeByVin(ctx.vinMasternode);
if(x != -1){
if(fDebug) LogPrintf("InstantX::ProcessConsensusVote - Masternode ADDR %s %d\n", vecMasternodes[x].addr.ToString().c_str(), n);
CMasternode* pmn = mnodeman.Find(ctx.vinMasternode);
if(pmn != NULL)
{
if(fDebug) LogPrintf("InstantX::ProcessConsensusVote - Masternode ADDR %s %d\n", pmn->addr.ToString().c_str(), n);
}
if(n == -1)
@ -480,9 +481,9 @@ bool CConsensusVote::SignatureValid()
std::string strMessage = txHash.ToString().c_str() + boost::lexical_cast<std::string>(nBlockHeight);
//LogPrintf("verify strMessage %s \n", strMessage.c_str());
int n = GetMasternodeByVin(vinMasternode);
CMasternode* pmn = mnodeman.Find(vinMasternode);
if(n == -1)
if(pmn == NULL)
{
LogPrintf("InstantX::CConsensusVote::SignatureValid() - Unknown Masternode\n");
return false;
@ -493,13 +494,13 @@ bool CConsensusVote::SignatureValid()
//LogPrintf("verify addr %d %s \n", n, vecMasternodes[n].addr.ToString().c_str());
CScript pubkey;
pubkey.SetDestination(vecMasternodes[n].pubkey2.GetID());
pubkey.SetDestination(pmn->pubkey2.GetID());
CTxDestination address1;
ExtractDestination(pubkey, address1);
CBitcoinAddress address2(address1);
//LogPrintf("verify pubkey2 %s \n", address2.ToString().c_str());
if(!darkSendSigner.VerifyMessage(vecMasternodes[n].pubkey2, vchMasterNodeSignature, strMessage, errorMessage)) {
if(!darkSendSigner.VerifyMessage(pmn->pubkey2, vchMasterNodeSignature, strMessage, errorMessage)) {
LogPrintf("InstantX::CConsensusVote::SignatureValid() - Verify message failed\n");
return false;
}
@ -549,7 +550,7 @@ bool CTransactionLock::SignaturesValid()
BOOST_FOREACH(CConsensusVote vote, vecConsensusVotes)
{
int n = GetMasternodeRank(vote.vinMasternode, vote.nBlockHeight, MIN_INSTANTX_PROTO_VERSION);
int n = mnodeman.GetMasternodeRank(vote.vinMasternode, vote.nBlockHeight, MIN_INSTANTX_PROTO_VERSION);
if(n == -1)
{

View File

@ -14,7 +14,7 @@
#include "init.h"
#include "instantx.h"
#include "darksend.h"
#include "masternode.h"
#include "masternodeman.h"
#include "net.h"
#include "txdb.h"
#include "txmempool.h"
@ -4457,37 +4457,37 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
//these allow masternodes to publish a limited amount of free transactions
vRecv >> tx >> vin >> vchSig >> sigTime;
BOOST_FOREACH(CMasterNode& mn, vecMasternodes) {
if(mn.vin == vin) {
if(!mn.allowFreeTx){
//multiple peers can send us a valid masternode transaction
if(fDebug) LogPrintf("dstx: Masternode sending too many transactions %s\n", tx.GetHash().ToString().c_str());
return true;
}
CMasternode* pmn = mnodeman.Find(vin);
if(pmn != NULL)
{
if(!pmn->allowFreeTx){
//multiple peers can send us a valid masternode transaction
if(fDebug) LogPrintf("dstx: Masternode sending too many transactions %s\n", tx.GetHash().ToString().c_str());
return true;
}
std::string strMessage = tx.GetHash().ToString() + boost::lexical_cast<std::string>(sigTime);
std::string strMessage = tx.GetHash().ToString() + boost::lexical_cast<std::string>(sigTime);
std::string errorMessage = "";
if(!darkSendSigner.VerifyMessage(mn.pubkey2, vchSig, strMessage, errorMessage)){
LogPrintf("dstx: Got bad masternode address signature %s \n", vin.ToString().c_str());
//pfrom->Misbehaving(20);
return false;
}
std::string errorMessage = "";
if(!darkSendSigner.VerifyMessage(pmn->pubkey2, vchSig, strMessage, errorMessage)){
LogPrintf("dstx: Got bad masternode address signature %s \n", vin.ToString().c_str());
//pfrom->Misbehaving(20);
return false;
}
LogPrintf("dstx: Got Masternode transaction %s\n", tx.GetHash().ToString().c_str());
LogPrintf("dstx: Got Masternode transaction %s\n", tx.GetHash().ToString().c_str());
allowFree = true;
mn.allowFreeTx = false;
allowFree = true;
pmn->allowFreeTx = false;
if(!mapDarksendBroadcastTxes.count(tx.GetHash())){
CDarksendBroadcastTx dstx;
dstx.tx = tx;
dstx.vin = vin;
dstx.vchSig = vchSig;
dstx.sigTime = sigTime;
if(!mapDarksendBroadcastTxes.count(tx.GetHash())){
CDarksendBroadcastTx dstx;
dstx.tx = tx;
dstx.vin = vin;
dstx.vchSig = vchSig;
dstx.sigTime = sigTime;
mapDarksendBroadcastTxes.insert(make_pair(tx.GetHash(), dstx));
}
mapDarksendBroadcastTxes.insert(make_pair(tx.GetHash(), dstx));
}
}
}
@ -4825,7 +4825,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
{
//probably one the extensions
ProcessMessageDarksend(pfrom, strCommand, vRecv);
ProcessMessageMasternode(pfrom, strCommand, vRecv);
mnodeman.ProcessMessage(pfrom, strCommand, vRecv);
ProcessMessageInstantX(pfrom, strCommand, vRecv);
ProcessSpork(pfrom, strCommand, vRecv);
}

View File

@ -1,321 +1,27 @@
// Copyright (c) 2014-2015 The Darkcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "masternode.h"
#include "activemasternode.h"
#include "masternodeman.h"
#include "darksend.h"
#include "core.h"
#include "util.h"
#include "addrman.h"
#include <boost/lexical_cast.hpp>
/** The list of active masternodes */
std::vector<CMasterNode> vecMasternodes;
/** Object for who's going to get paid on which blocks */
CMasternodePayments masternodePayments;
// keep track of masternode votes I've seen
map<uint256, CMasternodePaymentWinner> mapSeenMasternodeVotes;
// keep track of the scanning errors I've seen
map<uint256, int> mapSeenMasternodeScanningErrors;
// who's asked for the masternode list and the last time
std::map<CNetAddr, int64_t> askedForMasternodeList;
// which masternodes we've asked for
std::map<COutPoint, int64_t> askedForMasternodeListEntry;
// cache block hashes as we calculate them
std::map<int64_t, uint256> mapCacheBlockHashes;
// manage the masternode connections
void ProcessMasternodeConnections(){
LOCK(cs_vNodes);
BOOST_FOREACH(CNode* pnode, vNodes)
{
//if it's our masternode, let it be
if(darkSendPool.submittedToMasternode == pnode->addr) continue;
if(pnode->fDarkSendMaster){
LogPrintf("Closing masternode connection %s \n", pnode->addr.ToString().c_str());
pnode->CloseSocketDisconnect();
}
}
}
void ProcessMessageMasternode(CNode* pfrom, std::string& strCommand, CDataStream& vRecv)
void ProcessMessageMasternodePayments(CNode* pfrom, std::string& strCommand, CDataStream& vRecv)
{
if (strCommand == "dsee") { //DarkSend Election Entry
if(fLiteMode) return; //disable all darksend/masternode related functionality
bool fIsInitialDownload = IsInitialBlockDownload();
if(fIsInitialDownload) return;
CTxIn vin;
CService addr;
CPubKey pubkey;
CPubKey pubkey2;
vector<unsigned char> vchSig;
int64_t sigTime;
int count;
int current;
int64_t lastUpdated;
int protocolVersion;
std::string strMessage;
// 70047 and greater
vRecv >> vin >> addr >> vchSig >> sigTime >> pubkey >> pubkey2 >> count >> current >> lastUpdated >> protocolVersion;
// make sure signature isn't in the future (past is OK)
if (sigTime > GetAdjustedTime() + 60 * 60) {
LogPrintf("dsee - Signature rejected, too far into the future %s\n", vin.ToString().c_str());
return;
}
bool isLocal = addr.IsRFC1918() || addr.IsLocal();
if(RegTest()) isLocal = false;
std::string vchPubKey(pubkey.begin(), pubkey.end());
std::string vchPubKey2(pubkey2.begin(), pubkey2.end());
strMessage = addr.ToString() + boost::lexical_cast<std::string>(sigTime) + vchPubKey + vchPubKey2 + boost::lexical_cast<std::string>(protocolVersion);
if(protocolVersion < nMasternodeMinProtocol) {
LogPrintf("dsee - ignoring outdated masternode %s protocol version %d\n", vin.ToString().c_str(), protocolVersion);
return;
}
CScript pubkeyScript;
pubkeyScript.SetDestination(pubkey.GetID());
if(pubkeyScript.size() != 25) {
LogPrintf("dsee - pubkey the wrong size\n");
Misbehaving(pfrom->GetId(), 100);
return;
}
CScript pubkeyScript2;
pubkeyScript2.SetDestination(pubkey2.GetID());
if(pubkeyScript2.size() != 25) {
LogPrintf("dsee - pubkey2 the wrong size\n");
Misbehaving(pfrom->GetId(), 100);
return;
}
std::string errorMessage = "";
if(!darkSendSigner.VerifyMessage(pubkey, vchSig, strMessage, errorMessage)){
LogPrintf("dsee - Got bad masternode address signature\n");
Misbehaving(pfrom->GetId(), 100);
return;
}
if(Params().NetworkID() == CChainParams::MAIN){
if(addr.GetPort() != 9999) return;
}
//search existing masternode list, this is where we update existing masternodes with new dsee broadcasts
BOOST_FOREACH(CMasterNode& mn, vecMasternodes) {
if(mn.vin.prevout == vin.prevout) {
// count == -1 when it's a new entry
// e.g. We don't want the entry relayed/time updated when we're syncing the list
// mn.pubkey = pubkey, IsVinAssociatedWithPubkey is validated once below,
// after that they just need to match
if(count == -1 && mn.pubkey == pubkey && !mn.UpdatedWithin(MASTERNODE_MIN_DSEE_SECONDS)){
mn.UpdateLastSeen();
if(mn.now < sigTime){ //take the newest entry
LogPrintf("dsee - Got updated entry for %s\n", addr.ToString().c_str());
mn.pubkey2 = pubkey2;
mn.now = sigTime;
mn.sig = vchSig;
mn.protocolVersion = protocolVersion;
mn.addr = addr;
RelayDarkSendElectionEntry(vin, addr, vchSig, sigTime, pubkey, pubkey2, count, current, lastUpdated, protocolVersion);
}
}
return;
}
}
// make sure the vout that was signed is related to the transaction that spawned the masternode
// - this is expensive, so it's only done once per masternode
if(!darkSendSigner.IsVinAssociatedWithPubkey(vin, pubkey)) {
LogPrintf("dsee - Got mismatched pubkey and vin\n");
Misbehaving(pfrom->GetId(), 100);
return;
}
if(fDebug) LogPrintf("dsee - Got NEW masternode entry %s\n", addr.ToString().c_str());
// make sure it's still unspent
// - this is checked later by .check() in many places and by ThreadCheckDarkSendPool()
CValidationState state;
CTransaction tx = CTransaction();
CTxOut vout = CTxOut(999.99*COIN, darkSendPool.collateralPubKey);
tx.vin.push_back(vin);
tx.vout.push_back(vout);
if(AcceptableInputs(mempool, state, tx)){
if(fDebug) LogPrintf("dsee - Accepted masternode entry %i %i\n", count, current);
if(GetInputAge(vin) < MASTERNODE_MIN_CONFIRMATIONS){
LogPrintf("dsee - Input must have least %d confirmations\n", MASTERNODE_MIN_CONFIRMATIONS);
Misbehaving(pfrom->GetId(), 20);
return;
}
// use this as a peer
addrman.Add(CAddress(addr), pfrom->addr, 2*60*60);
// add our masternode
CMasterNode mn(addr, vin, pubkey, vchSig, sigTime, pubkey2, protocolVersion);
mn.UpdateLastSeen(lastUpdated);
vecMasternodes.push_back(mn);
// 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);
} else {
LogPrintf("dsee - Rejected masternode entry %s\n", addr.ToString().c_str());
int nDoS = 0;
if (state.IsInvalid(nDoS))
{
LogPrintf("dsee - %s from %s %s was not accepted into the memory pool\n", tx.GetHash().ToString().c_str(),
pfrom->addr.ToString().c_str(), pfrom->cleanSubVer.c_str());
if (nDoS > 0)
Misbehaving(pfrom->GetId(), nDoS);
}
}
}
else if (strCommand == "dseep") { //DarkSend Election Entry Ping
if(fLiteMode) return; //disable all darksend/masternode related functionality
bool fIsInitialDownload = IsInitialBlockDownload();
if(fIsInitialDownload) return;
CTxIn vin;
vector<unsigned char> vchSig;
int64_t sigTime;
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;
}
if (sigTime <= GetAdjustedTime() - 60 * 60) {
LogPrintf("dseep - Signature rejected, too far into the past %s - %d %d \n", vin.ToString().c_str(), sigTime, GetAdjustedTime());
return;
}
// see if we have this masternode
BOOST_FOREACH(CMasterNode& mn, vecMasternodes) {
if(mn.vin.prevout == vin.prevout) {
// 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<std::string>(sigTime) + boost::lexical_cast<std::string>(stop);
std::string errorMessage = "";
if(!darkSendSigner.VerifyMessage(mn.pubkey2, vchSig, strMessage, errorMessage)){
LogPrintf("dseep - Got bad masternode address signature %s \n", vin.ToString().c_str());
//Misbehaving(pfrom->GetId(), 100);
return;
}
mn.lastDseep = sigTime;
if(!mn.UpdatedWithin(MASTERNODE_MIN_DSEEP_SECONDS)){
mn.UpdateLastSeen();
if(stop) {
mn.Disable();
mn.Check();
}
RelayDarkSendElectionEntryPing(vin, vchSig, sigTime, stop);
}
}
return;
}
}
if(fDebug) LogPrintf("dseep - Couldn't find masternode entry %s\n", vin.ToString().c_str());
std::map<COutPoint, int64_t>::iterator i = askedForMasternodeListEntry.find(vin.prevout);
if (i != askedForMasternodeListEntry.end()){
int64_t t = (*i).second;
if (GetTime() < t) {
// we've asked recently
return;
}
}
// ask for the dsee info once from the node that sent dseep
LogPrintf("dseep - Asking source node for missing entry %s\n", vin.ToString().c_str());
pfrom->PushMessage("dseg", vin);
int64_t askAgain = GetTime()+(60*60*24);
askedForMasternodeListEntry[vin.prevout] = askAgain;
} else if (strCommand == "dseg") { //Get masternode list or specific entry
if(fLiteMode) return; //disable all darksend/masternode related functionality
CTxIn vin;
vRecv >> vin;
if(vin == CTxIn()) { //only should ask for this once
//local network
if(!pfrom->addr.IsRFC1918() && Params().NetworkID() == CChainParams::MAIN)
{
std::map<CNetAddr, int64_t>::iterator i = askedForMasternodeList.find(pfrom->addr);
if (i != askedForMasternodeList.end())
{
int64_t t = (*i).second;
if (GetTime() < t) {
Misbehaving(pfrom->GetId(), 34);
LogPrintf("dseg - peer already asked me for the list\n");
return;
}
}
int64_t askAgain = GetTime()+(60*60*3);
askedForMasternodeList[pfrom->addr] = askAgain;
}
} //else, asking for a specific node which is ok
int count = vecMasternodes.size();
int i = 0;
BOOST_FOREACH(CMasterNode mn, vecMasternodes) {
if(mn.addr.IsRFC1918()) continue; //local network
if(vin == CTxIn()){
mn.Check();
if(mn.IsEnabled()) {
if(fDebug) LogPrintf("dseg - Sending masternode entry - %s \n", mn.addr.ToString().c_str());
pfrom->PushMessage("dsee", mn.vin, mn.addr, mn.sig, mn.now, mn.pubkey, mn.pubkey2, count, i, mn.lastTimeSeen, mn.protocolVersion);
}
} else if (vin == mn.vin) {
if(fDebug) LogPrintf("dseg - Sending masternode entry - %s \n", mn.addr.ToString().c_str());
pfrom->PushMessage("dsee", mn.vin, mn.addr, mn.sig, mn.now, mn.pubkey, mn.pubkey2, count, i, mn.lastTimeSeen, mn.protocolVersion);
LogPrintf("dseg - Sent 1 masternode entries to %s\n", pfrom->addr.ToString().c_str());
return;
}
i++;
}
LogPrintf("dseg - Sent %d masternode entries to %s\n", count, pfrom->addr.ToString().c_str());
}
else if (strCommand == "mnget") { //Masternode Payments Request Sync
if (strCommand == "mnget") { //Masternode Payments Request Sync
if(fLiteMode) return; //disable all darksend/masternode related functionality
if(pfrom->HasFulfilledRequest("mnget")) {
@ -378,138 +84,6 @@ struct CompareValueOnly
}
};
struct CompareValueOnly2
{
bool operator()(const pair<int64_t, int>& t1,
const pair<int64_t, int>& t2) const
{
return t1.first < t2.first;
}
};
int CountMasternodesAboveProtocol(int protocolVersion)
{
int i = 0;
BOOST_FOREACH(CMasterNode& mn, vecMasternodes) {
if(mn.protocolVersion < protocolVersion) continue;
i++;
}
return i;
}
int GetMasternodeByVin(CTxIn& vin)
{
int i = 0;
BOOST_FOREACH(CMasterNode& mn, vecMasternodes) {
if (mn.vin == vin) return i;
i++;
}
return -1;
}
int GetCurrentMasterNode(int mod, int64_t nBlockHeight, int minProtocol)
{
int i = 0;
unsigned int score = 0;
int winner = -1;
// scan for winner
BOOST_FOREACH(CMasterNode mn, vecMasternodes) {
mn.Check();
if(mn.protocolVersion < minProtocol) continue;
if(!mn.IsEnabled()) {
i++;
continue;
}
// calculate the score for each masternode
uint256 n = mn.CalculateScore(mod, nBlockHeight);
unsigned int n2 = 0;
memcpy(&n2, &n, sizeof(n2));
// determine the winner
if(n2 > score){
score = n2;
winner = i;
}
i++;
}
return winner;
}
int GetMasternodeByRank(int findRank, int64_t nBlockHeight, int minProtocol)
{
int i = 0;
std::vector<pair<unsigned int, int> > vecMasternodeScores;
i = 0;
BOOST_FOREACH(CMasterNode mn, vecMasternodes) {
mn.Check();
if(mn.protocolVersion < minProtocol) continue;
if(!mn.IsEnabled()) {
i++;
continue;
}
uint256 n = mn.CalculateScore(1, nBlockHeight);
unsigned int n2 = 0;
memcpy(&n2, &n, sizeof(n2));
vecMasternodeScores.push_back(make_pair(n2, i));
i++;
}
sort(vecMasternodeScores.rbegin(), vecMasternodeScores.rend(), CompareValueOnly2());
int rank = 0;
BOOST_FOREACH (PAIRTYPE(unsigned int, int)& s, vecMasternodeScores){
rank++;
if(rank == findRank) return s.second;
}
return -1;
}
int GetMasternodeRank(CTxIn& vin, int64_t nBlockHeight, int minProtocol)
{
std::vector<pair<unsigned int, CTxIn> > vecMasternodeScores;
BOOST_FOREACH(CMasterNode& mn, vecMasternodes) {
mn.Check();
if(mn.protocolVersion < minProtocol) continue;
if(!mn.IsEnabled()) {
continue;
}
uint256 n = mn.CalculateScore(1, nBlockHeight);
unsigned int n2 = 0;
memcpy(&n2, &n, sizeof(n2));
vecMasternodeScores.push_back(make_pair(n2, mn.vin));
}
sort(vecMasternodeScores.rbegin(), vecMasternodeScores.rend(), CompareValueOnly());
unsigned int rank = 0;
BOOST_FOREACH (PAIRTYPE(unsigned int, CTxIn)& s, vecMasternodeScores){
rank++;
if(s.second == vin) {
return rank;
}
}
return -1;
}
//Get the last hash that matches the modulus given. Processed in reverse order
bool GetBlockHash(uint256& hash, int nBlockHeight)
{
@ -548,12 +122,72 @@ bool GetBlockHash(uint256& hash, int nBlockHeight)
return false;
}
CMasternode::CMasternode()
{
LOCK(cs);
vin = CTxIn();
addr = CService();
pubkey = CPubKey();
pubkey2 = CPubKey();
sig = std::vector<unsigned char>();
activeState = MASTERNODE_ENABLED;
now = GetTime();
lastDseep = 0;
lastTimeSeen = 0;
cacheInputAge = 0;
cacheInputAgeBlock = 0;
unitTest = false;
allowFreeTx = true;
protocolVersion = MIN_PEER_PROTO_VERSION;
nLastDsq = 0;
}
CMasternode::CMasternode(const CMasternode& other)
{
LOCK(cs);
vin = other.vin;
addr = other.addr;
pubkey = other.pubkey;
pubkey2 = other.pubkey2;
sig = other.sig;
activeState = other.activeState;
now = other.now;
lastDseep = other.lastDseep;
lastTimeSeen = other.lastTimeSeen;
cacheInputAge = other.cacheInputAge;
cacheInputAgeBlock = other.cacheInputAgeBlock;
unitTest = other.unitTest;
allowFreeTx = other.allowFreeTx;
protocolVersion = other.protocolVersion;
nLastDsq = other.nLastDsq;
}
CMasternode::CMasternode(CService newAddr, CTxIn newVin, CPubKey newPubkey, std::vector<unsigned char> newSig, int64_t newNow, CPubKey newPubkey2, int protocolVersionIn)
{
LOCK(cs);
vin = newVin;
addr = newAddr;
pubkey = newPubkey;
pubkey2 = newPubkey2;
sig = newSig;
activeState = MASTERNODE_ENABLED;
now = newNow;
lastDseep = 0;
lastTimeSeen = 0;
cacheInputAge = 0;
cacheInputAgeBlock = 0;
unitTest = false;
allowFreeTx = true;
protocolVersion = protocolVersionIn;
nLastDsq = 0;
}
//
// Deterministically calculate a given "score" for a masternode depending on how close it's hash is to
// the proof of work for that block. The further away they are the better, the furthest will win the election
// and get paid this block
//
uint256 CMasterNode::CalculateScore(int mod, int64_t nBlockHeight)
uint256 CMasternode::CalculateScore(int mod, int64_t nBlockHeight)
{
if(chainActive.Tip() == NULL) return 0;
@ -570,19 +204,19 @@ uint256 CMasterNode::CalculateScore(int mod, int64_t nBlockHeight)
return r;
}
void CMasterNode::Check()
void CMasternode::Check()
{
//once spent, stop doing the checks
if(enabled==3) return;
if(activeState == MASTERNODE_VIN_SPENT) return;
if(!UpdatedWithin(MASTERNODE_REMOVAL_SECONDS)){
enabled = 4;
activeState = MASTERNODE_REMOVE;
return;
}
if(!UpdatedWithin(MASTERNODE_EXPIRATION_SECONDS)){
enabled = 2;
activeState = MASTERNODE_EXPIRED;
return;
}
@ -594,12 +228,12 @@ void CMasterNode::Check()
tx.vout.push_back(vout);
if(!AcceptableInputs(mempool, state, tx)){
enabled = 3;
activeState = MASTERNODE_VIN_SPENT;
return;
}
}
enabled = 1; // OK
activeState = MASTERNODE_ENABLED; // OK
}
bool CMasternodePayments::CheckSignature(CMasternodePaymentWinner& winner)
@ -721,7 +355,7 @@ void CMasternodePayments::CleanPaymentList()
{
if(chainActive.Tip() == NULL) return;
int nLimit = std::max(((int)vecMasternodes.size())*2, 1000);
int nLimit = std::max(((int)mnodeman.size())*2, 1000);
vector<CMasternodePaymentWinner>::iterator it;
for(it=vWinning.begin();it<vWinning.end();it++){
@ -747,52 +381,37 @@ bool CMasternodePayments::ProcessBlock(int nBlockHeight)
vecLastPayments.push_back(winner.vin);
}
std::random_shuffle ( vecMasternodes.begin(), vecMasternodes.end() );
BOOST_FOREACH(CMasterNode& mn, vecMasternodes)
CMasternode *pmn = mnodeman.FindNotInVec(vecLastPayments);
if(pmn != NULL)
{
bool found = false;
BOOST_FOREACH(CTxIn& vin, vecLastPayments)
if(mn.vin == vin)
{
found = true;
break;
}
if(found) continue;
mn.Check();
if(!mn.IsEnabled()) continue;
newWinner.score = 0;
newWinner.nBlockHeight = nBlockHeight;
newWinner.vin = mn.vin;
newWinner.payee.SetDestination(mn.pubkey.GetID());
break;
newWinner.vin = pmn->vin;
newWinner.payee.SetDestination(pmn->pubkey.GetID());
}
//if we can't find new MN to get paid, pick first active MN counting back from the end of vecLastPayments list
if(newWinner.nBlockHeight == 0 && vecMasternodes.size() > 1)
if(newWinner.nBlockHeight == 0 && mnodeman.CountEnabled() > 0)
{
BOOST_REVERSE_FOREACH(CTxIn& vin, vecLastPayments)
BOOST_REVERSE_FOREACH(CTxIn& vinLP, vecLastPayments)
{
BOOST_FOREACH(CMasterNode& mn, vecMasternodes)
if(mn.vin == vin)
{
mn.Check();
if(!mn.IsEnabled()) break;
CMasternode* pmn = mnodeman.Find(vinLP);
if(pmn != NULL)
{
pmn->Check();
if(!pmn->IsEnabled()) continue;
newWinner.score = 0;
newWinner.nBlockHeight = nBlockHeight;
newWinner.vin = vin;
newWinner.payee.SetDestination(mn.pubkey.GetID());
break;
}
if(newWinner.nBlockHeight != 0) break; // we found active MN
newWinner.score = 0;
newWinner.nBlockHeight = nBlockHeight;
newWinner.vin = pmn->vin;
newWinner.payee.SetDestination(pmn->pubkey.GetID());
break; // we found active MN
}
}
}
if(newWinner.nBlockHeight == 0) return false;
if(Sign(newWinner))
{
if(AddWinningMasternode(newWinner))

View File

@ -16,9 +16,6 @@
#include "base58.h"
#include "main.h"
class CMasterNode;
class CMasternodePayments;
#define MASTERNODE_NOT_PROCESSED 0 // initial state
#define MASTERNODE_IS_CAPABLE 1
#define MASTERNODE_NOT_CAPABLE 2
@ -38,74 +35,121 @@ class CMasternodePayments;
using namespace std;
class CMasternode;
class CMasternodePayments;
class CMasternodePaymentWinner;
extern std::vector<CMasterNode> vecMasternodes;
extern CMasternodePayments masternodePayments;
extern std::vector<CTxIn> vecMasternodeAskedFor;
extern map<uint256, CMasternodePaymentWinner> mapSeenMasternodeVotes;
extern map<int64_t, uint256> mapCacheBlockHashes;
enum masternodeState {
MASTERNODE_ENABLED = 1,
MASTERNODE_EXPIRED = 2,
MASTERNODE_VIN_SPENT = 3,
MASTERNODE_REMOVE = 4
};
// manage the masternode connections
void ProcessMasternodeConnections();
int CountMasternodesAboveProtocol(int protocolVersion);
// Get the current winner for this block
int GetCurrentMasterNode(int mod=1, int64_t nBlockHeight=0, int minProtocol=0);
int GetMasternodeByVin(CTxIn& vin);
int GetMasternodeRank(CTxIn& vin, int64_t nBlockHeight=0, int minProtocol=0);
int GetMasternodeByRank(int findRank, int64_t nBlockHeight=0, int minProtocol=0);
void ProcessMessageMasternode(CNode* pfrom, std::string& strCommand, CDataStream& vRecv);
void ProcessMessageMasternodePayments(CNode* pfrom, std::string& strCommand, CDataStream& vRecv);
//
// The Masternode Class. For managing the darksend process. It contains the input of the 1000DRK, signature to prove
// it's the one who own that ip address and code for calculating the payment election.
//
class CMasterNode
class CMasternode
{
private:
// critical section to protect the inner data structures
mutable CCriticalSection cs;
public:
CService addr;
CTxIn vin;
int64_t lastTimeSeen;
CService addr;
CPubKey pubkey;
CPubKey pubkey2;
std::vector<unsigned char> sig;
int activeState;
int64_t now; //dsee message times
int64_t lastDseep;
int64_t lastTimeSeen;
int cacheInputAge;
int cacheInputAgeBlock;
int enabled;
bool unitTest;
bool allowFreeTx;
int protocolVersion;
int64_t nLastDsq; //the dsq count from the last dsq broadcast of this node
//the dsq count from the last dsq broadcast of this node
int64_t nLastDsq;
CMasternode();
CMasternode(const CMasternode& other);
CMasternode(CService newAddr, CTxIn newVin, CPubKey newPubkey, std::vector<unsigned char> newSig, int64_t newNow, CPubKey newPubkey2, int protocolVersionIn);
CMasterNode(CService newAddr, CTxIn newVin, CPubKey newPubkey, std::vector<unsigned char> newSig, int64_t newNow, CPubKey newPubkey2, int protocolVersionIn)
void swap(CMasternode& first, CMasternode& second) // nothrow
{
addr = newAddr;
vin = newVin;
pubkey = newPubkey;
pubkey2 = newPubkey2;
sig = newSig;
now = newNow;
enabled = 1;
lastTimeSeen = 0;
unitTest = false;
cacheInputAge = 0;
cacheInputAgeBlock = 0;
nLastDsq = 0;
lastDseep = 0;
allowFreeTx = true;
protocolVersion = protocolVersionIn;
// enable ADL (not necessary in our case, but good practice)
using std::swap;
// by swapping the members of two classes,
// the two classes are effectively swapped
swap(first.vin, second.vin);
swap(first.addr, second.addr);
swap(first.pubkey, second.pubkey);
swap(first.pubkey2, second.pubkey2);
swap(first.sig, second.sig);
swap(first.activeState, second.activeState);
swap(first.now, second.now);
swap(first.lastDseep, second.lastDseep);
swap(first.lastTimeSeen, second.lastTimeSeen);
swap(first.cacheInputAge, second.cacheInputAge);
swap(first.cacheInputAgeBlock, second.cacheInputAgeBlock);
swap(first.allowFreeTx, second.allowFreeTx);
swap(first.protocolVersion, second.protocolVersion);
swap(first.unitTest, second.unitTest);
swap(first.nLastDsq, second.nLastDsq);
}
CMasternode& operator=(CMasternode from)
{
swap(*this, from);
return *this;
}
friend bool operator==(const CMasternode& a, const CMasternode& b)
{
return a.vin == b.vin;
}
friend bool operator!=(const CMasternode& a, const CMasternode& b)
{
return !(a.vin == b.vin);
}
uint256 CalculateScore(int mod=1, int64_t nBlockHeight=0);
IMPLEMENT_SERIALIZE
(
// serialized format:
// * version byte (currently 0)
// * all fields (?)
{
LOCK(cs);
unsigned char nVersion = 0;
READWRITE(nVersion);
READWRITE(vin);
READWRITE(addr);
READWRITE(pubkey);
READWRITE(pubkey2);
READWRITE(sig);
READWRITE(activeState);
READWRITE(now);
READWRITE(lastDseep);
READWRITE(lastTimeSeen);
READWRITE(cacheInputAge);
READWRITE(cacheInputAgeBlock);
READWRITE(unitTest);
READWRITE(allowFreeTx);
READWRITE(protocolVersion);
READWRITE(nLastDsq);
}
)
void UpdateLastSeen(int64_t override=0)
{
if(override == 0){
@ -138,7 +182,7 @@ public:
bool IsEnabled()
{
return enabled == 1;
return activeState == MASTERNODE_ENABLED;
}
int GetMasternodeInputAge()
@ -154,7 +198,6 @@ public:
}
};
// for storing the winning payments
class CMasternodePaymentWinner
{
@ -227,7 +270,7 @@ public:
void Relay(CMasternodePaymentWinner& winner);
void Sync(CNode* node);
void CleanPaymentList();
int LastPayment(CMasterNode& mn);
int LastPayment(CMasternode& mn);
//slow
bool GetBlockPayee(int nBlockHeight, CScript& payee);
@ -276,5 +319,4 @@ public:
bool GetBlockPayee(int nBlockHeight, CScript& payee);
};*/
#endif

622
src/masternodeman.cpp Normal file
View File

@ -0,0 +1,622 @@
// Copyright (c) 2014-2015 The Darkcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "masternodeman.h"
#include "activemasternode.h"
#include "darksend.h"
#include "core.h"
#include "util.h"
#include "addrman.h"
#include <boost/lexical_cast.hpp>
#include <boost/filesystem.hpp>
/** Masternode manager */
CMasternodeMan mnodeman;
struct CompareValueOnly
{
bool operator()(const pair<int64_t, CTxIn>& t1,
const pair<int64_t, CTxIn>& t2) const
{
return t1.first < t2.first;
}
};
//
// CMasternodeDB
//
CMasternodeDB::CMasternodeDB()
{
pathMN = GetDataDir() / "masternodes.dat";
}
bool CMasternodeDB::Write(const CMasternodeMan& mnodemanToSave)
{
// serialize addresses, checksum data up to that point, then append csum
CDataStream ssMasternodes(SER_DISK, CLIENT_VERSION);
ssMasternodes << FLATDATA(Params().MessageStart());
ssMasternodes << mnodemanToSave;
uint256 hash = Hash(ssMasternodes.begin(), ssMasternodes.end());
ssMasternodes << hash;
// open output file, and associate with CAutoFile
FILE *file = fopen(pathMN.string().c_str(), "wb");
CAutoFile fileout = CAutoFile(file, SER_DISK, CLIENT_VERSION);
if (!fileout)
return error("%s : Failed to open file %s", __func__, pathMN.string());
// Write and commit header, data
try {
fileout << ssMasternodes;
}
catch (std::exception &e) {
return error("%s : Serialize or I/O error - %s", __func__, e.what());
}
FileCommit(fileout);
fileout.fclose();
return true;
}
bool CMasternodeDB::Read(CMasternodeMan& mnodemanToLoad)
{
// open input file, and associate with CAutoFile
FILE *file = fopen(pathMN.string().c_str(), "rb");
CAutoFile filein = CAutoFile(file, SER_DISK, CLIENT_VERSION);
if (!filein)
return error("%s : Failed to open file %s", __func__, pathMN.string());
// use file size to size memory buffer
int fileSize = boost::filesystem::file_size(pathMN);
int dataSize = fileSize - sizeof(uint256);
// Don't try to resize to a negative number if file is small
if (dataSize < 0)
dataSize = 0;
vector<unsigned char> vchData;
vchData.resize(dataSize);
uint256 hashIn;
// read data and checksum from file
try {
filein.read((char *)&vchData[0], dataSize);
filein >> hashIn;
}
catch (std::exception &e) {
return error("%s : Deserialize or I/O error - %s", __func__, e.what());
}
filein.fclose();
CDataStream ssMasternodes(vchData, SER_DISK, CLIENT_VERSION);
// verify stored checksum matches input data
uint256 hashTmp = Hash(ssMasternodes.begin(), ssMasternodes.end());
if (hashIn != hashTmp)
return error("%s : Checksum mismatch, data corrupted", __func__);
unsigned char pchMsgTmp[4];
try {
// de-serialize file header (network specific magic number) and ..
ssMasternodes >> FLATDATA(pchMsgTmp);
// ... verify the network matches ours
if (memcmp(pchMsgTmp, Params().MessageStart(), sizeof(pchMsgTmp)))
return error("%s : Invalid network magic number", __func__);
// de-serialize address data into one CMnList object
ssMasternodes >> mnodemanToLoad;
}
catch (std::exception &e) {
return error("%s : Deserialize or I/O error - %s", __func__, e.what());
mnodemanToLoad.Clear();
}
return true;
}
void DumpMasternodes()
{
int64_t nStart = GetTimeMillis();
CMasternodeDB mndb;
mndb.Write(mnodeman);
LogPrint("masternode", "Flushed %d masternodes to masternodes.dat %dms\n",
mnodeman.size(), GetTimeMillis() - nStart);
}
CMasternodeMan::CMasternodeMan() {}
bool CMasternodeMan::Add(CMasternode &mn)
{
LOCK(cs);
if (!mn.IsEnabled())
return false;
CMasternode *pmn = Find(mn.vin);
if (pmn == NULL)
{
vMasternodes.push_back(mn);
return true;
}
return false;
}
void CMasternodeMan::Check()
{
LOCK(cs);
BOOST_FOREACH(CMasternode& mn, vMasternodes)
mn.Check();
}
void CMasternodeMan::CheckAndRemove()
{
LOCK(cs);
Check();
//remove inactive
vector<CMasternode>::iterator it = vMasternodes.begin();
while(it != vMasternodes.end()){
if((*it).activeState == 4 || (*it).activeState == 3){
LogPrintf("Removing inactive masternode %s\n", (*it).addr.ToString().c_str());
it = vMasternodes.erase(it);
} else {
++it;
}
}
// check who's asked for the masternode list
map<CNetAddr, int64_t>::iterator it1 = mAskedUsForMasternodeList.begin();
while(it1 != mAskedUsForMasternodeList.end()){
if((*it1).second < GetTime())
it1 = mAskedUsForMasternodeList.erase(it1);
else ++it1;
}
// check who we asked for the masternode list
it1 = mWeAskedForMasternodeList.begin();
while(it1 != mWeAskedForMasternodeList.end()){
if((*it1).second < GetTime())
it1 = mWeAskedForMasternodeList.erase(it1);
else ++it1;
}
// check which masternodes we've asked for
map<COutPoint, int64_t>::iterator it2 = mWeAskedForMasternodeListEntry.begin();
while(it2 != mWeAskedForMasternodeListEntry.end()){
if((*it2).second < GetTime())
it2 = mWeAskedForMasternodeListEntry.erase(it2);
else ++it2;
}
}
int CMasternodeMan::CountEnabled()
{
int i = 0;
BOOST_FOREACH(CMasternode& mn, vMasternodes) {
mn.Check();
if(mn.IsEnabled()) i++;
}
return i;
}
int CMasternodeMan::CountMasternodesAboveProtocol(int protocolVersion)
{
int i = 0;
BOOST_FOREACH(CMasternode& mn, vMasternodes) {
mn.Check();
if(mn.protocolVersion < protocolVersion || !mn.IsEnabled()) continue;
i++;
}
return i;
}
void CMasternodeMan::DsegUpdate(CNode* pnode)
{
std::map<CNetAddr, int64_t>::iterator it = mWeAskedForMasternodeList.find(pnode->addr);
if (it != mWeAskedForMasternodeList.end())
{
if (GetTime() < (*it).second) {
LogPrintf("dseg - we already asked %s for the list; skipping...\n", pnode->addr.ToString());
return;
}
}
pnode->PushMessage("dseg", CTxIn());
int64_t askAgain = GetTime() + MASTERNODES_DSEG_SECONDS;
mWeAskedForMasternodeList[pnode->addr] = askAgain;
}
CMasternode *CMasternodeMan::Find(const CTxIn &vin)
{
LOCK(cs);
BOOST_FOREACH(CMasternode& mn, vMasternodes)
{
if(mn.vin == vin)
return &mn;
}
return NULL;
}
CMasternode *CMasternodeMan::FindNotInVec(const std::vector<CTxIn> &vVins)
{
LOCK(cs);
BOOST_FOREACH(CMasternode &mn, vMasternodes)
{
mn.Check();
if(!mn.IsEnabled()) continue;
bool found = false;
BOOST_FOREACH(const CTxIn& vin, vVins)
if(mn.vin == vin)
{
found = true;
break;
}
if(found) continue;
return &mn;
}
return NULL;
}
CMasternode *CMasternodeMan::FindRandom()
{
LOCK(cs);
if(size() == 0) return NULL;
return &vMasternodes[GetRandInt(vMasternodes.size())];
}
CMasternode* CMasternodeMan::GetCurrentMasterNode(int mod, int64_t nBlockHeight, int minProtocol)
{
unsigned int score = 0;
CMasternode* winner = NULL;
// scan for winner
BOOST_FOREACH(CMasternode& mn, vMasternodes) {
mn.Check();
if(mn.protocolVersion < minProtocol || !mn.IsEnabled()) continue;
// calculate the score for each masternode
uint256 n = mn.CalculateScore(mod, nBlockHeight);
unsigned int n2 = 0;
memcpy(&n2, &n, sizeof(n2));
// determine the winner
if(n2 > score){
score = n2;
winner = &mn;
}
}
return winner;
}
int CMasternodeMan::GetMasternodeRank(const CTxIn& vin, int64_t nBlockHeight, int minProtocol)
{
std::vector<pair<unsigned int, CTxIn> > vecMasternodeScores;
// scan for winner
BOOST_FOREACH(CMasternode& mn, vMasternodes) {
mn.Check();
if(mn.protocolVersion < minProtocol) continue;
if(!mn.IsEnabled()) {
continue;
}
uint256 n = mn.CalculateScore(1, nBlockHeight);
unsigned int n2 = 0;
memcpy(&n2, &n, sizeof(n2));
vecMasternodeScores.push_back(make_pair(n2, mn.vin));
}
sort(vecMasternodeScores.rbegin(), vecMasternodeScores.rend(), CompareValueOnly());
unsigned int rank = 0;
BOOST_FOREACH (PAIRTYPE(unsigned int, CTxIn)& s, vecMasternodeScores){
rank++;
if(s.second == vin) {
return rank;
}
}
return -1;
}
void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CDataStream& vRecv)
{
if(fLiteMode) return; //disable all darksend/masternode related functionality
if(IsInitialBlockDownload()) return;
LOCK(cs);
if (strCommand == "dsee") { //DarkSend Election Entry
CTxIn vin;
CService addr;
CPubKey pubkey;
CPubKey pubkey2;
vector<unsigned char> vchSig;
int64_t sigTime;
int count;
int current;
int64_t lastUpdated;
int protocolVersion;
std::string strMessage;
// 70047 and greater
vRecv >> vin >> addr >> vchSig >> sigTime >> pubkey >> pubkey2 >> count >> current >> lastUpdated >> protocolVersion;
// make sure signature isn't in the future (past is OK)
if (sigTime > GetAdjustedTime() + 60 * 60) {
LogPrintf("dsee - Signature rejected, too far into the future %s\n", vin.ToString().c_str());
return;
}
bool isLocal = addr.IsRFC1918() || addr.IsLocal();
if(RegTest()) isLocal = false;
std::string vchPubKey(pubkey.begin(), pubkey.end());
std::string vchPubKey2(pubkey2.begin(), pubkey2.end());
strMessage = addr.ToString() + boost::lexical_cast<std::string>(sigTime) + vchPubKey + vchPubKey2 + boost::lexical_cast<std::string>(protocolVersion);
if(protocolVersion < nMasternodeMinProtocol) {
LogPrintf("dsee - ignoring outdated masternode %s protocol version %d\n", vin.ToString().c_str(), protocolVersion);
return;
}
CScript pubkeyScript;
pubkeyScript.SetDestination(pubkey.GetID());
if(pubkeyScript.size() != 25) {
LogPrintf("dsee - pubkey the wrong size\n");
Misbehaving(pfrom->GetId(), 100);
return;
}
CScript pubkeyScript2;
pubkeyScript2.SetDestination(pubkey2.GetID());
if(pubkeyScript2.size() != 25) {
LogPrintf("dsee - pubkey2 the wrong size\n");
Misbehaving(pfrom->GetId(), 100);
return;
}
std::string errorMessage = "";
if(!darkSendSigner.VerifyMessage(pubkey, vchSig, strMessage, errorMessage)){
LogPrintf("dsee - Got bad masternode address signature\n");
Misbehaving(pfrom->GetId(), 100);
return;
}
if(Params().NetworkID() == CChainParams::MAIN){
if(addr.GetPort() != 9999) return;
}
//search existing masternode list, this is where we update existing masternodes with new dsee broadcasts
CMasternode* pmn = this->Find(vin);
if(pmn != NULL)
{
// count == -1 when it's a new entry
// e.g. We don't want the entry relayed/time updated when we're syncing the list
// mn.pubkey = pubkey, IsVinAssociatedWithPubkey is validated once below,
// after that they just need to match
if(count == -1 && pmn->pubkey == pubkey && !pmn->UpdatedWithin(MASTERNODE_MIN_DSEE_SECONDS)){
pmn->UpdateLastSeen();
if(pmn->now < sigTime){ //take the newest entry
LogPrintf("dsee - Got updated entry for %s\n", addr.ToString().c_str());
pmn->pubkey2 = pubkey2;
pmn->now = sigTime;
pmn->sig = vchSig;
pmn->protocolVersion = protocolVersion;
pmn->addr = addr;
pmn->Check();
if(pmn->IsEnabled())
RelayDarkSendElectionEntry(vin, addr, vchSig, sigTime, pubkey, pubkey2, count, current, lastUpdated, protocolVersion);
}
}
return;
}
// make sure the vout that was signed is related to the transaction that spawned the masternode
// - this is expensive, so it's only done once per masternode
if(!darkSendSigner.IsVinAssociatedWithPubkey(vin, pubkey)) {
LogPrintf("dsee - Got mismatched pubkey and vin\n");
Misbehaving(pfrom->GetId(), 100);
return;
}
if(fDebug) LogPrintf("dsee - Got NEW masternode entry %s\n", addr.ToString().c_str());
// make sure it's still unspent
// - this is checked later by .check() in many places and by ThreadCheckDarkSendPool()
CValidationState state;
CTransaction tx = CTransaction();
CTxOut vout = CTxOut(999.99*COIN, darkSendPool.collateralPubKey);
tx.vin.push_back(vin);
tx.vout.push_back(vout);
if(AcceptableInputs(mempool, state, tx)){
if(fDebug) LogPrintf("dsee - Accepted masternode entry %i %i\n", count, current);
if(GetInputAge(vin) < MASTERNODE_MIN_CONFIRMATIONS){
LogPrintf("dsee - Input must have least %d confirmations\n", MASTERNODE_MIN_CONFIRMATIONS);
Misbehaving(pfrom->GetId(), 20);
return;
}
// use this as a peer
addrman.Add(CAddress(addr), pfrom->addr, 2*60*60);
// add our masternode
CMasternode mn(addr, vin, pubkey, vchSig, sigTime, pubkey2, protocolVersion);
mn.UpdateLastSeen(lastUpdated);
this->Add(mn);
// 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);
} else {
LogPrintf("dsee - Rejected masternode entry %s\n", addr.ToString().c_str());
int nDoS = 0;
if (state.IsInvalid(nDoS))
{
LogPrintf("dsee - %s from %s %s was not accepted into the memory pool\n", tx.GetHash().ToString().c_str(),
pfrom->addr.ToString().c_str(), pfrom->cleanSubVer.c_str());
if (nDoS > 0)
Misbehaving(pfrom->GetId(), nDoS);
}
}
}
else if (strCommand == "dseep") { //DarkSend Election Entry Ping
CTxIn vin;
vector<unsigned char> vchSig;
int64_t sigTime;
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;
}
if (sigTime <= GetAdjustedTime() - 60 * 60) {
LogPrintf("dseep - Signature rejected, too far into the past %s - %d %d \n", vin.ToString().c_str(), sigTime, GetAdjustedTime());
return;
}
// see if we have this masternode
CMasternode* pmn = this->Find(vin);
if(pmn != NULL)
{
// LogPrintf("dseep - Found corresponding mn for vin: %s\n", vin.ToString().c_str());
// take this only if it's newer
if(pmn->lastDseep < sigTime)
{
std::string strMessage = pmn->addr.ToString() + boost::lexical_cast<std::string>(sigTime) + boost::lexical_cast<std::string>(stop);
std::string errorMessage = "";
if(!darkSendSigner.VerifyMessage(pmn->pubkey2, vchSig, strMessage, errorMessage))
{
LogPrintf("dseep - Got bad masternode address signature %s \n", vin.ToString().c_str());
//Misbehaving(pfrom->GetId(), 100);
return;
}
pmn->lastDseep = sigTime;
if(!pmn->UpdatedWithin(MASTERNODE_MIN_DSEEP_SECONDS))
{
if(stop) pmn->Disable();
else
{
pmn->UpdateLastSeen();
pmn->Check();
if(!pmn->IsEnabled()) return;
}
RelayDarkSendElectionEntryPing(vin, vchSig, sigTime, stop);
}
}
return;
}
if(fDebug) LogPrintf("dseep - Couldn't find masternode entry %s\n", vin.ToString().c_str());
std::map<COutPoint, int64_t>::iterator i = mWeAskedForMasternodeListEntry.find(vin.prevout);
if (i != mWeAskedForMasternodeListEntry.end())
{
int64_t t = (*i).second;
if (GetTime() < t) return; // we've asked recently
}
// ask for the dsee info once from the node that sent dseep
LogPrintf("dseep - Asking source node for missing entry %s\n", vin.ToString().c_str());
pfrom->PushMessage("dseg", vin);
int64_t askAgain = GetTime()+(60*60*24);
mWeAskedForMasternodeListEntry[vin.prevout] = askAgain;
} else if (strCommand == "dseg") { //Get masternode list or specific entry
CTxIn vin;
vRecv >> vin;
if(vin == CTxIn()) { //only should ask for this once
//local network
if(!pfrom->addr.IsRFC1918() && Params().NetworkID() == CChainParams::MAIN)
{
std::map<CNetAddr, int64_t>::iterator i = mAskedUsForMasternodeList.find(pfrom->addr);
if (i != mAskedUsForMasternodeList.end())
{
int64_t t = (*i).second;
if (GetTime() < t) {
Misbehaving(pfrom->GetId(), 34);
LogPrintf("dseg - peer already asked me for the list\n");
return;
}
}
int64_t askAgain = GetTime() + MASTERNODES_DSEG_SECONDS;
mAskedUsForMasternodeList[pfrom->addr] = askAgain;
}
} //else, asking for a specific node which is ok
int count = this->size();
int i = 0;
BOOST_FOREACH(CMasternode& mn, vMasternodes) {
if(mn.addr.IsRFC1918()) continue; //local network
if(mn.IsEnabled())
{
if(fDebug) LogPrintf("dseg - Sending masternode entry - %s \n", mn.addr.ToString().c_str());
if(vin == CTxIn()){
pfrom->PushMessage("dsee", mn.vin, mn.addr, mn.sig, mn.now, mn.pubkey, mn.pubkey2, count, i, mn.lastTimeSeen, mn.protocolVersion);
} else if (vin == mn.vin) {
pfrom->PushMessage("dsee", mn.vin, mn.addr, mn.sig, mn.now, mn.pubkey, mn.pubkey2, count, i, mn.lastTimeSeen, mn.protocolVersion);
LogPrintf("dseg - Sent 1 masternode entries to %s\n", pfrom->addr.ToString().c_str());
return;
}
i++;
}
}
LogPrintf("dseg - Sent %d masternode entries to %s\n", i, pfrom->addr.ToString().c_str());
}
}

118
src/masternodeman.h Normal file
View File

@ -0,0 +1,118 @@
// Copyright (c) 2014-2015 The Darkcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef MASTERNODEMAN_H
#define MASTERNODEMAN_H
#include "bignum.h"
#include "sync.h"
#include "net.h"
#include "key.h"
#include "core.h"
#include "util.h"
#include "script.h"
#include "base58.h"
#include "main.h"
#include "masternode.h"
#define MASTERNODES_DUMP_SECONDS (15*60)
#define MASTERNODES_DSEG_SECONDS (3*60*60)
using namespace std;
class CMasternodeMan;
extern CMasternodeMan mnodeman;
void DumpMasternodes();
/** Access to the MN database (masternodes.dat) */
class CMasternodeDB
{
private:
boost::filesystem::path pathMN;
public:
CMasternodeDB();
bool Write(const CMasternodeMan &mnodemanToSave);
bool Read(CMasternodeMan& mnodemanToLoad);
};
class CMasternodeMan
{
private:
// critical section to protect the inner data structures
mutable CCriticalSection cs;
// map to hold all MNs
std::vector<CMasternode> vMasternodes;
// who's asked for the masternode list and the last time
std::map<CNetAddr, int64_t> mAskedUsForMasternodeList;
// who we asked for the masternode list and the last time
std::map<CNetAddr, int64_t> mWeAskedForMasternodeList;
// which masternodes we've asked for
std::map<COutPoint, int64_t> mWeAskedForMasternodeListEntry;
public:
IMPLEMENT_SERIALIZE
(
// serialized format:
// * version byte (currently 0)
// * masternodes vector
{
LOCK(cs);
unsigned char nVersion = 0;
READWRITE(nVersion);
READWRITE(vMasternodes);
READWRITE(mAskedUsForMasternodeList);
READWRITE(mWeAskedForMasternodeList);
READWRITE(mWeAskedForMasternodeListEntry);
}
)
CMasternodeMan();
CMasternodeMan(CMasternodeMan& other);
// Add an entry
bool Add(CMasternode &mn);
// Check all masternodes
void Check();
// Check all masternodes and remove inactive
void CheckAndRemove();
// Clear masternode vector
void Clear() { vMasternodes.clear(); }
int CountEnabled();
int CountMasternodesAboveProtocol(int protocolVersion);
void DsegUpdate(CNode* pnode);
// Find an entry
CMasternode* Find(const CTxIn& vin);
//Find an entry thta do not match every entry provided vector
CMasternode* FindNotInVec(const std::vector<CTxIn> &vVins);
// Find a random entry
CMasternode* FindRandom();
// Get the current winner for this block
CMasternode* GetCurrentMasterNode(int mod=1, int64_t nBlockHeight=0, int minProtocol=0);
std::vector<CMasternode> GetFullMasternodeVector() { Check(); return vMasternodes; }
int GetMasternodeRank(const CTxIn &vin, int64_t nBlockHeight, int minProtocol=0);
void ProcessMessage(CNode* pfrom, std::string& strCommand, CDataStream& vRecv);
// Return the number of (unique) masternodes
int size() { return vMasternodes.size(); }
};
#endif

View File

@ -12,7 +12,7 @@
#ifdef ENABLE_WALLET
#include "wallet.h"
#endif
#include "masternode.h"
#include "masternodeman.h"
//////////////////////////////////////////////////////////////////////////////
//
@ -163,9 +163,9 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
//spork
if(!masternodePayments.GetBlockPayee(pindexPrev->nHeight+1, pblock->payee)){
//no masternode detected
int winningNode = GetCurrentMasterNode(1);
if(winningNode >= 0){
pblock->payee.SetDestination(vecMasternodes[winningNode].pubkey.GetID());
CMasternode* winningNode = mnodeman.GetCurrentMasterNode(1);
if(winningNode){
pblock->payee.SetDestination(winningNode->pubkey.GetID());
} else {
LogPrintf("CreateNewBlock: Failed to detect masternode to pay\n");
hasPayment = false;

View File

@ -13,6 +13,7 @@
#include "main.h"
#include "net.h"
#include "ui_interface.h"
#include "masternodeman.h"
#include <stdint.h>
@ -24,7 +25,7 @@ static const int64_t nClientStartupTime = GetTime();
ClientModel::ClientModel(OptionsModel *optionsModel, QObject *parent) :
QObject(parent), optionsModel(optionsModel),
cachedNumBlocks(0),
cachedNumBlocks(0), cachedMasternodeCountString(""),
cachedReindexing(0), cachedImporting(0),
numBlocksAtStartup(-1), pollTimer(0)
{
@ -32,6 +33,11 @@ ClientModel::ClientModel(OptionsModel *optionsModel, QObject *parent) :
connect(pollTimer, SIGNAL(timeout()), this, SLOT(updateTimer()));
pollTimer->start(MODEL_UPDATE_DELAY);
pollMnTimer = new QTimer(this);
connect(pollMnTimer, SIGNAL(timeout()), this, SLOT(updateMnTimer()));
// no need to update as frequent as data for balances/txes/blocks
pollMnTimer->start(MODEL_UPDATE_DELAY * 4);
subscribeToCoreSignals();
}
@ -54,6 +60,11 @@ int ClientModel::getNumConnections(unsigned int flags) const
return nNum;
}
QString ClientModel::getMasternodeCountString() const
{
return QString::number((int)mnodeman.CountEnabled()) + " / " + QString::number((int)mnodeman.size());
}
int ClientModel::getNumBlocks() const
{
LOCK(cs_main);
@ -117,6 +128,24 @@ void ClientModel::updateTimer()
emit bytesChanged(getTotalBytesRecv(), getTotalBytesSent());
}
void ClientModel::updateMnTimer()
{
// Get required lock upfront. This avoids the GUI from getting stuck on
// periodical polls if the core is holding the locks for a longer time -
// for example, during a wallet rescan.
TRY_LOCK(cs_main, lockMain);
if(!lockMain)
return;
QString newMasternodeCountString = getMasternodeCountString();
if (cachedMasternodeCountString != newMasternodeCountString)
{
cachedMasternodeCountString = newMasternodeCountString;
emit strMasternodesChanged(cachedMasternodeCountString);
}
}
void ClientModel::updateNumConnections(int numConnections)
{
emit numConnectionsChanged(numConnections);

View File

@ -46,6 +46,7 @@ public:
//! Return number of connections, default is in- and outbound (total)
int getNumConnections(unsigned int flags = CONNECTIONS_ALL) const;
QString getMasternodeCountString() const;
int getNumBlocks() const;
int getNumBlocksAtStartup();
@ -74,12 +75,14 @@ private:
OptionsModel *optionsModel;
int cachedNumBlocks;
QString cachedMasternodeCountString;
bool cachedReindexing;
bool cachedImporting;
int numBlocksAtStartup;
QTimer *pollTimer;
QTimer *pollMnTimer;
void subscribeToCoreSignals();
void unsubscribeFromCoreSignals();
@ -87,6 +90,7 @@ private:
signals:
void numConnectionsChanged(int count);
void numBlocksChanged(int count);
void strMasternodesChanged(const QString &strMasternodes);
void alertsChanged(const QString &warnings);
void bytesChanged(quint64 totalBytesIn, quint64 totalBytesOut);
@ -95,6 +99,7 @@ signals:
public slots:
void updateTimer();
void updateMnTimer();
void updateNumConnections(int numConnections);
void updateAlert(const QString &hash, int status);
};

View File

@ -11,7 +11,6 @@
#include "rpcserver.h"
#include "rpcclient.h"
#include "masternode.h"
#include "json/json_spirit_value.h"
#include <openssl/crypto.h>
@ -276,6 +275,9 @@ void RPCConsole::setClientModel(ClientModel *model)
setNumBlocks(model->getNumBlocks());
connect(model, SIGNAL(numBlocksChanged(int)), this, SLOT(setNumBlocks(int)));
setMasternodeCount(model->getMasternodeCountString());
connect(model, SIGNAL(strMasternodesChanged(QString)), this, SLOT(setMasternodeCount(QString)));
updateTrafficStats(model->getTotalBytesRecv(), model->getTotalBytesSent());
connect(model, SIGNAL(bytesChanged(quint64,quint64)), this, SLOT(updateTrafficStats(quint64, quint64)));
@ -373,11 +375,11 @@ void RPCConsole::setNumBlocks(int count)
ui->numberOfBlocks->setText(QString::number(count));
if(clientModel)
ui->lastBlockTime->setText(clientModel->getLastBlockDate().toString());
}
// set masternode count
QString masternodes = QString::number((int)vecMasternodes.size());
ui->masternodeCount->setText(masternodes);
void RPCConsole::setMasternodeCount(const QString &strMasternodes)
{
ui->masternodeCount->setText(strMasternodes);
}
void RPCConsole::on_lineEdit_returnPressed()

View File

@ -53,6 +53,8 @@ public slots:
void setNumConnections(int count);
/** Set number of blocks shown in the UI */
void setNumBlocks(int count);
/** Set number of masternodes shown in the UI */
void setMasternodeCount(const QString &strMasternodes);
/** Go forward or back in history */
void browseHistory(int offset);
/** Scroll console view to end */

View File

@ -7,8 +7,8 @@
#include "core.h"
#include "db.h"
#include "init.h"
#include "masternode.h"
#include "activemasternode.h"
#include "masternodeman.h"
#include "masternodeconfig.h"
#include "rpcserver.h"
#include <boost/lexical_cast.hpp>
@ -77,7 +77,7 @@ Value getpoolinfo(const Array& params, bool fHelp)
"Returns an object containing anonymous pool-related information.");
Object obj;
obj.push_back(Pair("current_masternode", GetCurrentMasterNode()));
obj.push_back(Pair("current_masternode", mnodeman.GetCurrentMasterNode()->addr.ToString()));
obj.push_back(Pair("state", darkSendPool.GetState()));
obj.push_back(Pair("entries", darkSendPool.GetEntriesCount()));
obj.push_back(Pair("entries_accepted", darkSendPool.GetCountEntriesAccepted()));
@ -239,46 +239,20 @@ Value masternode(const Array& params, bool fHelp)
if (strCommand == "list")
{
std::string strCommand = "active";
if (params.size() == 2){
strCommand = params[1].get_str().c_str();
}
if (strCommand != "active" && strCommand != "vin" && strCommand != "pubkey" && strCommand != "lastseen" && strCommand != "activeseconds" && strCommand != "rank" && strCommand != "protocol"){
throw runtime_error(
"list supports 'active', 'vin', 'pubkey', 'lastseen', 'activeseconds', 'rank', 'protocol'\n");
}
Object obj;
BOOST_FOREACH(CMasterNode mn, vecMasternodes) {
mn.Check();
if(strCommand == "active"){
obj.push_back(Pair(mn.addr.ToString().c_str(), (int)mn.IsEnabled()));
} else if (strCommand == "vin") {
obj.push_back(Pair(mn.addr.ToString().c_str(), mn.vin.prevout.hash.ToString().c_str()));
} else if (strCommand == "pubkey") {
CScript pubkey;
pubkey.SetDestination(mn.pubkey.GetID());
CTxDestination address1;
ExtractDestination(pubkey, address1);
CBitcoinAddress address2(address1);
obj.push_back(Pair(mn.addr.ToString().c_str(), address2.ToString().c_str()));
} else if (strCommand == "protocol") {
obj.push_back(Pair(mn.addr.ToString().c_str(), (int64_t)mn.protocolVersion));
} else if (strCommand == "lastseen") {
obj.push_back(Pair(mn.addr.ToString().c_str(), (int64_t)mn.lastTimeSeen));
} else if (strCommand == "activeseconds") {
obj.push_back(Pair(mn.addr.ToString().c_str(), (int64_t)(mn.lastTimeSeen - mn.now)));
} else if (strCommand == "rank") {
obj.push_back(Pair(mn.addr.ToString().c_str(), (int)(GetMasternodeRank(mn.vin, chainActive.Tip()->nHeight))));
}
}
return obj;
Array newParams(params.size() - 1);
std::copy(params.begin() + 1, params.end(), newParams.begin());
return masternodelist(newParams, fHelp);
}
if (strCommand == "count")
{
if (params.size() > 2){
throw runtime_error(
"too many parameters\n");
}
if (params.size() == 2) return mnodeman.CountEnabled();
return mnodeman.size();
}
if (strCommand == "count") return (int)vecMasternodes.size();
if (strCommand == "start")
{
@ -455,9 +429,9 @@ Value masternode(const Array& params, bool fHelp)
if (strCommand == "current")
{
int winner = GetCurrentMasterNode(1);
if(winner >= 0) {
return vecMasternodes[winner].addr.ToString().c_str();
CMasternode* winner = mnodeman.GetCurrentMasterNode(1);
if(winner) {
return winner->addr.ToString().c_str();
}
return "unknown";
@ -551,3 +525,85 @@ Value masternode(const Array& params, bool fHelp)
return Value::null;
}
Value masternodelist(const Array& params, bool fHelp)
{
std::string strMode = "active";
std::string strFilter = "";
if (params.size() >= 1) strMode = params[0].get_str();
if (params.size() == 2) strFilter = params[1].get_str();
if (fHelp ||
(strMode != "active" && strMode != "vin" && strMode != "pubkey" && strMode != "lastseen"
&& strMode != "activeseconds" && strMode != "rank" && strMode != "protocol" && strMode != "full"))
{
throw runtime_error(
"masternodelist ( \"mode\" \"filter\" )\n"
"Get a list of masternodes in different modes\n"
"\nArguments:\n"
"1. \"mode\" (string, optional, defauls = active) The mode to run list in\n"
"2. \"filter\" (string, optional) Filter results, can be applied in few modes only\n"
"Available modes:\n"
" active - Print '1' if active and '0' otherwise (can be filtered, exact match)\n"
" activeseconds - Print number of seconds masternode recognized by the network as enabled\n"
" full - Print info in format 'active | protocol | pubkey | vin | lastseen | activeseconds' (can be filtered, partial match)\n"
" lastseen - Print timestamp of when a masternode was last seen on the network\n"
" protocol - Print protocol of a masternode (can be filtered, exact match)\n"
" pubkey - Print public key associated with a masternode (can be filtered, partial match)\n"
" rank - Print rank of a masternode based on current block\n"
" vin - Print vin associated with a masternode (can be filtered, partial match)\n"
);
}
Object obj;
std::vector<CMasternode> vMasternodes = mnodeman.GetFullMasternodeVector();
BOOST_FOREACH(CMasternode& mn, vMasternodes) {
std::string strAddr = mn.addr.ToString().c_str();
if(strMode == "active"){
if(strFilter !="" && stoi(strFilter) != mn.IsEnabled()) continue;
obj.push_back(Pair(strAddr, (int)mn.IsEnabled()));
} else if (strMode == "vin") {
if(strFilter !="" && mn.vin.prevout.hash.ToString().find(strFilter) == string::npos) continue;
obj.push_back(Pair(strAddr, mn.vin.prevout.hash.ToString().c_str()));
} else if (strMode == "pubkey") {
CScript pubkey;
pubkey.SetDestination(mn.pubkey.GetID());
CTxDestination address1;
ExtractDestination(pubkey, address1);
CBitcoinAddress address2(address1);
if(strFilter !="" && address2.ToString().find(strFilter) == string::npos) continue;
obj.push_back(Pair(strAddr, address2.ToString().c_str()));
} else if (strMode == "protocol") {
if(strFilter !="" && stoi(strFilter) != mn.protocolVersion) continue;
obj.push_back(Pair(strAddr, (int64_t)mn.protocolVersion));
} else if (strMode == "lastseen") {
obj.push_back(Pair(strAddr, (int64_t)mn.lastTimeSeen));
} else if (strMode == "activeseconds") {
obj.push_back(Pair(strAddr, (int64_t)(mn.lastTimeSeen - mn.now)));
} else if (strMode == "rank") {
obj.push_back(Pair(strAddr, (int)(mnodeman.GetMasternodeRank(mn.vin, chainActive.Tip()->nHeight))));
} else if (strMode == "full") {
CScript pubkey;
pubkey.SetDestination(mn.pubkey.GetID());
CTxDestination address1;
ExtractDestination(pubkey, address1);
CBitcoinAddress address2(address1);
std::ostringstream stringStream;
stringStream << (mn.IsEnabled() ? "1" : "0") << " | " <<
mn.protocolVersion << " | " <<
address2.ToString() << " | " <<
mn.vin.prevout.hash.ToString() << " | " <<
mn.lastTimeSeen << " | " <<
(mn.lastTimeSeen - mn.now);
std::string output = stringStream.str();
stringStream << " " << strAddr;
if(strFilter !="" && stringStream.str().find(strFilter) == string::npos) continue;
obj.push_back(Pair(strAddr, output));
}
}
return obj;
}

View File

@ -274,6 +274,7 @@ static const CRPCCommand vRPCCommands[] =
{ "spork", &spork, true, false, false },
{ "masternode", &masternode, true, false, true },
{ "masternodelist", &masternodelist, true, false, false },
#ifdef ENABLE_WALLET
/* Wallet */
{ "addmultisigaddress", &addmultisigaddress, false, false, true },

View File

@ -193,6 +193,7 @@ extern json_spirit::Value verifychain(const json_spirit::Array& params, bool fHe
extern json_spirit::Value darksend(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value spork(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value masternode(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value masternodelist(const json_spirit::Array& params, bool fHelp);
#endif

View File

@ -136,7 +136,6 @@ public:
bool SelectCoinsDark(int64_t nValueMin, int64_t nValueMax, std::vector<CTxIn>& setCoinsRet, int64_t& nValueRet, int nDarksendRoundsMin, int nDarksendRoundsMax) const;
bool SelectCoinsByDenominations(int nDenom, int64_t nValueMin, int64_t nValueMax, std::vector<CTxIn>& setCoinsRet, vector<COutput>& vCoins, int64_t& nValueRet, int nDarksendRoundsMin, int nDarksendRoundsMax);
bool SelectCoinsDarkDenominated(int64_t nTargetValue, std::vector<CTxIn>& setCoinsRet, int64_t& nValueRet) const;
bool SelectCoinsMasternode(CTxIn& vin, int64_t& nValueRet, CScript& pubScript) const;
bool HasCollateralInputs() const;
bool IsCollateralAmount(int64_t nInputAmount) const;
int CountInputsWithAmount(int64_t nInputAmount);