Merge pull request #197 from UdjinM6/v0.11.2.x_masternodemanager
V0.11.2.x masternodemanager
This commit is contained in:
commit
97d88a6fa7
@ -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 \
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
};
|
||||
|
128
src/darksend.cpp
128
src/darksend.cpp
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
16
src/init.cpp
16
src/init.cpp
@ -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");
|
||||
|
@ -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)
|
||||
{
|
||||
|
54
src/main.cpp
54
src/main.cpp
@ -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);
|
||||
}
|
||||
|
@ -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))
|
||||
|
128
src/masternode.h
128
src/masternode.h
@ -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
622
src/masternodeman.cpp
Normal 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
118
src/masternodeman.h
Normal 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
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
};
|
||||
|
@ -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()
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
|
||||
}
|
||||
|
@ -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 },
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user