V0.12.1.x sentinel watchdog pr (#1079)
Squashed: * Replaced unsafe mnodeman.Find function with Get in governance-vote.cpp * Reject unparsable governance objects * Implemented sentinel watchdog objects (separated out from locking changes) * Added WATCHDOG support to rpcgovernance.cpp * Implemented WATCHDOG_EXPIRED state for masternodes * Added serialization of watchdog timestamps * Masternode fixes - Added version check to CMasternodeMan deserialization - Added several missing locking calls in CMasternodeMan * Fixed missing member initialization in CMasternode constructor and added more logging * Added MASTERNODE_WATCHDOG_MAX_SECONDS to governanceinfo * Added masternodewatchdogmaxseconds info to getgovernanceinfo help * Make masternodes remain in WATCHDOG_EXPIRED state unless removed or collateral expires * Allow watchdog object creation by WATCHDOG_EXPIRED MN * Fixed MN validation logic for governance object creation * Count total masternodes instead of enabled masternodes in masternode-sync * Transition out of WATCHDOG_EXPIRED state if the watchdog is inactive * Fixed IsWatchdogExpired bug * Fixed rate check for watchdog objects and no longer check MN state when validating governance objects * Applied PR #1061 patch * Ported locking changes from other branch * Require only 1 block between new watchdog objects * Accept pings for WATCHDOG_EXPIRED masternodes * Lock CmasternodeMan::cs in CmasternodeMan::ProcessMessage * Several governance changes - Fixed uninitialized value in CGovernancePayment class - Return an error on submission if any superblock payment cannot be parsed - Added logging more statements * Explicitly initialize all governance object members * Fix deadlock * Fixed non-threadsafe access to masternode in activemasternode.cpp * Revert added wallet lock * Changed CActiveMasternode so that watchdog expired nodes can still send pings * Modified CActiveMasternode to run pinger regardless of state when MN is in list * Added voter and time information to getvotes command * Improved CActiveMasternode state management * Implemented GetInfo functions for more efficient thread-safe access to masternode information * Added CActiveMasternode debug logging messages * Fixed initial type setting and error message for incorrect protocol version * Changes based on code review comments * Set active state for local mode
This commit is contained in:
parent
a584a68634
commit
94e38e3184
@ -13,125 +13,42 @@ extern CWallet* pwalletMain;
|
||||
// Keep track of the active Masternode
|
||||
CActiveMasternode activeMasternode;
|
||||
|
||||
// Bootup the Masternode, look for a 1000DASH input and register on the network
|
||||
void CActiveMasternode::ManageState()
|
||||
{
|
||||
std::string strError;
|
||||
LogPrint("masternode", "CActiveMasternode::ManageState -- Start\n");
|
||||
if(!fMasterNode) {
|
||||
LogPrint("masternode", "CActiveMasternode::ManageState -- Not a masternode, returning\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if(!fMasterNode) return;
|
||||
|
||||
if (fDebug) LogPrintf("CActiveMasternode::ManageState -- Begin\n");
|
||||
|
||||
//need correct blocks to send ping
|
||||
if(Params().NetworkIDString() != CBaseChainParams::REGTEST && !masternodeSync.IsBlockchainSynced()) {
|
||||
nState = ACTIVE_MASTERNODE_SYNC_IN_PROCESS;
|
||||
LogPrintf("CActiveMasternode::ManageState -- %s\n", GetStatus());
|
||||
return;
|
||||
}
|
||||
|
||||
if(nState == ACTIVE_MASTERNODE_SYNC_IN_PROCESS) nState = ACTIVE_MASTERNODE_INITIAL;
|
||||
|
||||
if(nState == ACTIVE_MASTERNODE_INITIAL) {
|
||||
CMasternode *pmn;
|
||||
pmn = mnodeman.Find(pubKeyMasternode);
|
||||
if(pmn != NULL) {
|
||||
pmn->Check();
|
||||
if((pmn->IsEnabled() || pmn->IsPreEnabled()) && pmn->nProtocolVersion == PROTOCOL_VERSION)
|
||||
EnableRemoteMasterNode(pmn->vin, pmn->addr);
|
||||
}
|
||||
if(nState == ACTIVE_MASTERNODE_SYNC_IN_PROCESS) {
|
||||
nState = ACTIVE_MASTERNODE_INITIAL;
|
||||
}
|
||||
|
||||
if(nState != ACTIVE_MASTERNODE_STARTED) {
|
||||
LogPrint("masternode", "CActiveMasternode::ManageState -- status = %s, type = %s, pinger enabled = %d\n", GetStatus(), GetType(), fPingerEnabled);
|
||||
|
||||
// Set defaults
|
||||
nState = ACTIVE_MASTERNODE_NOT_CAPABLE;
|
||||
strNotCapableReason = "";
|
||||
|
||||
if(pwalletMain->IsLocked()) {
|
||||
strNotCapableReason = "Wallet is locked.";
|
||||
LogPrintf("CActiveMasternode::ManageState -- not capable: %s\n", strNotCapableReason);
|
||||
return;
|
||||
}
|
||||
|
||||
if(pwalletMain->GetBalance() == 0) {
|
||||
nState = ACTIVE_MASTERNODE_INITIAL;
|
||||
LogPrintf("CActiveMasternode::ManageState() -- %s\n", GetStatus());
|
||||
return;
|
||||
}
|
||||
|
||||
if(!GetLocal(service)) {
|
||||
strNotCapableReason = "Can't detect external address. Please consider using the externalip configuration option if problem persists.";
|
||||
LogPrintf("CActiveMasternode::ManageState -- not capable: %s\n", strNotCapableReason);
|
||||
return;
|
||||
}
|
||||
|
||||
int mainnetDefaultPort = Params(CBaseChainParams::MAIN).GetDefaultPort();
|
||||
if(Params().NetworkIDString() == CBaseChainParams::MAIN) {
|
||||
if(service.GetPort() != mainnetDefaultPort) {
|
||||
strNotCapableReason = strprintf("Invalid port: %u - only %d is supported on mainnet.", service.GetPort(), mainnetDefaultPort);
|
||||
LogPrintf("CActiveMasternode::ManageState -- not capable: %s\n", strNotCapableReason);
|
||||
return;
|
||||
}
|
||||
} else if(service.GetPort() == mainnetDefaultPort) {
|
||||
strNotCapableReason = strprintf("Invalid port: %u - %d is only supported on mainnet.", service.GetPort(), mainnetDefaultPort);
|
||||
LogPrintf("CActiveMasternode::ManageState -- not capable: %s\n", strNotCapableReason);
|
||||
return;
|
||||
}
|
||||
|
||||
LogPrintf("CActiveMasternode::ManageState -- Checking inbound connection to '%s'\n", service.ToString());
|
||||
|
||||
if(!ConnectNode((CAddress)service, NULL, true)) {
|
||||
strNotCapableReason = "Could not connect to " + service.ToString();
|
||||
LogPrintf("CActiveMasternode::ManageState -- not capable: %s\n", strNotCapableReason);
|
||||
return;
|
||||
}
|
||||
|
||||
// Choose coins to use
|
||||
CPubKey pubKeyCollateral;
|
||||
CKey keyCollateral;
|
||||
|
||||
if(pwalletMain->GetMasternodeVinAndKeys(vin, pubKeyCollateral, keyCollateral)) {
|
||||
|
||||
int nInputAge = GetInputAge(vin);
|
||||
if(nInputAge < Params().GetConsensus().nMasternodeMinimumConfirmations){
|
||||
nState = ACTIVE_MASTERNODE_INPUT_TOO_NEW;
|
||||
strNotCapableReason = strprintf("%s - %d confirmations", GetStatus(), nInputAge);
|
||||
LogPrintf("CActiveMasternode::ManageState -- %s\n", strNotCapableReason);
|
||||
return;
|
||||
}
|
||||
|
||||
LOCK(pwalletMain->cs_wallet);
|
||||
pwalletMain->LockCoin(vin.prevout);
|
||||
|
||||
CMasternodeBroadcast mnb;
|
||||
if(!CMasternodeBroadcast::Create(vin, service, keyCollateral, pubKeyCollateral, keyMasternode, pubKeyMasternode, strError, mnb)) {
|
||||
strNotCapableReason = "Error on CMasternodeBroadcast::Create -- " + strError;
|
||||
LogPrintf("CActiveMasternode::ManageState -- %s\n", strNotCapableReason);
|
||||
return;
|
||||
}
|
||||
|
||||
//update to masternode list
|
||||
LogPrintf("CActiveMasternode::ManageState -- Update Masternode List\n");
|
||||
mnodeman.UpdateMasternodeList(mnb);
|
||||
|
||||
//send to all peers
|
||||
LogPrintf("CActiveMasternode::ManageState -- Relay broadcast, vin=%s\n", vin.ToString());
|
||||
mnb.Relay();
|
||||
|
||||
LogPrintf("CActiveMasternode::ManageState -- Is capable master node!\n");
|
||||
nState = ACTIVE_MASTERNODE_STARTED;
|
||||
|
||||
return;
|
||||
} else {
|
||||
strNotCapableReason = "Could not find suitable coins!";
|
||||
LogPrintf("CActiveMasternode::ManageState -- %s\n", strNotCapableReason);
|
||||
return;
|
||||
}
|
||||
if(eType == MASTERNODE_UNKNOWN) {
|
||||
ManageStateInitial();
|
||||
}
|
||||
|
||||
//send to all peers
|
||||
if(!SendMasternodePing(strError)) {
|
||||
LogPrintf("CActiveMasternode::ManageState -- Error on SendMasternodePing(): %s\n", strError);
|
||||
if(eType == MASTERNODE_REMOTE) {
|
||||
ManageStateRemote();
|
||||
}
|
||||
else {
|
||||
ManageStateLocal();
|
||||
}
|
||||
|
||||
if(fPingerEnabled) {
|
||||
std::string strError;
|
||||
if(!SendMasternodePing(strError)) {
|
||||
LogPrintf("CActiveMasternode::ManageState -- Error on SendMasternodePing(): %s\n", strError);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -147,10 +64,29 @@ std::string CActiveMasternode::GetStatus()
|
||||
}
|
||||
}
|
||||
|
||||
std::string CActiveMasternode::GetType()
|
||||
{
|
||||
std::string strType;
|
||||
switch(eType) {
|
||||
case MASTERNODE_UNKNOWN:
|
||||
strType = "UNKNOWN";
|
||||
break;
|
||||
case MASTERNODE_REMOTE:
|
||||
strType = "REMOTE";
|
||||
break;
|
||||
case MASTERNODE_LOCAL:
|
||||
strType = "LOCAL";
|
||||
break;
|
||||
default:
|
||||
strType = "UNKNOWN";
|
||||
break;
|
||||
}
|
||||
return strType;
|
||||
}
|
||||
|
||||
bool CActiveMasternode::SendMasternodePing(std::string& strErrorRet)
|
||||
{
|
||||
if(nState != ACTIVE_MASTERNODE_STARTED) {
|
||||
strErrorRet = "Masternode is not in a running status";
|
||||
if(vin == CTxIn()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -160,34 +96,25 @@ bool CActiveMasternode::SendMasternodePing(std::string& strErrorRet)
|
||||
return false;
|
||||
}
|
||||
|
||||
// Update lastPing for our masternode in Masternode list
|
||||
CMasternode* pmn = mnodeman.Find(vin);
|
||||
if(pmn != NULL) {
|
||||
if(pmn->IsPingedWithin(MASTERNODE_MIN_MNP_SECONDS, mnp.sigTime)) {
|
||||
strErrorRet = "Too early to send Masternode Ping";
|
||||
return false;
|
||||
}
|
||||
|
||||
pmn->lastPing = mnp;
|
||||
mnodeman.mapSeenMasternodePing.insert(std::make_pair(mnp.GetHash(), mnp));
|
||||
|
||||
//mnodeman.mapSeenMasternodeBroadcast.lastPing is probably outdated, so we'll update it
|
||||
CMasternodeBroadcast mnb(*pmn);
|
||||
uint256 hash = mnb.GetHash();
|
||||
if(mnodeman.mapSeenMasternodeBroadcast.count(hash))
|
||||
mnodeman.mapSeenMasternodeBroadcast[hash].lastPing = mnp;
|
||||
|
||||
LogPrintf("CActiveMasternode::SendMasternodePing -- Relaying ping, collateral=%s\n", vin.ToString());
|
||||
mnp.Relay();
|
||||
|
||||
return true;
|
||||
} else {
|
||||
// Seems like we are trying to send a ping while the Masternode is not registered in the network
|
||||
strErrorRet = "PrivateSend Masternode List doesn't include our Masternode, shutting down Masternode pinging service! " + vin.ToString();
|
||||
if(!mnodeman.Has(vin)) {
|
||||
strErrorRet = "Masternode List doesn't include our Masternode, shutting down Masternode pinging service! " + vin.ToString();
|
||||
nState = ACTIVE_MASTERNODE_NOT_CAPABLE;
|
||||
strNotCapableReason = strErrorRet;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Update lastPing for our masternode in Masternode list
|
||||
if(mnodeman.IsMasternodePingedWithin(vin, MASTERNODE_MIN_MNP_SECONDS, mnp.sigTime)) {
|
||||
strErrorRet = "Too early to send Masternode Ping";
|
||||
return false;
|
||||
}
|
||||
|
||||
mnodeman.SetMasternodeLastPing(vin, mnp);
|
||||
|
||||
LogPrintf("CActiveMasternode::SendMasternodePing -- Relaying ping, collateral=%s\n", vin.ToString());
|
||||
mnp.Relay();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// when starting a Masternode, this can enable to run as a hot wallet with no funds
|
||||
@ -205,3 +132,145 @@ bool CActiveMasternode::EnableRemoteMasterNode(CTxIn& vinNew, CService& serviceN
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CActiveMasternode::ManageStateInitial()
|
||||
{
|
||||
LogPrint("masternode", "CActiveMasternode::ManageStateInitial -- Start status = %s, type = %s, pinger enabled = %d\n", GetStatus(), GetType(), fPingerEnabled);
|
||||
|
||||
// Check that our local network configuration is correct
|
||||
if(!GetLocal(service)) {
|
||||
strNotCapableReason = "Can't detect external address. Please consider using the externalip configuration option if problem persists.";
|
||||
LogPrintf("CActiveMasternode::ManageStateInitial -- not capable: %s\n", strNotCapableReason);
|
||||
return;
|
||||
}
|
||||
|
||||
int mainnetDefaultPort = Params(CBaseChainParams::MAIN).GetDefaultPort();
|
||||
if(Params().NetworkIDString() == CBaseChainParams::MAIN) {
|
||||
if(service.GetPort() != mainnetDefaultPort) {
|
||||
strNotCapableReason = strprintf("Invalid port: %u - only %d is supported on mainnet.", service.GetPort(), mainnetDefaultPort);
|
||||
LogPrintf("CActiveMasternode::ManageStateInitial -- not capable: %s\n", strNotCapableReason);
|
||||
return;
|
||||
}
|
||||
} else if(service.GetPort() == mainnetDefaultPort) {
|
||||
strNotCapableReason = strprintf("Invalid port: %u - %d is only supported on mainnet.", service.GetPort(), mainnetDefaultPort);
|
||||
LogPrintf("CActiveMasternode::ManageStateInitial -- not capable: %s\n", strNotCapableReason);
|
||||
return;
|
||||
}
|
||||
|
||||
LogPrintf("CActiveMasternode::ManageState -- Checking inbound connection to '%s'\n", service.ToString());
|
||||
|
||||
if(!ConnectNode((CAddress)service, NULL, true)) {
|
||||
strNotCapableReason = "Could not connect to " + service.ToString();
|
||||
LogPrintf("CActiveMasternode::ManageStateInitial -- not capable: %s\n", strNotCapableReason);
|
||||
return;
|
||||
}
|
||||
|
||||
// Default to REMOTE
|
||||
eType = MASTERNODE_REMOTE;
|
||||
|
||||
// Check if wallet funds are available
|
||||
if(!pwalletMain) {
|
||||
strNotCapableReason = "Wallet not available.";
|
||||
LogPrintf("CActiveMasternode::ManageStateInitial -- not capable: %s\n", strNotCapableReason);
|
||||
return;
|
||||
}
|
||||
|
||||
if(pwalletMain->IsLocked()) {
|
||||
strNotCapableReason = "Wallet is locked.";
|
||||
LogPrintf("CActiveMasternode::ManageStateInitial -- not capable: %s\n", strNotCapableReason);
|
||||
return;
|
||||
}
|
||||
|
||||
if(pwalletMain->GetBalance() < 1000*COIN) {
|
||||
strNotCapableReason = "Wallet balance is < 1000 DASH";
|
||||
LogPrintf("CActiveMasternode::ManageStateInitial -- not capable: %s\n", strNotCapableReason);
|
||||
return;
|
||||
}
|
||||
|
||||
// Choose coins to use
|
||||
CPubKey pubKeyCollateral;
|
||||
CKey keyCollateral;
|
||||
|
||||
// If collateral is found switch to LOCAL mode
|
||||
if(pwalletMain->GetMasternodeVinAndKeys(vin, pubKeyCollateral, keyCollateral)) {
|
||||
eType = MASTERNODE_LOCAL;
|
||||
}
|
||||
|
||||
LogPrint("masternode", "CActiveMasternode::ManageStateInitial -- End status = %s, type = %s, pinger enabled = %d\n", GetStatus(), GetType(), fPingerEnabled);
|
||||
}
|
||||
|
||||
void CActiveMasternode::ManageStateRemote()
|
||||
{
|
||||
LogPrint("masternode", "CActiveMasternode::ManageStateRemote -- status = %s, type = %s, pinger enabled = %d\n", GetStatus(), GetType(), fPingerEnabled);
|
||||
mnodeman.CheckMasternode(pubKeyMasternode);
|
||||
masternode_info_t infoMn = mnodeman.GetMasternodeInfo(pubKeyMasternode);
|
||||
if(infoMn.fInfoValid) {
|
||||
if(infoMn.nProtocolVersion != PROTOCOL_VERSION) {
|
||||
nState = ACTIVE_MASTERNODE_NOT_CAPABLE;
|
||||
strNotCapableReason = "Invalid protocol version";
|
||||
return;
|
||||
}
|
||||
vin = infoMn.vin;
|
||||
service = infoMn.addr;
|
||||
fPingerEnabled = true;
|
||||
if(((infoMn.nActiveState == CMasternode::MASTERNODE_ENABLED) ||
|
||||
(infoMn.nActiveState == CMasternode::MASTERNODE_PRE_ENABLED) ||
|
||||
(infoMn.nActiveState == CMasternode::MASTERNODE_WATCHDOG_EXPIRED))) {
|
||||
nState = ACTIVE_MASTERNODE_STARTED;
|
||||
}
|
||||
else {
|
||||
nState = ACTIVE_MASTERNODE_NOT_CAPABLE;
|
||||
strNotCapableReason = "Masternode in EXPIRED state";
|
||||
}
|
||||
}
|
||||
else {
|
||||
fPingerEnabled = false;
|
||||
strNotCapableReason = "Masternode not in masternode list";
|
||||
nState = ACTIVE_MASTERNODE_NOT_CAPABLE;
|
||||
}
|
||||
}
|
||||
|
||||
void CActiveMasternode::ManageStateLocal()
|
||||
{
|
||||
LogPrint("masternode", "CActiveMasternode::ManageStateLocal -- status = %s, type = %s, pinger enabled = %d\n", GetStatus(), GetType(), fPingerEnabled);
|
||||
if(nState == ACTIVE_MASTERNODE_STARTED) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Choose coins to use
|
||||
CPubKey pubKeyCollateral;
|
||||
CKey keyCollateral;
|
||||
|
||||
if(pwalletMain->GetMasternodeVinAndKeys(vin, pubKeyCollateral, keyCollateral)) {
|
||||
int nInputAge = GetInputAge(vin);
|
||||
if(nInputAge < Params().GetConsensus().nMasternodeMinimumConfirmations){
|
||||
nState = ACTIVE_MASTERNODE_INPUT_TOO_NEW;
|
||||
strNotCapableReason = strprintf("%s - %d confirmations", GetStatus(), nInputAge);
|
||||
LogPrintf("CActiveMasternode::ManageStateLocal -- %s\n", strNotCapableReason);
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
LOCK(pwalletMain->cs_wallet);
|
||||
pwalletMain->LockCoin(vin.prevout);
|
||||
}
|
||||
|
||||
CMasternodeBroadcast mnb;
|
||||
std::string strError;
|
||||
if(!CMasternodeBroadcast::Create(vin, service, keyCollateral, pubKeyCollateral, keyMasternode, pubKeyMasternode, strError, mnb)) {
|
||||
strNotCapableReason = "Error on CMasternodeBroadcast::Create -- " + strError;
|
||||
LogPrintf("CActiveMasternode::ManageStateLocal -- %s\n", strNotCapableReason);
|
||||
return;
|
||||
}
|
||||
|
||||
//update to masternode list
|
||||
LogPrintf("CActiveMasternode::ManageStateLocal -- Update Masternode List\n");
|
||||
mnodeman.UpdateMasternodeList(mnb);
|
||||
|
||||
//send to all peers
|
||||
LogPrintf("CActiveMasternode::ManageStateLocal -- Relay broadcast, vin=%s\n", vin.ToString());
|
||||
mnb.Relay();
|
||||
fPingerEnabled = true;
|
||||
nState = ACTIVE_MASTERNODE_STARTED;
|
||||
}
|
||||
}
|
||||
|
@ -22,10 +22,21 @@ extern CActiveMasternode activeMasternode;
|
||||
// Responsible for activating the Masternode and pinging the network
|
||||
class CActiveMasternode
|
||||
{
|
||||
public:
|
||||
enum masternode_type_enum_t {
|
||||
MASTERNODE_UNKNOWN = 0,
|
||||
MASTERNODE_REMOTE = 1,
|
||||
MASTERNODE_LOCAL = 2
|
||||
};
|
||||
|
||||
private:
|
||||
// critical section to protect the inner data structures
|
||||
mutable CCriticalSection cs;
|
||||
|
||||
masternode_type_enum_t eType;
|
||||
|
||||
bool fPingerEnabled;
|
||||
|
||||
/// Ping Masternode
|
||||
bool SendMasternodePing(std::string& strErrorRet);
|
||||
|
||||
@ -41,15 +52,28 @@ public:
|
||||
int nState; // should be one of ACTIVE_MASTERNODE_XXXX
|
||||
std::string strNotCapableReason;
|
||||
|
||||
CActiveMasternode() : nState(ACTIVE_MASTERNODE_INITIAL) {}
|
||||
CActiveMasternode()
|
||||
: eType(MASTERNODE_UNKNOWN),
|
||||
fPingerEnabled(false),
|
||||
nState(ACTIVE_MASTERNODE_INITIAL)
|
||||
{}
|
||||
|
||||
/// Manage state of active Masternode
|
||||
void ManageState();
|
||||
|
||||
std::string GetStatus();
|
||||
|
||||
std::string GetType();
|
||||
|
||||
/// Enable cold wallet mode (run a Masternode with no funds)
|
||||
bool EnableRemoteMasterNode(CTxIn& vinNew, CService& serviceNew);
|
||||
|
||||
private:
|
||||
void ManageStateInitial();
|
||||
|
||||
void ManageStateRemote();
|
||||
|
||||
void ManageStateLocal();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -295,6 +295,7 @@ std::vector<CSuperblock_sptr> CGovernanceTriggerManager::GetActiveTriggers()
|
||||
|
||||
bool CSuperblockManager::IsSuperblockTriggered(int nBlockHeight)
|
||||
{
|
||||
LogPrint("gobject", "CSuperblockManager::IsSuperblockTriggered -- Start nBlockHeight = %d\n", nBlockHeight);
|
||||
if (!CSuperblock::IsValidBlockHeight(nBlockHeight)) {
|
||||
return false;
|
||||
}
|
||||
@ -303,11 +304,14 @@ bool CSuperblockManager::IsSuperblockTriggered(int nBlockHeight)
|
||||
// GET ALL ACTIVE TRIGGERS
|
||||
std::vector<CSuperblock_sptr> vecTriggers = triggerman.GetActiveTriggers();
|
||||
|
||||
LogPrint("gobject", "CSuperblockManager::IsSuperblockTriggered -- vecTriggers.size() = %d\n", vecTriggers.size());
|
||||
|
||||
DBG( cout << "IsSuperblockTriggered Number triggers = " << vecTriggers.size() << endl; );
|
||||
|
||||
BOOST_FOREACH(CSuperblock_sptr pSuperblock, vecTriggers)
|
||||
{
|
||||
if(!pSuperblock) {
|
||||
LogPrintf("CSuperblockManager::IsSuperblockTriggered -- Non-superblock found, continuing\n");
|
||||
DBG( cout << "IsSuperblockTriggered Not a superblock, continuing " << endl; );
|
||||
continue;
|
||||
}
|
||||
@ -315,27 +319,35 @@ bool CSuperblockManager::IsSuperblockTriggered(int nBlockHeight)
|
||||
CGovernanceObject* pObj = pSuperblock->GetGovernanceObject();
|
||||
|
||||
if(!pObj) {
|
||||
LogPrintf("CSuperblockManager::IsSuperblockTriggered -- pObj == NULL, continuing\n");
|
||||
DBG( cout << "IsSuperblockTriggered pObj is NULL, continuing" << endl; );
|
||||
continue;
|
||||
}
|
||||
|
||||
LogPrint("gobject", "CSuperblockManager::IsSuperblockTriggered -- data = %s\n", pObj->GetDataAsString());
|
||||
|
||||
// note : 12.1 - is epoch calculation correct?
|
||||
|
||||
if(nBlockHeight != pSuperblock->GetBlockStart()) {
|
||||
LogPrint("gobject", "CSuperblockManager::IsSuperblockTriggered -- block height doesn't match nBlockHeight = %d, blockStart = %d, continuing\n",
|
||||
nBlockHeight,
|
||||
pSuperblock->GetBlockStart());
|
||||
DBG( cout << "IsSuperblockTriggered Not the target block, continuing"
|
||||
<< ", nBlockHeight = " << nBlockHeight
|
||||
<< ", superblock->GetBlockStart() = " << pSuperblock->GetBlockStart()
|
||||
<< endl; );
|
||||
<< ", nBlockHeight = " << nBlockHeight
|
||||
<< ", superblock->GetBlockStart() = " << pSuperblock->GetBlockStart()
|
||||
<< endl; );
|
||||
continue;
|
||||
}
|
||||
|
||||
// MAKE SURE THIS TRIGGER IS ACTIVE VIA FUNDING CACHE FLAG
|
||||
|
||||
if(pObj->fCachedFunding) {
|
||||
LogPrint("gobject", "CSuperblockManager::IsSuperblockTriggered -- fCacheFunding = true, returning true\n");
|
||||
DBG( cout << "IsSuperblockTriggered returning true" << endl; );
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
LogPrint("gobject", "CSuperblockManager::IsSuperblockTriggered -- fCacheFunding = false, continuing\n");
|
||||
DBG( cout << "IsSuperblockTriggered No fCachedFunding, continuing" << endl; );
|
||||
}
|
||||
}
|
||||
@ -402,7 +414,7 @@ void CSuperblockManager::CreateSuperblock(CMutableTransaction& txNewRet, int nBl
|
||||
|
||||
CSuperblock_sptr pSuperblock;
|
||||
if(!CSuperblockManager::GetBestSuperblock(pSuperblock, nBlockHeight)) {
|
||||
LogPrint("superblock", "CSuperblockManager::CreateSuperblock -- Can't find superblock for height %d\n", nBlockHeight);
|
||||
LogPrint("gobject", "CSuperblockManager::CreateSuperblock -- Can't find superblock for height %d\n", nBlockHeight);
|
||||
DBG( cout << "CSuperblockManager::CreateSuperblock Failed to get superblock for height, returning" << endl; );
|
||||
return;
|
||||
}
|
||||
@ -507,6 +519,9 @@ CSuperblock(uint256& nHash)
|
||||
std::string strAmounts = obj["payment_amounts"].get_str();
|
||||
ParsePaymentSchedule(strAddresses, strAmounts);
|
||||
|
||||
LogPrint("gobject", "CSuperblock -- nEpochStart = %d, strAddresses = %s, strAmounts = %s, vecPayments.size() = %d\n",
|
||||
nEpochStart, strAddresses, strAmounts, vecPayments.size());
|
||||
|
||||
DBG( cout << "CSuperblock Constructor End" << endl; );
|
||||
}
|
||||
|
||||
@ -554,13 +569,15 @@ void CSuperblock::ParsePaymentSchedule(std::string& strPaymentAddresses, std::st
|
||||
|
||||
if (vecParsed1.size() != vecParsed2.size()) {
|
||||
std::ostringstream ostr;
|
||||
ostr << "CSuperblock::ParsePaymentSchedule Mismatched payments and amounts";
|
||||
ostr << "CSuperblock::ParsePaymentSchedule -- Mismatched payments and amounts";
|
||||
LogPrintf("%s\n", ostr.str());
|
||||
throw std::runtime_error(ostr.str());
|
||||
}
|
||||
|
||||
if (vecParsed1.size() == 0) {
|
||||
std::ostringstream ostr;
|
||||
ostr << "CSuperblock::ParsePaymentSchedule Error no payments";
|
||||
ostr << "CSuperblock::ParsePaymentSchedule -- Error no payments";
|
||||
LogPrintf("%s\n", ostr.str());
|
||||
throw std::runtime_error(ostr.str());
|
||||
}
|
||||
|
||||
@ -576,7 +593,8 @@ void CSuperblock::ParsePaymentSchedule(std::string& strPaymentAddresses, std::st
|
||||
CBitcoinAddress address(vecParsed1[i]);
|
||||
if (!address.IsValid()) {
|
||||
std::ostringstream ostr;
|
||||
ostr << "CSuperblock::ParsePaymentSchedule Invalid Dash Address : " << vecParsed1[i];
|
||||
ostr << "CSuperblock::ParsePaymentSchedule -- Invalid Dash Address : " << vecParsed1[i];
|
||||
LogPrintf("%s\n", ostr.str());
|
||||
throw std::runtime_error(ostr.str());
|
||||
}
|
||||
|
||||
@ -595,6 +613,14 @@ void CSuperblock::ParsePaymentSchedule(std::string& strPaymentAddresses, std::st
|
||||
if(payment.IsValid()) {
|
||||
vecPayments.push_back(payment);
|
||||
}
|
||||
else {
|
||||
vecPayments.clear();
|
||||
std::ostringstream ostr;
|
||||
ostr << "CSuperblock::ParsePaymentSchedule -- Invalid payment found: address = " << address.ToString()
|
||||
<< ", amount = " << nAmount;
|
||||
LogPrintf("%s\n", ostr.str());
|
||||
throw std::runtime_error(ostr.str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -646,6 +672,9 @@ bool CSuperblock::IsValid(const CTransaction& txNew, int nBlockHeight, CAmount b
|
||||
int nPayments = CountPayments();
|
||||
int nMinerPayments = nOutputs - nPayments;
|
||||
|
||||
LogPrint("gobject", "CSuperblock::IsValid nOutputs = %d, nPayments = %d, strData = %s\n",
|
||||
nOutputs, nPayments, GetGovernanceObject()->strData);
|
||||
|
||||
// We require an exact match (including order) between the expected
|
||||
// superblock payments and the payments actually in the block, after
|
||||
// skipping any initial miner payments.
|
||||
@ -716,7 +745,7 @@ std::string CSuperblockManager::GetRequiredPaymentsString(int nBlockHeight)
|
||||
|
||||
CSuperblock_sptr pSuperblock;
|
||||
if(!GetBestSuperblock(pSuperblock, nBlockHeight)) {
|
||||
LogPrint("superblock", "CSuperblockManager::GetRequiredPaymentsString -- Can't find superblock for height %d\n", nBlockHeight);
|
||||
LogPrint("gobject", "CSuperblockManager::GetRequiredPaymentsString -- Can't find superblock for height %d\n", nBlockHeight);
|
||||
return "error";
|
||||
}
|
||||
|
||||
|
@ -99,27 +99,33 @@ public:
|
||||
CAmount nAmount;
|
||||
|
||||
CGovernancePayment()
|
||||
{
|
||||
SetNull();
|
||||
}
|
||||
:fValid(false),
|
||||
script(),
|
||||
nAmount(0)
|
||||
{}
|
||||
|
||||
CGovernancePayment(CBitcoinAddress addrIn, CAmount nAmountIn)
|
||||
:fValid(false),
|
||||
script(),
|
||||
nAmount(0)
|
||||
{
|
||||
try
|
||||
{
|
||||
CTxDestination dest = addrIn.Get();
|
||||
script = GetScriptForDestination(dest);
|
||||
nAmount = nAmountIn;
|
||||
} catch(...) {
|
||||
SetNull(); //set fValid to false
|
||||
fValid = true;
|
||||
}
|
||||
catch(std::exception& e)
|
||||
{
|
||||
LogPrintf("CGovernancePayment Payment not valid: addrIn = %s, nAmountIn = %d, what = %s\n",
|
||||
addrIn.ToString(), nAmountIn, e.what());
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
LogPrintf("CGovernancePayment Payment not valid: addrIn = %s, nAmountIn = %d\n",
|
||||
addrIn.ToString(), nAmountIn);
|
||||
}
|
||||
}
|
||||
|
||||
void SetNull()
|
||||
{
|
||||
script = CScript();
|
||||
nAmount = 0;
|
||||
fValid = false;
|
||||
}
|
||||
|
||||
bool IsValid() { return fValid; }
|
||||
|
@ -283,9 +283,8 @@ bool CGovernanceVote::IsValid(bool fSignatureCheck)
|
||||
return false;
|
||||
}
|
||||
|
||||
CMasternode* pmn = mnodeman.Find(vinMasternode);
|
||||
if(pmn == NULL)
|
||||
{
|
||||
masternode_info_t infoMn = mnodeman.GetMasternodeInfo(vinMasternode);
|
||||
if(!infoMn.fInfoValid) {
|
||||
LogPrint("gobject", "CGovernanceVote::IsValid -- Unknown Masternode - %s\n", vinMasternode.prevout.ToStringShort());
|
||||
return false;
|
||||
}
|
||||
@ -296,7 +295,7 @@ bool CGovernanceVote::IsValid(bool fSignatureCheck)
|
||||
std::string strMessage = vinMasternode.prevout.ToStringShort() + "|" + nParentHash.ToString() + "|" +
|
||||
boost::lexical_cast<std::string>(nVoteSignal) + "|" + boost::lexical_cast<std::string>(nVoteOutcome) + "|" + boost::lexical_cast<std::string>(nTime);
|
||||
|
||||
if(!darkSendSigner.VerifyMessage(pmn->pubKeyMasternode, vchSig, strMessage, strError)) {
|
||||
if(!darkSendSigner.VerifyMessage(infoMn.pubKeyMasternode, vchSig, strMessage, strError)) {
|
||||
LogPrintf("CGovernanceVote::IsValid -- VerifyMessage() failed, error: %s\n", strError);
|
||||
return false;
|
||||
}
|
||||
|
@ -109,9 +109,9 @@ public:
|
||||
|
||||
int64_t GetTimestamp() const { return nTime; }
|
||||
|
||||
vote_signal_enum_t GetSignal() { return vote_signal_enum_t(nVoteSignal); }
|
||||
vote_signal_enum_t GetSignal() const { return vote_signal_enum_t(nVoteSignal); }
|
||||
|
||||
vote_outcome_enum_t GetOutcome() { return vote_outcome_enum_t(nVoteOutcome); }
|
||||
vote_outcome_enum_t GetOutcome() const { return vote_outcome_enum_t(nVoteOutcome); }
|
||||
|
||||
const uint256& GetParentHash() const { return nParentHash; }
|
||||
|
||||
@ -129,6 +129,8 @@ public:
|
||||
|
||||
CTxIn& GetVinMasternode() { return vinMasternode; }
|
||||
|
||||
const CTxIn& GetVinMasternode() const { return vinMasternode; }
|
||||
|
||||
/**
|
||||
* GetHash()
|
||||
*
|
||||
@ -148,8 +150,12 @@ public:
|
||||
|
||||
std::string ToString()
|
||||
{
|
||||
std::string strRet = CGovernanceVoting::ConvertOutcomeToString(GetOutcome()) + ":" + CGovernanceVoting::ConvertSignalToString(GetSignal());
|
||||
return strRet;
|
||||
std::ostringstream ostr;
|
||||
ostr << vinMasternode.ToString() << ":"
|
||||
<< nTime << ":"
|
||||
<< CGovernanceVoting::ConvertOutcomeToString(GetOutcome()) << ":"
|
||||
<< CGovernanceVoting::ConvertSignalToString(GetSignal());
|
||||
return ostr.str();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -36,6 +36,8 @@ CGovernanceManager::CGovernanceManager()
|
||||
mapSeenGovernanceObjects(),
|
||||
mapSeenVotes(),
|
||||
mapOrphanVotes(),
|
||||
mapVotesByHash(),
|
||||
mapVotesByType(),
|
||||
mapLastMasternodeTrigger(),
|
||||
cs()
|
||||
{}
|
||||
@ -186,8 +188,7 @@ void CGovernanceManager::ProcessMessage(CNode* pfrom, std::string& strCommand, C
|
||||
|
||||
// FIND THE MASTERNODE OF THE VOTER
|
||||
|
||||
CMasternode* pmn = mnodeman.Find(vote.GetVinMasternode());
|
||||
if(pmn == NULL) {
|
||||
if(!mnodeman.Has(vote.GetVinMasternode())) {
|
||||
LogPrint("gobject", "gobject - unknown masternode - vin: %s\n", vote.GetVinMasternode().ToString());
|
||||
mnodeman.AskForMN(pfrom, vote.GetVinMasternode());
|
||||
return;
|
||||
@ -212,7 +213,7 @@ void CGovernanceManager::ProcessMessage(CNode* pfrom, std::string& strCommand, C
|
||||
if(AddOrUpdateVote(vote, pfrom, strError)) {
|
||||
vote.Relay();
|
||||
masternodeSync.AddedBudgetItem(vote.GetHash());
|
||||
pmn->AddGovernanceVote(vote.GetParentHash());
|
||||
mnodeman.AddGovernanceVote(vote.GetVinMasternode(), vote.GetParentHash());
|
||||
}
|
||||
|
||||
LogPrint("gobject", "NEW governance vote: %s\n", vote.GetHash().ToString());
|
||||
@ -267,11 +268,15 @@ bool CGovernanceManager::AddGovernanceObject(CGovernanceObject& govobj)
|
||||
<< ", nObjectType = " << govobj.nObjectType
|
||||
<< endl; );
|
||||
|
||||
if(govobj.nObjectType == GOVERNANCE_OBJECT_TRIGGER) {
|
||||
switch(govobj.nObjectType) {
|
||||
case GOVERNANCE_OBJECT_TRIGGER:
|
||||
mapLastMasternodeTrigger[govobj.vinMasternode.prevout] = nCachedBlockHeight;
|
||||
DBG( cout << "CGovernanceManager::AddGovernanceObject Before AddNewTrigger" << endl; );
|
||||
triggerman.AddNewTrigger(govobj.GetHash());
|
||||
DBG( cout << "CGovernanceManager::AddGovernanceObject After AddNewTrigger" << endl; );
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
DBG( cout << "CGovernanceManager::AddGovernanceObject END" << endl; );
|
||||
@ -283,8 +288,18 @@ void CGovernanceManager::UpdateCachesAndClean()
|
||||
{
|
||||
LogPrintf("CGovernanceManager::UpdateCachesAndClean \n");
|
||||
|
||||
std::vector<uint256> vecDirtyHashes = mnodeman.GetAndClearDirtyGovernanceObjectHashes();
|
||||
|
||||
LOCK(cs);
|
||||
|
||||
for(size_t i = 0; i < vecDirtyHashes.size(); ++i) {
|
||||
object_m_it it = mapObjects.find(vecDirtyHashes[i]);
|
||||
if(it == mapObjects.end()) {
|
||||
continue;
|
||||
}
|
||||
it->second.fDirtyCache = true;
|
||||
}
|
||||
|
||||
// DOUBLE CHECK THAT WE HAVE A VALID POINTER TO TIP
|
||||
|
||||
if(!pCurrentBlockIndex) return;
|
||||
@ -322,6 +337,7 @@ void CGovernanceManager::UpdateCachesAndClean()
|
||||
|
||||
if(pObj->fCachedDelete || pObj->fExpired) {
|
||||
LogPrintf("UpdateCachesAndClean --- erase obj %s\n", (*it).first.ToString());
|
||||
mnodeman.RemoveGovernanceObject(pObj->GetHash());
|
||||
mapObjects.erase(it++);
|
||||
} else {
|
||||
++it;
|
||||
@ -561,6 +577,9 @@ bool CGovernanceManager::AddOrUpdateVote(const CGovernanceVote& vote, CNode* pfr
|
||||
{
|
||||
pGovObj->fDirtyCache = true;
|
||||
UpdateCachesAndClean();
|
||||
if(pGovObj->GetObjectType() == GOVERNANCE_OBJECT_WATCHDOG) {
|
||||
mnodeman.UpdateWatchdogVoteTime(vote.GetVinMasternode());
|
||||
}
|
||||
} else {
|
||||
LogPrintf("Governance object not found! Can't update fDirtyCache - %s\n", vote.GetParentHash().ToString());
|
||||
}
|
||||
@ -568,15 +587,27 @@ bool CGovernanceManager::AddOrUpdateVote(const CGovernanceVote& vote, CNode* pfr
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CGovernanceManager::MasternodeRateCheck(const CTxIn& vin)
|
||||
bool CGovernanceManager::MasternodeRateCheck(const CTxIn& vin, int nObjectType)
|
||||
{
|
||||
LOCK(cs);
|
||||
|
||||
int mindiff = 0;
|
||||
switch(nObjectType) {
|
||||
case GOVERNANCE_OBJECT_TRIGGER:
|
||||
mindiff = Params().GetConsensus().nSuperblockCycle - Params().GetConsensus().nSuperblockCycle / 10;
|
||||
break;
|
||||
case GOVERNANCE_OBJECT_WATCHDOG:
|
||||
mindiff = 1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
txout_m_it it = mapLastMasternodeTrigger.find(vin.prevout);
|
||||
if(it == mapLastMasternodeTrigger.end()) {
|
||||
return true;
|
||||
}
|
||||
// Allow 1 trigger per mn per cycle, with a small fudge factor
|
||||
int mindiff = Params().GetConsensus().nSuperblockCycle - Params().GetConsensus().nSuperblockCycle / 10;
|
||||
if((nCachedBlockHeight - it->second) > mindiff) {
|
||||
return true;
|
||||
}
|
||||
@ -587,79 +618,73 @@ bool CGovernanceManager::MasternodeRateCheck(const CTxIn& vin)
|
||||
}
|
||||
|
||||
CGovernanceObject::CGovernanceObject()
|
||||
: cs(),
|
||||
nHashParent(),
|
||||
nRevision(0),
|
||||
nTime(0),
|
||||
nCollateralHash(),
|
||||
strData(),
|
||||
nObjectType(GOVERNANCE_OBJECT_UNKNOWN),
|
||||
vinMasternode(),
|
||||
vchSig(),
|
||||
fCachedLocalValidity(false),
|
||||
strLocalValidityError(),
|
||||
fCachedFunding(false),
|
||||
fCachedValid(true),
|
||||
fCachedDelete(false),
|
||||
fCachedEndorsed(false),
|
||||
fDirtyCache(true),
|
||||
fUnparsable(false),
|
||||
fExpired(false)
|
||||
{
|
||||
// MAIN OBJECT DATA
|
||||
|
||||
nTime = 0;
|
||||
nObjectType = GOVERNANCE_OBJECT_UNKNOWN;
|
||||
|
||||
nHashParent = uint256(); //parent object, 0 is root
|
||||
nRevision = 0; //object revision in the system
|
||||
nCollateralHash = uint256(); //fee-tx
|
||||
|
||||
// CACHING FOR VARIOUS FLAGS
|
||||
|
||||
fCachedFunding = false;
|
||||
fCachedValid = true;
|
||||
fCachedDelete = false;
|
||||
fCachedEndorsed = false;
|
||||
fDirtyCache = true;
|
||||
fUnparsable = false;
|
||||
fExpired = false;
|
||||
|
||||
// PARSE JSON DATA STORAGE (STRDATA)
|
||||
LoadData();
|
||||
}
|
||||
|
||||
CGovernanceObject::CGovernanceObject(uint256 nHashParentIn, int nRevisionIn, int64_t nTimeIn, uint256 nCollateralHashIn, std::string strDataIn)
|
||||
: cs(),
|
||||
nHashParent(nHashParentIn),
|
||||
nRevision(nRevisionIn),
|
||||
nTime(nTimeIn),
|
||||
nCollateralHash(nCollateralHashIn),
|
||||
strData(strDataIn),
|
||||
nObjectType(GOVERNANCE_OBJECT_UNKNOWN),
|
||||
vinMasternode(),
|
||||
vchSig(),
|
||||
fCachedLocalValidity(false),
|
||||
strLocalValidityError(),
|
||||
fCachedFunding(false),
|
||||
fCachedValid(true),
|
||||
fCachedDelete(false),
|
||||
fCachedEndorsed(false),
|
||||
fDirtyCache(true),
|
||||
fUnparsable(false),
|
||||
fExpired(false)
|
||||
{
|
||||
// MAIN OBJECT DATA
|
||||
|
||||
nHashParent = nHashParentIn; //parent object, 0 is root
|
||||
nRevision = nRevisionIn; //object revision in the system
|
||||
nTime = nTimeIn;
|
||||
nCollateralHash = nCollateralHashIn; //fee-tx
|
||||
nObjectType = GOVERNANCE_OBJECT_UNKNOWN; // Avoid having an uninitialized variable
|
||||
strData = strDataIn;
|
||||
|
||||
// CACHING FOR VARIOUS FLAGS
|
||||
|
||||
fCachedFunding = false;
|
||||
fCachedValid = true;
|
||||
fCachedDelete = false;
|
||||
fCachedEndorsed = false;
|
||||
fDirtyCache = true;
|
||||
fUnparsable = false;
|
||||
fExpired = false;
|
||||
|
||||
// PARSE JSON DATA STORAGE (STRDATA)
|
||||
LoadData();
|
||||
}
|
||||
|
||||
CGovernanceObject::CGovernanceObject(const CGovernanceObject& other)
|
||||
{
|
||||
// COPY OTHER OBJECT'S DATA INTO THIS OBJECT
|
||||
|
||||
nHashParent = other.nHashParent;
|
||||
nRevision = other.nRevision;
|
||||
nTime = other.nTime;
|
||||
nCollateralHash = other.nCollateralHash;
|
||||
strData = other.strData;
|
||||
nObjectType = other.nObjectType;
|
||||
|
||||
fUnparsable = true;
|
||||
|
||||
vinMasternode = other.vinMasternode;
|
||||
vchSig = other.vchSig;
|
||||
|
||||
// caching
|
||||
fCachedFunding = other.fCachedFunding;
|
||||
fCachedValid = other.fCachedValid;
|
||||
fCachedDelete = other.fCachedDelete;
|
||||
fCachedEndorsed = other.fCachedEndorsed;
|
||||
fDirtyCache = other.fDirtyCache;
|
||||
fExpired = other.fExpired;
|
||||
}
|
||||
: cs(),
|
||||
nHashParent(other.nHashParent),
|
||||
nRevision(other.nRevision),
|
||||
nTime(other.nTime),
|
||||
nCollateralHash(other.nCollateralHash),
|
||||
strData(other.strData),
|
||||
nObjectType(other.nObjectType),
|
||||
vinMasternode(other.vinMasternode),
|
||||
vchSig(other.vchSig),
|
||||
fCachedLocalValidity(other.fCachedLocalValidity),
|
||||
strLocalValidityError(other.strLocalValidityError),
|
||||
fCachedFunding(other.fCachedFunding),
|
||||
fCachedValid(other.fCachedValid),
|
||||
fCachedDelete(other.fCachedDelete),
|
||||
fCachedEndorsed(other.fCachedEndorsed),
|
||||
fDirtyCache(other.fDirtyCache),
|
||||
fUnparsable(other.fUnparsable),
|
||||
fExpired(other.fExpired)
|
||||
{}
|
||||
|
||||
void CGovernanceObject::SetMasternodeInfo(const CTxIn& vin)
|
||||
{
|
||||
@ -789,6 +814,7 @@ void CGovernanceObject::LoadData()
|
||||
nObjectType = obj["type"].get_int();
|
||||
}
|
||||
catch(std::exception& e) {
|
||||
fUnparsable = true;
|
||||
std::ostringstream ostr;
|
||||
ostr << "CGovernanceObject::LoadData Error parsing JSON"
|
||||
<< ", e.what() = " << e.what();
|
||||
@ -797,6 +823,7 @@ void CGovernanceObject::LoadData()
|
||||
return;
|
||||
}
|
||||
catch(...) {
|
||||
fUnparsable = true;
|
||||
std::ostringstream ostr;
|
||||
ostr << "CGovernanceObject::LoadData Unknown Error parsing JSON";
|
||||
DBG( cout << ostr.str() << endl; );
|
||||
@ -854,9 +881,14 @@ bool CGovernanceObject::IsValidLocally(const CBlockIndex* pindex, std::string& s
|
||||
return true;
|
||||
}
|
||||
|
||||
if(fUnparsable) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch(nObjectType) {
|
||||
case GOVERNANCE_OBJECT_PROPOSAL:
|
||||
case GOVERNANCE_OBJECT_TRIGGER:
|
||||
case GOVERNANCE_OBJECT_WATCHDOG:
|
||||
break;
|
||||
default:
|
||||
strError = strprintf("Invalid object type %d", nObjectType);
|
||||
@ -872,29 +904,25 @@ bool CGovernanceObject::IsValidLocally(const CBlockIndex* pindex, std::string& s
|
||||
|
||||
// CHECK COLLATERAL IF REQUIRED (HIGH CPU USAGE)
|
||||
|
||||
if(fCheckCollateral) {
|
||||
if(nObjectType == GOVERNANCE_OBJECT_TRIGGER) {
|
||||
if(fCheckCollateral) {
|
||||
if((nObjectType == GOVERNANCE_OBJECT_TRIGGER) || (nObjectType == GOVERNANCE_OBJECT_WATCHDOG)) {
|
||||
std::string strVin = vinMasternode.prevout.ToStringShort();
|
||||
CMasternode mn;
|
||||
if(!mnodeman.Get(vinMasternode, mn)) {
|
||||
masternode_info_t infoMn = mnodeman.GetMasternodeInfo(vinMasternode);
|
||||
if(!infoMn.fInfoValid) {
|
||||
strError = "Masternode not found vin: " + strVin;
|
||||
return false;
|
||||
}
|
||||
if(!mn.IsEnabled()) {
|
||||
strError = "Masternode not enabled vin: " + strVin;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check that we have a valid MN signature
|
||||
if(!CheckSignature(mn.pubKeyMasternode)) {
|
||||
strError = "Invalid masternode signature for: " + strVin + ", pubkey id = " + mn.pubKeyMasternode.GetID().ToString();
|
||||
if(!CheckSignature(infoMn.pubKeyMasternode)) {
|
||||
strError = "Invalid masternode signature for: " + strVin + ", pubkey id = " + infoMn.pubKeyMasternode.GetID().ToString();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only perform rate check if we are synced because during syncing it is expected
|
||||
// that objects will be seen in rapid succession
|
||||
if(masternodeSync.IsSynced()) {
|
||||
if(!governance.MasternodeRateCheck(vinMasternode)) {
|
||||
if(!governance.MasternodeRateCheck(vinMasternode, nObjectType)) {
|
||||
strError = "Masternode attempting to create too many objects vin: " + strVin;
|
||||
return false;
|
||||
}
|
||||
@ -932,6 +960,7 @@ CAmount CGovernanceObject::GetMinCollateralFee()
|
||||
switch(nObjectType) {
|
||||
case GOVERNANCE_OBJECT_PROPOSAL: return GOVERNANCE_PROPOSAL_FEE_TX;
|
||||
case GOVERNANCE_OBJECT_TRIGGER: return 0;
|
||||
case GOVERNANCE_OBJECT_WATCHDOG: return 0;
|
||||
default: return MAX_MONEY;
|
||||
}
|
||||
}
|
||||
|
@ -35,6 +35,7 @@ static const int MIN_GOVERNANCE_PEER_PROTO_VERSION = 70202;
|
||||
static const int GOVERNANCE_OBJECT_UNKNOWN = 0;
|
||||
static const int GOVERNANCE_OBJECT_PROPOSAL = 1;
|
||||
static const int GOVERNANCE_OBJECT_TRIGGER = 2;
|
||||
static const int GOVERNANCE_OBJECT_WATCHDOG = 3;
|
||||
|
||||
static const CAmount GOVERNANCE_PROPOSAL_FEE_TX = (0.33*COIN);
|
||||
|
||||
@ -205,7 +206,7 @@ public:
|
||||
|
||||
void AddSeenVote(uint256 nHash, int status);
|
||||
|
||||
bool MasternodeRateCheck(const CTxIn& vin);
|
||||
bool MasternodeRateCheck(const CTxIn& vin, int nObjectType);
|
||||
|
||||
};
|
||||
|
||||
|
@ -169,7 +169,9 @@ void CMasternodeSync::ProcessTick()
|
||||
if(!pCurrentBlockIndex) return;
|
||||
|
||||
//the actual count of masternodes we have currently
|
||||
int nMnCount = mnodeman.CountEnabled();
|
||||
int nMnCount = mnodeman.CountMasternodes();
|
||||
|
||||
LogPrintf("CMasternodeSync::ProcessTick -- nTick %d nMnCount = %d\n", nTick, nMnCount);
|
||||
|
||||
// RESET SYNCING INCASE OF FAILURE
|
||||
{
|
||||
@ -222,7 +224,7 @@ void CMasternodeSync::ProcessTick()
|
||||
} else if(nRequestedMasternodeAttempt < 4) {
|
||||
mnodeman.DsegUpdate(pnode);
|
||||
} else if(nRequestedMasternodeAttempt < 6) {
|
||||
int nMnCount = mnodeman.CountEnabled();
|
||||
int nMnCount = mnodeman.CountMasternodes();
|
||||
pnode->PushMessage(NetMsgType::MASTERNODEPAYMENTSYNC, nMnCount); //sync payment votes
|
||||
uint256 n = uint256();
|
||||
pnode->PushMessage(NetMsgType::MNGOVERNANCESYNC, n); //sync masternode votes
|
||||
@ -274,6 +276,8 @@ void CMasternodeSync::ProcessTick()
|
||||
/* Note: Is this activing up? It's probably related to int CMasternodeMan::GetEstimatedMasternodes(int nBlock)
|
||||
Surely doesn't work right for testnet currently */
|
||||
// try to fetch data from at least two peers though
|
||||
LogPrintf("CMasternodeSync::ProcessTick -- nTick %d nMnCount %d, Estimated masternode count required: %d\n",
|
||||
nTick, nMnCount, mnodeman.GetEstimatedMasternodes(pCurrentBlockIndex->nHeight)*0.9);
|
||||
if(nRequestedMasternodeAttempt > 1 && nMnCount > mnodeman.GetEstimatedMasternodes(pCurrentBlockIndex->nHeight)*0.9) {
|
||||
LogPrintf("CMasternodeSync::ProcessTick -- nTick %d nRequestedMasternodeAssets %d -- found enough data\n", nTick, nRequestedMasternodeAssets);
|
||||
SwitchToNextAsset();
|
||||
|
@ -27,6 +27,7 @@ CMasternode::CMasternode() :
|
||||
nLastDsq(0),
|
||||
nTimeLastChecked(0),
|
||||
nTimeLastPaid(0),
|
||||
nTimeLastWatchdogVote(0),
|
||||
nActiveState(MASTERNODE_ENABLED),
|
||||
nCacheCollateralBlock(0),
|
||||
nBlockLastPaid(0),
|
||||
@ -46,6 +47,7 @@ CMasternode::CMasternode(CService addrNew, CTxIn vinNew, CPubKey pubKeyCollatera
|
||||
nLastDsq(0),
|
||||
nTimeLastChecked(0),
|
||||
nTimeLastPaid(0),
|
||||
nTimeLastWatchdogVote(0),
|
||||
nActiveState(MASTERNODE_ENABLED),
|
||||
nCacheCollateralBlock(0),
|
||||
nBlockLastPaid(0),
|
||||
@ -65,6 +67,7 @@ CMasternode::CMasternode(const CMasternode& other) :
|
||||
nLastDsq(other.nLastDsq),
|
||||
nTimeLastChecked(other.nTimeLastChecked),
|
||||
nTimeLastPaid(other.nTimeLastPaid),
|
||||
nTimeLastWatchdogVote(other.nTimeLastWatchdogVote),
|
||||
nActiveState(other.nActiveState),
|
||||
nCacheCollateralBlock(other.nCacheCollateralBlock),
|
||||
nBlockLastPaid(other.nBlockLastPaid),
|
||||
@ -84,6 +87,7 @@ CMasternode::CMasternode(const CMasternodeBroadcast& mnb) :
|
||||
nLastDsq(mnb.nLastDsq),
|
||||
nTimeLastChecked(0),
|
||||
nTimeLastPaid(0),
|
||||
nTimeLastWatchdogVote(0),
|
||||
nActiveState(MASTERNODE_ENABLED),
|
||||
nCacheCollateralBlock(0),
|
||||
nBlockLastPaid(0),
|
||||
@ -137,6 +141,13 @@ arith_uint256 CMasternode::CalculateScore(const uint256& blockHash)
|
||||
|
||||
void CMasternode::Check(bool fForce)
|
||||
{
|
||||
LOCK(cs);
|
||||
|
||||
bool fWatchdogActive = mnodeman.IsWatchdogActive();
|
||||
|
||||
LogPrint("masternode", "CMasternode::Check start -- vin = %s\n",
|
||||
vin.prevout.ToStringShort());
|
||||
|
||||
//once spent, stop doing the checks
|
||||
if(nActiveState == MASTERNODE_OUTPOINT_SPENT) return;
|
||||
|
||||
@ -145,12 +156,15 @@ void CMasternode::Check(bool fForce)
|
||||
if(!fForce && (GetTime() - nTimeLastChecked < MASTERNODE_CHECK_SECONDS)) return;
|
||||
nTimeLastChecked = GetTime();
|
||||
|
||||
bool fRemove = // If there were no pings for quite a long time ...
|
||||
!IsPingedWithin(MASTERNODE_REMOVAL_SECONDS) ||
|
||||
// or masternode doesn't meet payment protocol requirements ...
|
||||
nProtocolVersion < mnpayments.GetMinMasternodePaymentsProto() ||
|
||||
// or it's our own node and we just updated it to the new protocol but we are still waiting for activation ...
|
||||
(pubKeyMasternode == activeMasternode.pubKeyMasternode && nProtocolVersion < PROTOCOL_VERSION);
|
||||
if((nActiveState == MASTERNODE_WATCHDOG_EXPIRED) && !fWatchdogActive) {
|
||||
// Redo the checks
|
||||
nActiveState = MASTERNODE_ENABLED;
|
||||
}
|
||||
|
||||
// masternode doesn't meet payment protocol requirements ...
|
||||
bool fRemove = nProtocolVersion < mnpayments.GetMinMasternodePaymentsProto() ||
|
||||
// or it's our own node and we just updated it to the new protocol but we are still waiting for activation ...
|
||||
(pubKeyMasternode == activeMasternode.pubKeyMasternode && nProtocolVersion < PROTOCOL_VERSION);
|
||||
|
||||
if(fRemove) {
|
||||
// it should be removed from the list
|
||||
@ -162,7 +176,9 @@ void CMasternode::Check(bool fForce)
|
||||
}
|
||||
|
||||
if(!IsPingedWithin(MASTERNODE_EXPIRATION_SECONDS)) {
|
||||
nActiveState = MASTERNODE_EXPIRED;
|
||||
if(nActiveState != MASTERNODE_WATCHDOG_EXPIRED) {
|
||||
nActiveState = MASTERNODE_EXPIRED;
|
||||
}
|
||||
|
||||
// RESCAN AFFECTED VOTES
|
||||
FlagGovernanceItemsAsDirty();
|
||||
@ -170,7 +186,10 @@ void CMasternode::Check(bool fForce)
|
||||
}
|
||||
|
||||
if(lastPing.sigTime - sigTime < MASTERNODE_MIN_MNP_SECONDS) {
|
||||
nActiveState = MASTERNODE_PRE_ENABLED;
|
||||
if(nActiveState != MASTERNODE_WATCHDOG_EXPIRED) {
|
||||
nActiveState = MASTERNODE_PRE_ENABLED;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@ -192,6 +211,14 @@ void CMasternode::Check(bool fForce)
|
||||
}
|
||||
}
|
||||
|
||||
bool fWatchdogExpired = (fWatchdogActive && ((GetTime() - nTimeLastWatchdogVote) > MASTERNODE_WATCHDOG_MAX_SECONDS));
|
||||
LogPrint("masternode", "CMasternode::Check -- vin = %s, nTimeLastWatchdogVote = %d, GetTime() = %d, fWatchdogExpired = %d\n",
|
||||
vin.prevout.ToStringShort(), nTimeLastWatchdogVote, GetTime(), fWatchdogExpired);
|
||||
if(fWatchdogExpired) {
|
||||
nActiveState = MASTERNODE_WATCHDOG_EXPIRED;
|
||||
return;
|
||||
}
|
||||
|
||||
nActiveState = MASTERNODE_ENABLED; // OK
|
||||
}
|
||||
|
||||
@ -203,6 +230,24 @@ bool CMasternode::IsValidNetAddr()
|
||||
(addr.IsIPv4() && IsReachable(addr) && addr.IsRoutable());
|
||||
}
|
||||
|
||||
masternode_info_t CMasternode::GetInfo()
|
||||
{
|
||||
masternode_info_t info;
|
||||
info.vin = vin;
|
||||
info.addr = addr;
|
||||
info.pubKeyCollateralAddress = pubKeyCollateralAddress;
|
||||
info.pubKeyMasternode = pubKeyMasternode;
|
||||
info.sigTime = sigTime;
|
||||
info.nLastDsq = nLastDsq;
|
||||
info.nTimeLastChecked = nTimeLastChecked;
|
||||
info.nTimeLastPaid = nTimeLastPaid;
|
||||
info.nTimeLastWatchdogVote = nTimeLastWatchdogVote;
|
||||
info.nActiveState = nActiveState;
|
||||
info.nProtocolVersion = nProtocolVersion;
|
||||
info.fInfoValid = true;
|
||||
return info;
|
||||
}
|
||||
|
||||
std::string CMasternode::GetStatus()
|
||||
{
|
||||
switch(nActiveState) {
|
||||
@ -211,6 +256,7 @@ std::string CMasternode::GetStatus()
|
||||
case CMasternode::MASTERNODE_EXPIRED: return "EXPIRED";
|
||||
case CMasternode::MASTERNODE_OUTPOINT_SPENT: return "OUTPOINT_SPENT";
|
||||
case CMasternode::MASTERNODE_REMOVE: return "REMOVE";
|
||||
case CMasternode::MASTERNODE_WATCHDOG_EXPIRED: return "WATCHDOG_EXPIRED";
|
||||
default: return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
@ -458,7 +504,7 @@ bool CMasternodeBroadcast::CheckInputsAndAdd(int& nDos)
|
||||
|
||||
if(pmn != NULL) {
|
||||
// nothing to do here if we already know about this masternode and it's (pre)enabled
|
||||
if(pmn->IsEnabled() || pmn->IsPreEnabled()) return true;
|
||||
if(pmn->IsEnabled() || pmn->IsPreEnabled() || pmn->IsWatchdogExpired()) return true;
|
||||
// if it's not (pre)enabled, remove old MN first and continue
|
||||
mnodeman.Remove(pmn->vin);
|
||||
}
|
||||
@ -722,7 +768,7 @@ bool CMasternodePing::CheckAndUpdate(int& nDos, bool fRequireEnabled, bool fChec
|
||||
return false;
|
||||
}
|
||||
|
||||
if (fRequireEnabled && !pmn->IsEnabled() && !pmn->IsPreEnabled()) return false;
|
||||
if (fRequireEnabled && !pmn->IsEnabled() && !pmn->IsPreEnabled() && !pmn->IsWatchdogExpired()) return false;
|
||||
|
||||
// LogPrintf("mnping - Found corresponding mn for vin: %s\n", vin.prevout.ToStringShort());
|
||||
// update only if there is no known ping for this masternode or
|
||||
@ -780,27 +826,45 @@ void CMasternodePing::Relay()
|
||||
|
||||
void CMasternode::AddGovernanceVote(uint256 nGovernanceObjectHash)
|
||||
{
|
||||
if(mapGovernaceObjectsVotedOn.count(nGovernanceObjectHash)) {
|
||||
mapGovernaceObjectsVotedOn[nGovernanceObjectHash]++;
|
||||
if(mapGovernanceObjectsVotedOn.count(nGovernanceObjectHash)) {
|
||||
mapGovernanceObjectsVotedOn[nGovernanceObjectHash]++;
|
||||
} else {
|
||||
mapGovernaceObjectsVotedOn.insert(std::make_pair(nGovernanceObjectHash, 1));
|
||||
mapGovernanceObjectsVotedOn.insert(std::make_pair(nGovernanceObjectHash, 1));
|
||||
}
|
||||
}
|
||||
|
||||
void CMasternode::RemoveGovernanceObject(uint256 nGovernanceObjectHash)
|
||||
{
|
||||
std::map<uint256, int>::iterator it = mapGovernanceObjectsVotedOn.find(nGovernanceObjectHash);
|
||||
if(it == mapGovernanceObjectsVotedOn.end()) {
|
||||
return;
|
||||
}
|
||||
mapGovernanceObjectsVotedOn.erase(it);
|
||||
}
|
||||
|
||||
void CMasternode::UpdateWatchdogVoteTime()
|
||||
{
|
||||
LOCK(cs);
|
||||
nTimeLastWatchdogVote = GetTime();
|
||||
}
|
||||
|
||||
/**
|
||||
* FLAG GOVERNANCE ITEMS AS DIRTY
|
||||
*
|
||||
* - When masternode come and go on the network, we must flag the items they voted on to recalc it's cached flags
|
||||
*
|
||||
*/
|
||||
|
||||
void CMasternode::FlagGovernanceItemsAsDirty()
|
||||
{
|
||||
std::map<uint256, int>::iterator it = mapGovernaceObjectsVotedOn.begin();
|
||||
while(it != mapGovernaceObjectsVotedOn.end()){
|
||||
CGovernanceObject *pObj = governance.FindGovernanceObject((*it).first);
|
||||
|
||||
if(pObj) pObj->fDirtyCache = true;
|
||||
++it;
|
||||
std::vector<uint256> vecDirty;
|
||||
{
|
||||
std::map<uint256, int>::iterator it = mapGovernanceObjectsVotedOn.begin();
|
||||
while(it != mapGovernanceObjectsVotedOn.end()) {
|
||||
vecDirty.push_back(it->first);
|
||||
++it;
|
||||
}
|
||||
}
|
||||
for(size_t i = 0; i < vecDirty.size(); ++i) {
|
||||
mnodeman.AddDirtyGovernanceObjectHash(vecDirty[i]);
|
||||
}
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ static const int MASTERNODE_MIN_DSEG_SECONDS = 10 * 60;
|
||||
static const int MASTERNODE_EXPIRATION_SECONDS = 65 * 60;
|
||||
static const int MASTERNODE_REMOVAL_SECONDS = 75 * 60;
|
||||
static const int MASTERNODE_CHECK_SECONDS = 5;
|
||||
static const int MASTERNODE_WATCHDOG_MAX_SECONDS = 2 * 60 * 60;
|
||||
|
||||
//
|
||||
// The Masternode Ping Class : Contains a different serialize method for sending pings from masternodes throughout the network
|
||||
@ -95,6 +96,36 @@ public:
|
||||
|
||||
};
|
||||
|
||||
struct masternode_info_t {
|
||||
|
||||
masternode_info_t()
|
||||
: vin(),
|
||||
addr(),
|
||||
pubKeyCollateralAddress(),
|
||||
pubKeyMasternode(),
|
||||
sigTime(0),
|
||||
nLastDsq(0),
|
||||
nTimeLastChecked(0),
|
||||
nTimeLastPaid(0),
|
||||
nTimeLastWatchdogVote(0),
|
||||
nActiveState(0),
|
||||
nProtocolVersion(0),
|
||||
fInfoValid(false)
|
||||
{}
|
||||
|
||||
CTxIn vin;
|
||||
CService addr;
|
||||
CPubKey pubKeyCollateralAddress;
|
||||
CPubKey pubKeyMasternode;
|
||||
int64_t sigTime; //mnb message time
|
||||
int64_t nLastDsq; //the dsq count from the last dsq broadcast of this node
|
||||
int64_t nTimeLastChecked;
|
||||
int64_t nTimeLastPaid;
|
||||
int64_t nTimeLastWatchdogVote;
|
||||
int nActiveState;
|
||||
int nProtocolVersion;
|
||||
bool fInfoValid;
|
||||
};
|
||||
|
||||
//
|
||||
// The Masternode Class. For managing the Darksend process. It contains the input of the 1000DRK, signature to prove
|
||||
@ -112,7 +143,8 @@ public:
|
||||
MASTERNODE_ENABLED,
|
||||
MASTERNODE_EXPIRED,
|
||||
MASTERNODE_OUTPOINT_SPENT,
|
||||
MASTERNODE_REMOVE
|
||||
MASTERNODE_REMOVE,
|
||||
MASTERNODE_WATCHDOG_EXPIRED
|
||||
};
|
||||
|
||||
CTxIn vin;
|
||||
@ -125,6 +157,7 @@ public:
|
||||
int64_t nLastDsq; //the dsq count from the last dsq broadcast of this node
|
||||
int64_t nTimeLastChecked;
|
||||
int64_t nTimeLastPaid;
|
||||
int64_t nTimeLastWatchdogVote;
|
||||
int nActiveState;
|
||||
int nCacheCollateralBlock;
|
||||
int nBlockLastPaid;
|
||||
@ -133,7 +166,7 @@ public:
|
||||
bool fUnitTest;
|
||||
|
||||
// KEEP TRACK OF GOVERNANCE ITEMS EACH MASTERNODE HAS VOTE UPON FOR RECALCULATION
|
||||
std::map<uint256, int> mapGovernaceObjectsVotedOn;
|
||||
std::map<uint256, int> mapGovernanceObjectsVotedOn;
|
||||
|
||||
CMasternode();
|
||||
CMasternode(const CMasternode& other);
|
||||
@ -155,13 +188,14 @@ public:
|
||||
READWRITE(nLastDsq);
|
||||
READWRITE(nTimeLastChecked);
|
||||
READWRITE(nTimeLastPaid);
|
||||
READWRITE(nTimeLastWatchdogVote);
|
||||
READWRITE(nActiveState);
|
||||
READWRITE(nCacheCollateralBlock);
|
||||
READWRITE(nBlockLastPaid);
|
||||
READWRITE(nProtocolVersion);
|
||||
READWRITE(fAllowMixingTx);
|
||||
READWRITE(fUnitTest);
|
||||
READWRITE(mapGovernaceObjectsVotedOn);
|
||||
READWRITE(mapGovernanceObjectsVotedOn);
|
||||
}
|
||||
|
||||
void swap(CMasternode& first, CMasternode& second) // nothrow
|
||||
@ -181,13 +215,14 @@ public:
|
||||
swap(first.nLastDsq, second.nLastDsq);
|
||||
swap(first.nTimeLastChecked, second.nTimeLastChecked);
|
||||
swap(first.nTimeLastPaid, second.nTimeLastPaid);
|
||||
swap(first.nTimeLastWatchdogVote, second.nTimeLastWatchdogVote);
|
||||
swap(first.nActiveState, second.nActiveState);
|
||||
swap(first.nCacheCollateralBlock, second.nCacheCollateralBlock);
|
||||
swap(first.nBlockLastPaid, second.nBlockLastPaid);
|
||||
swap(first.nProtocolVersion, second.nProtocolVersion);
|
||||
swap(first.fAllowMixingTx, second.fAllowMixingTx);
|
||||
swap(first.fUnitTest, second.fUnitTest);
|
||||
swap(first.mapGovernaceObjectsVotedOn, second.mapGovernaceObjectsVotedOn);
|
||||
swap(first.mapGovernanceObjectsVotedOn, second.mapGovernanceObjectsVotedOn);
|
||||
}
|
||||
|
||||
// CALCULATE A RANK AGAINST OF GIVEN BLOCK
|
||||
@ -212,8 +247,12 @@ public:
|
||||
bool IsEnabled() { return nActiveState == MASTERNODE_ENABLED; }
|
||||
bool IsPreEnabled() { return nActiveState == MASTERNODE_PRE_ENABLED; }
|
||||
|
||||
bool IsWatchdogExpired() { return nActiveState == MASTERNODE_WATCHDOG_EXPIRED; }
|
||||
|
||||
bool IsValidNetAddr();
|
||||
|
||||
masternode_info_t GetInfo();
|
||||
|
||||
std::string GetStatus();
|
||||
|
||||
int GetCollateralAge();
|
||||
@ -226,8 +265,10 @@ public:
|
||||
void AddGovernanceVote(uint256 nGovernanceObjectHash);
|
||||
// RECALCULATE CACHED STATUS FLAGS FOR ALL AFFECTED OBJECTS
|
||||
void FlagGovernanceItemsAsDirty();
|
||||
// TODO: There probably should be some method to clean mapGovernaceObjectsVotedOn map
|
||||
// under some conditions. We shouldn't store everything in memory forever.
|
||||
|
||||
void RemoveGovernanceObject(uint256 nGovernanceObjectHash);
|
||||
|
||||
void UpdateWatchdogVoteTime();
|
||||
|
||||
CMasternode& operator=(CMasternode from)
|
||||
{
|
||||
|
@ -35,8 +35,11 @@ struct CompareScoreMN
|
||||
}
|
||||
};
|
||||
|
||||
const std::string CMasternodeMan::SERIALIZATION_VERSION_STRING = "CMasternodeMan-Version-1";
|
||||
|
||||
CMasternodeMan::CMasternodeMan() {
|
||||
nDsqCount = 0;
|
||||
nLastWatchdogVoteTime = 0;
|
||||
}
|
||||
|
||||
bool CMasternodeMan::Add(CMasternode &mn)
|
||||
@ -78,6 +81,8 @@ void CMasternodeMan::Check()
|
||||
{
|
||||
LOCK(cs);
|
||||
|
||||
LogPrint("masternode", "CMasternodeMan::Check nLastWatchdogVoteTime = %d, IsWatchdogActive() = %d\n", nLastWatchdogVoteTime, IsWatchdogActive());
|
||||
|
||||
BOOST_FOREACH(CMasternode& mn, vMasternodes) {
|
||||
mn.Check();
|
||||
}
|
||||
@ -180,10 +185,26 @@ void CMasternodeMan::Clear()
|
||||
mapSeenMasternodeBroadcast.clear();
|
||||
mapSeenMasternodePing.clear();
|
||||
nDsqCount = 0;
|
||||
nLastWatchdogVoteTime = 0;
|
||||
}
|
||||
|
||||
int CMasternodeMan::CountMasternodes(int protocolVersion)
|
||||
{
|
||||
LOCK(cs);
|
||||
int i = 0;
|
||||
protocolVersion = protocolVersion == -1 ? mnpayments.GetMinMasternodePaymentsProto() : protocolVersion;
|
||||
|
||||
BOOST_FOREACH(CMasternode& mn, vMasternodes) {
|
||||
if(mn.nProtocolVersion < protocolVersion) continue;
|
||||
i++;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
int CMasternodeMan::CountEnabled(int protocolVersion)
|
||||
{
|
||||
LOCK(cs);
|
||||
int i = 0;
|
||||
protocolVersion = protocolVersion == -1 ? mnpayments.GetMinMasternodePaymentsProto() : protocolVersion;
|
||||
|
||||
@ -198,6 +219,7 @@ int CMasternodeMan::CountEnabled(int protocolVersion)
|
||||
|
||||
int CMasternodeMan::CountByIP(int nNetworkType)
|
||||
{
|
||||
LOCK(cs);
|
||||
int nNodeCount = 0;
|
||||
|
||||
BOOST_FOREACH(CMasternode& mn, vMasternodes)
|
||||
@ -292,6 +314,37 @@ bool CMasternodeMan::Get(const CTxIn& vin, CMasternode& masternode)
|
||||
return true;
|
||||
}
|
||||
|
||||
masternode_info_t CMasternodeMan::GetMasternodeInfo(const CTxIn& vin)
|
||||
{
|
||||
masternode_info_t info;
|
||||
LOCK(cs);
|
||||
CMasternode* pMN = Find(vin);
|
||||
if(!pMN) {
|
||||
return info;
|
||||
}
|
||||
info = pMN->GetInfo();
|
||||
return info;
|
||||
}
|
||||
|
||||
masternode_info_t CMasternodeMan::GetMasternodeInfo(const CPubKey& pubKeyMasternode)
|
||||
{
|
||||
masternode_info_t info;
|
||||
LOCK(cs);
|
||||
CMasternode* pMN = Find(pubKeyMasternode);
|
||||
if(!pMN) {
|
||||
return info;
|
||||
}
|
||||
info = pMN->GetInfo();
|
||||
return info;
|
||||
}
|
||||
|
||||
bool CMasternodeMan::Has(const CTxIn& vin)
|
||||
{
|
||||
LOCK(cs);
|
||||
CMasternode* pMN = Find(vin);
|
||||
return (pMN != NULL);
|
||||
}
|
||||
|
||||
//
|
||||
// Deterministically select the oldest/best masternode to pay on the network
|
||||
//
|
||||
@ -544,7 +597,7 @@ void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CData
|
||||
if(fLiteMode) return; //disable all Darksend/Masternode related functionality
|
||||
if(!masternodeSync.IsBlockchainSynced()) return;
|
||||
|
||||
LOCK(cs_process_message);
|
||||
LOCK(cs);
|
||||
|
||||
if (strCommand == NetMsgType::MNANNOUNCE) { //Masternode Broadcast
|
||||
CMasternodeBroadcast mnb;
|
||||
@ -707,6 +760,7 @@ int CMasternodeMan::GetEstimatedMasternodes(int nBlock)
|
||||
}
|
||||
|
||||
void CMasternodeMan::UpdateMasternodeList(CMasternodeBroadcast mnb) {
|
||||
LOCK(cs);
|
||||
mapSeenMasternodePing.insert(make_pair(mnb.lastPing.GetHash(), mnb.lastPing));
|
||||
mapSeenMasternodeBroadcast.insert(make_pair(mnb.GetHash(), mnb));
|
||||
|
||||
@ -725,6 +779,7 @@ void CMasternodeMan::UpdateMasternodeList(CMasternodeBroadcast mnb) {
|
||||
}
|
||||
|
||||
bool CMasternodeMan::CheckMnbAndUpdateMasternodeList(CMasternodeBroadcast mnb, int& nDos) {
|
||||
LOCK(cs);
|
||||
nDos = 0;
|
||||
LogPrint("masternode", "CMasternodeMan::CheckMnbAndUpdateMasternodeList - Masternode broadcast, vin: %s\n", mnb.vin.ToString());
|
||||
|
||||
@ -759,6 +814,7 @@ bool CMasternodeMan::CheckMnbAndUpdateMasternodeList(CMasternodeBroadcast mnb, i
|
||||
}
|
||||
|
||||
void CMasternodeMan::UpdateLastPaid(const CBlockIndex *pindex) {
|
||||
LOCK(cs);
|
||||
if(fLiteMode) return;
|
||||
|
||||
static bool IsFirstRun = true;
|
||||
@ -776,3 +832,106 @@ void CMasternodeMan::UpdateLastPaid(const CBlockIndex *pindex) {
|
||||
// every time is like the first time if winners list is not synced
|
||||
IsFirstRun = !masternodeSync.IsWinnersListSynced();
|
||||
}
|
||||
|
||||
void CMasternodeMan::UpdateWatchdogVoteTime(const CTxIn& vin)
|
||||
{
|
||||
LOCK(cs);
|
||||
CMasternode* pMN = Find(vin);
|
||||
if(!pMN) {
|
||||
return;
|
||||
}
|
||||
pMN->UpdateWatchdogVoteTime();
|
||||
nLastWatchdogVoteTime = GetTime();
|
||||
}
|
||||
|
||||
bool CMasternodeMan::IsWatchdogActive()
|
||||
{
|
||||
LOCK(cs);
|
||||
// Check if any masternodes have voted recently, otherwise return false
|
||||
return (GetTime() - nLastWatchdogVoteTime) <= MASTERNODE_WATCHDOG_MAX_SECONDS;
|
||||
}
|
||||
|
||||
void CMasternodeMan::AddGovernanceVote(const CTxIn& vin, uint256 nGovernanceObjectHash)
|
||||
{
|
||||
LOCK(cs);
|
||||
CMasternode* pMN = Find(vin);
|
||||
if(!pMN) {
|
||||
return;
|
||||
}
|
||||
pMN->AddGovernanceVote(nGovernanceObjectHash);
|
||||
}
|
||||
|
||||
void CMasternodeMan::RemoveGovernanceObject(uint256 nGovernanceObjectHash)
|
||||
{
|
||||
LOCK(cs);
|
||||
BOOST_FOREACH(CMasternode& mn, vMasternodes) {
|
||||
mn.RemoveGovernanceObject(nGovernanceObjectHash);
|
||||
}
|
||||
}
|
||||
|
||||
void CMasternodeMan::CheckMasternode(const CTxIn& vin, bool fForce)
|
||||
{
|
||||
LOCK(cs);
|
||||
CMasternode* pMN = Find(vin);
|
||||
if(!pMN) {
|
||||
return;
|
||||
}
|
||||
pMN->Check(fForce);
|
||||
}
|
||||
|
||||
void CMasternodeMan::CheckMasternode(const CPubKey& pubKeyMasternode, bool fForce)
|
||||
{
|
||||
LOCK(cs);
|
||||
CMasternode* pMN = Find(pubKeyMasternode);
|
||||
if(!pMN) {
|
||||
return;
|
||||
}
|
||||
pMN->Check(fForce);
|
||||
}
|
||||
|
||||
int CMasternodeMan::GetMasternodeState(const CTxIn& vin)
|
||||
{
|
||||
LOCK(cs);
|
||||
CMasternode* pMN = Find(vin);
|
||||
if(!pMN) {
|
||||
return CMasternode::MASTERNODE_REMOVE;
|
||||
}
|
||||
return pMN->nActiveState;
|
||||
}
|
||||
|
||||
int CMasternodeMan::GetMasternodeState(const CPubKey& pubKeyMasternode)
|
||||
{
|
||||
LOCK(cs);
|
||||
CMasternode* pMN = Find(pubKeyMasternode);
|
||||
if(!pMN) {
|
||||
return CMasternode::MASTERNODE_REMOVE;
|
||||
}
|
||||
return pMN->nActiveState;
|
||||
}
|
||||
|
||||
bool CMasternodeMan::IsMasternodePingedWithin(const CTxIn& vin, int nSeconds, int64_t nTimeToCheckAt)
|
||||
{
|
||||
LOCK(cs);
|
||||
CMasternode* pMN = Find(vin);
|
||||
if(!pMN) {
|
||||
return false;
|
||||
}
|
||||
return pMN->IsPingedWithin(nSeconds, nTimeToCheckAt);
|
||||
}
|
||||
|
||||
void CMasternodeMan::SetMasternodeLastPing(const CTxIn& vin, const CMasternodePing& mnp)
|
||||
{
|
||||
LOCK(cs);
|
||||
CMasternode* pMN = Find(vin);
|
||||
if(!pMN) {
|
||||
return;
|
||||
}
|
||||
pMN->lastPing = mnp;
|
||||
mapSeenMasternodePing.insert(std::make_pair(mnp.GetHash(), mnp));
|
||||
|
||||
CMasternodeBroadcast mnb(*pMN);
|
||||
uint256 hash = mnb.GetHash();
|
||||
if(mapSeenMasternodeBroadcast.count(hash)) {
|
||||
mapSeenMasternodeBroadcast[hash].lastPing = mnp;
|
||||
}
|
||||
}
|
||||
|
@ -24,6 +24,8 @@ extern CMasternodeMan mnodeman;
|
||||
class CMasternodeMan
|
||||
{
|
||||
private:
|
||||
static const std::string SERIALIZATION_VERSION_STRING;
|
||||
|
||||
static const int MASTERNODES_LAST_PAID_SCAN_BLOCKS = 100;
|
||||
|
||||
// critical section to protect the inner data structures
|
||||
@ -41,6 +43,10 @@ private:
|
||||
// which Masternodes we've asked for
|
||||
std::map<COutPoint, int64_t> mWeAskedForMasternodeListEntry;
|
||||
|
||||
std::vector<uint256> vecDirtyGovernanceObjectHashes;
|
||||
|
||||
int64_t nLastWatchdogVoteTime;
|
||||
|
||||
public:
|
||||
// Keep track of all broadcasts I've seen
|
||||
map<uint256, CMasternodeBroadcast> mapSeenMasternodeBroadcast;
|
||||
@ -58,14 +64,28 @@ public:
|
||||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
|
||||
LOCK(cs);
|
||||
std::string strVersion;
|
||||
if(ser_action.ForRead()) {
|
||||
READWRITE(strVersion);
|
||||
}
|
||||
else {
|
||||
strVersion = SERIALIZATION_VERSION_STRING;
|
||||
READWRITE(strVersion);
|
||||
}
|
||||
|
||||
READWRITE(vMasternodes);
|
||||
READWRITE(mAskedUsForMasternodeList);
|
||||
READWRITE(mWeAskedForMasternodeList);
|
||||
READWRITE(mWeAskedForMasternodeListEntry);
|
||||
READWRITE(nLastWatchdogVoteTime);
|
||||
READWRITE(nDsqCount);
|
||||
|
||||
READWRITE(mapSeenMasternodeBroadcast);
|
||||
READWRITE(mapSeenMasternodePing);
|
||||
if(ser_action.ForRead() && (strVersion != SERIALIZATION_VERSION_STRING)) {
|
||||
LogPrintf("CMasternodeMan::SerializationOp - Incompatible format detected, resetting data\n");
|
||||
Clear();
|
||||
}
|
||||
}
|
||||
|
||||
CMasternodeMan();
|
||||
@ -86,6 +106,8 @@ public:
|
||||
/// Clear Masternode vector
|
||||
void Clear();
|
||||
|
||||
int CountMasternodes(int protocolVersion = -1);
|
||||
|
||||
int CountEnabled(int protocolVersion = -1);
|
||||
|
||||
/// Count Masternodes by network type - NET_IPV4, NET_IPV6, NET_TOR
|
||||
@ -102,6 +124,12 @@ public:
|
||||
bool Get(const CPubKey& pubKeyMasternode, CMasternode& masternode);
|
||||
bool Get(const CTxIn& vin, CMasternode& masternode);
|
||||
|
||||
bool Has(const CTxIn& vin);
|
||||
|
||||
masternode_info_t GetMasternodeInfo(const CTxIn& vin);
|
||||
|
||||
masternode_info_t GetMasternodeInfo(const CPubKey& pubKeyMasternode);
|
||||
|
||||
/// Find an entry in the masternode list that is next to be paid
|
||||
CMasternode* GetNextMasternodeInQueueForPayment(int nBlockHeight, bool fFilterSigTime, int& nCount);
|
||||
|
||||
@ -135,6 +163,40 @@ public:
|
||||
bool CheckMnbAndUpdateMasternodeList(CMasternodeBroadcast mnb, int& nDos);
|
||||
|
||||
void UpdateLastPaid(const CBlockIndex *pindex);
|
||||
|
||||
void AddDirtyGovernanceObjectHash(const uint256& nHash)
|
||||
{
|
||||
LOCK(cs);
|
||||
vecDirtyGovernanceObjectHashes.push_back(nHash);
|
||||
}
|
||||
|
||||
std::vector<uint256> GetAndClearDirtyGovernanceObjectHashes()
|
||||
{
|
||||
LOCK(cs);
|
||||
std::vector<uint256> vecTmp = vecDirtyGovernanceObjectHashes;
|
||||
vecDirtyGovernanceObjectHashes.clear();
|
||||
return vecTmp;;
|
||||
}
|
||||
|
||||
bool IsWatchdogActive();
|
||||
|
||||
void UpdateWatchdogVoteTime(const CTxIn& vin);
|
||||
|
||||
void AddGovernanceVote(const CTxIn& vin, uint256 nGovernanceObjectHash);
|
||||
|
||||
void RemoveGovernanceObject(uint256 nGovernanceObjectHash);
|
||||
|
||||
void CheckMasternode(const CTxIn& vin, bool fForce = false);
|
||||
|
||||
void CheckMasternode(const CPubKey& pubKeyMasternode, bool fForce = false);
|
||||
|
||||
int GetMasternodeState(const CTxIn& vin);
|
||||
|
||||
int GetMasternodeState(const CPubKey& pubKeyMasternode);
|
||||
|
||||
bool IsMasternodePingedWithin(const CTxIn& vin, int nSeconds, int64_t nTimeToCheckAt = -1);
|
||||
|
||||
void SetMasternodeLastPing(const CTxIn& vin, const CMasternodePing& mnp);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "darksend.h"
|
||||
#include "governance.h"
|
||||
#include "darksend.h"
|
||||
#include "masternode.h"
|
||||
#include "masternode-payments.h"
|
||||
#include "masternode-sync.h"
|
||||
#include "masternodeconfig.h"
|
||||
@ -107,8 +108,9 @@ UniValue gobject(const UniValue& params, bool fHelp)
|
||||
|
||||
CGovernanceObject govobj(hashParent, nRevision, nTime, uint256(), strData);
|
||||
|
||||
if(govobj.GetObjectType() == GOVERNANCE_OBJECT_TRIGGER) {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Trigger objects need not be prepared (however only masternodes can create them)");
|
||||
if((govobj.GetObjectType() == GOVERNANCE_OBJECT_TRIGGER) ||
|
||||
(govobj.GetObjectType() == GOVERNANCE_OBJECT_WATCHDOG)) {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Trigger and watchdog objects need not be prepared (however only masternodes can create them)");
|
||||
}
|
||||
|
||||
std::string strError = "";
|
||||
@ -187,7 +189,8 @@ UniValue gobject(const UniValue& params, bool fHelp)
|
||||
<< endl; );
|
||||
|
||||
// Attempt to sign triggers if we are a MN
|
||||
if(govobj.GetObjectType() == GOVERNANCE_OBJECT_TRIGGER) {
|
||||
if((govobj.GetObjectType() == GOVERNANCE_OBJECT_TRIGGER) ||
|
||||
(govobj.GetObjectType() == GOVERNANCE_OBJECT_WATCHDOG)) {
|
||||
if(mnFound) {
|
||||
govobj.SetMasternodeInfo(mn.vin);
|
||||
govobj.Sign(activeMasternode.keyMasternode, activeMasternode.pubKeyMasternode);
|
||||
@ -773,11 +776,12 @@ UniValue getgovernanceinfo(const UniValue& params, bool fHelp)
|
||||
"Returns an object containing governance parameters.\n"
|
||||
"\nResult:\n"
|
||||
"{\n"
|
||||
" \"governanceminquorum\": xxxxx, (numeric) the absolute minimum number of votes needed to trigger a governance action\n"
|
||||
" \"proposalfee\": xxx.xx, (numeric) the collateral transaction fee which must be paid to create a proposal in " + CURRENCY_UNIT + "\n"
|
||||
" \"superblockcycle\": xxxxx, (numeric) the number of blocks between superblocks\n"
|
||||
" \"lastsuperblock\": xxxxx, (numeric) the block number of the last superblock\n"
|
||||
" \"nextsuperblock\": xxxxx, (numeric) the block number of the next superblock\n"
|
||||
" \"governanceminquorum\": xxxxx, (numeric) the absolute minimum number of votes needed to trigger a governance action\n"
|
||||
" \"masternodewatchdogmaxseconds\": xxxxx, (numeric) sentinel watchdog expiration time in seconds\n"
|
||||
" \"proposalfee\": xxx.xx, (numeric) the collateral transaction fee which must be paid to create a proposal in " + CURRENCY_UNIT + "\n"
|
||||
" \"superblockcycle\": xxxxx, (numeric) the number of blocks between superblocks\n"
|
||||
" \"lastsuperblock\": xxxxx, (numeric) the block number of the last superblock\n"
|
||||
" \"nextsuperblock\": xxxxx, (numeric) the block number of the next superblock\n"
|
||||
"}\n"
|
||||
"\nExamples:\n"
|
||||
+ HelpExampleCli("getgovernanceinfo", "")
|
||||
@ -813,6 +817,7 @@ UniValue getgovernanceinfo(const UniValue& params, bool fHelp)
|
||||
|
||||
UniValue obj(UniValue::VOBJ);
|
||||
obj.push_back(Pair("governanceminquorum", Params().GetConsensus().nGovernanceMinQuorum));
|
||||
obj.push_back(Pair("masternodewatchdogmaxseconds", MASTERNODE_WATCHDOG_MAX_SECONDS));
|
||||
obj.push_back(Pair("proposalfee", ValueFromAmount(GOVERNANCE_PROPOSAL_FEE_TX)));
|
||||
obj.push_back(Pair("superblockcycle", Params().GetConsensus().nSuperblockCycle));
|
||||
obj.push_back(Pair("lastsuperblock", nLastSuperblock));
|
||||
|
Loading…
Reference in New Issue
Block a user