Updated Reference-Node Implementation

- Added nLastPaid to masternode information for persistant storage of the masternode payment cycle
- Masternodes get flagged as just paid when they enter the masternode list and must wait a full cycle to be paid again
- Masternode RPC commands now show short vin string instead of ip address
This commit is contained in:
Evan Duffield 2015-04-16 07:08:06 -07:00
parent 5daefc1a08
commit 88f6a598b9
7 changed files with 65 additions and 40 deletions

View File

@ -156,6 +156,9 @@ CMasternode::CMasternode()
lastVote = 0;
nScanningErrorCount = 0;
nLastScanningErrorBlockHeight = 0;
//mark last paid as current for new entries
nLastPaid = GetAdjustedTime();
}
CMasternode::CMasternode(const CMasternode& other)
@ -182,6 +185,7 @@ CMasternode::CMasternode(const CMasternode& other)
lastVote = other.lastVote;
nScanningErrorCount = other.nScanningErrorCount;
nLastScanningErrorBlockHeight = other.nLastScanningErrorBlockHeight;
nLastPaid = other.nLastPaid;
}
CMasternode::CMasternode(CService newAddr, CTxIn newVin, CPubKey newPubkey, std::vector<unsigned char> newSig, int64_t newSigTime, CPubKey newPubkey2, int protocolVersionIn, CScript newDonationAddress, int newDonationPercentage)
@ -208,6 +212,7 @@ CMasternode::CMasternode(CService newAddr, CTxIn newVin, CPubKey newPubkey, std:
lastVote = 0;
nScanningErrorCount = 0;
nLastScanningErrorBlockHeight = 0;
nLastPaid = GetAdjustedTime();
}
//
@ -434,7 +439,7 @@ bool CMasternodePayments::ProcessBlock(int nBlockHeight)
}
// pay to the oldest MN that still had no payment but its input is old enough and it was active long enough
CMasternode *pmn = mnodeman.FindOldestNotInVec(vecLastPayments, nMinimumAge, 0);
CMasternode *pmn = mnodeman.FindOldestNotInVec(vecLastPayments, nMinimumAge);
if(pmn != NULL)
{
LogPrintf(" Found by FindOldestNotInVec \n");
@ -442,6 +447,7 @@ bool CMasternodePayments::ProcessBlock(int nBlockHeight)
newWinner.score = 0;
newWinner.nBlockHeight = nBlockHeight;
newWinner.vin = pmn->vin;
pmn->nLastPaid = GetAdjustedTime();
if(pmn->donationPercentage > 0 && (nHash % 100) <= (unsigned int)pmn->donationPercentage) {
newWinner.payee = pmn->donationAddress;
@ -468,6 +474,7 @@ bool CMasternodePayments::ProcessBlock(int nBlockHeight)
newWinner.score = 0;
newWinner.nBlockHeight = nBlockHeight;
newWinner.vin = pmn->vin;
pmn->nLastPaid = GetAdjustedTime();
if(pmn->donationPercentage > 0 && (nHash % 100) <= (unsigned int)pmn->donationPercentage) {
newWinner.payee = pmn->donationAddress;

View File

@ -84,6 +84,7 @@ public:
int64_t lastVote;
int nScanningErrorCount;
int nLastScanningErrorBlockHeight;
int64_t nLastPaid;
CMasternode();
CMasternode(const CMasternode& other);
@ -117,6 +118,7 @@ public:
swap(first.lastVote, second.lastVote);
swap(first.nScanningErrorCount, second.nScanningErrorCount);
swap(first.nLastScanningErrorBlockHeight, second.nLastScanningErrorBlockHeight);
swap(first.nLastPaid, second.nLastPaid);
}
CMasternode& operator=(CMasternode from)
@ -161,6 +163,12 @@ public:
READWRITE(lastVote);
READWRITE(nScanningErrorCount);
READWRITE(nLastScanningErrorBlockHeight);
READWRITE(nLastPaid);
}
int64_t SecondsSincePayment()
{
return (GetAdjustedTime() - nLastPaid);
}
void UpdateLastSeen(int64_t override=0)

View File

@ -345,8 +345,7 @@ CMasternode *CMasternodeMan::Find(const CPubKey &pubKeyMasternode)
return NULL;
}
CMasternode* CMasternodeMan::FindOldestNotInVec(const std::vector<CTxIn> &vVins, int nMinimumAge, int nMinimumActiveSeconds)
CMasternode* CMasternodeMan::FindOldestNotInVec(const std::vector<CTxIn> &vVins, int nMinimumAge)
{
LOCK(cs);
@ -357,9 +356,7 @@ CMasternode* CMasternodeMan::FindOldestNotInVec(const std::vector<CTxIn> &vVins,
mn.Check();
if(!mn.IsEnabled()) continue;
if(Params().NetworkID() != CBaseChainParams::REGTEST){
if(mn.GetMasternodeInputAge() < nMinimumAge || mn.lastTimeSeen - mn.sigTime < nMinimumActiveSeconds) continue;
}
if(Params().NetworkID() != CBaseChainParams::REGTEST && mn.GetMasternodeInputAge() < nMinimumAge) continue;
bool found = false;
BOOST_FOREACH(const CTxIn& vin, vVins)
@ -371,7 +368,7 @@ CMasternode* CMasternodeMan::FindOldestNotInVec(const std::vector<CTxIn> &vVins,
if(found) continue;
if(pOldestMasternode == NULL || pOldestMasternode->GetMasternodeInputAge() < mn.GetMasternodeInputAge()){
if(pOldestMasternode == NULL || pOldestMasternode->SecondsSincePayment() < mn.SecondsSincePayment()){
pOldestMasternode = &mn;
}
}

View File

@ -103,7 +103,7 @@ public:
CMasternode* Find(const CPubKey& pubKeyMasternode);
/// Find an entry thta do not match every entry provided vector
CMasternode* FindOldestNotInVec(const std::vector<CTxIn> &vVins, int nMinimumAge, int nMinimumActiveSeconds);
CMasternode* FindOldestNotInVec(const std::vector<CTxIn> &vVins, int nMinimumAge);
/// Find a random entry
CMasternode* FindRandom();

View File

@ -14,6 +14,11 @@ std::string COutPoint::ToString() const
return strprintf("COutPoint(%s, %u)", hash.ToString()/*.substr(0,10)*/, n);
}
std::string COutPoint::ToStringShort() const
{
return strprintf("%s-%u", hash.ToString().substr(0,64), n);
}
CTxIn::CTxIn(COutPoint prevoutIn, CScript scriptSigIn, uint32_t nSequenceIn)
{
prevout = prevoutIn;

View File

@ -47,6 +47,8 @@ public:
}
std::string ToString() const;
std::string ToStringShort() const;
};
/** An input of a transaction. It contains the location of the previous
@ -145,7 +147,7 @@ public:
// to spend something, then we consider it dust.
// A typical txout is 34 bytes big, and will
// need a CTxIn of at least 148 bytes to spend:
// so dust is a txout less than 546 satoshis
// so dust is a txout less than 546 satoshis
// with default minRelayTxFee.
size_t nSize = GetSerializeSize(SER_DISK,0)+148u;
return (nValue < 3*minRelayTxFee.GetFee(nSize));

View File

@ -641,7 +641,7 @@ Value masternode(const Array& params, bool fHelp)
failed++;
continue;
}
CMasternode* pmn = mnodeman.Find(pubKeyMasternode);
if(pmn == NULL)
{
@ -728,7 +728,7 @@ Value masternodelist(const Array& params, bool fHelp)
if (fHelp ||
(strMode != "status" && strMode != "vin" && strMode != "pubkey" && strMode != "lastseen" && strMode != "activeseconds" && strMode != "rank"
&& strMode != "protocol" && strMode != "full" && strMode != "votes" && strMode != "donation" && strMode != "pose"))
&& strMode != "protocol" && strMode != "full" && strMode != "votes" && strMode != "donation" && strMode != "pose" && strMode != "lastpaid"))
{
throw runtime_error(
"masternodelist ( \"mode\" \"filter\" )\n"
@ -750,9 +750,10 @@ Value masternodelist(const Array& params, bool fHelp)
" rank - Print rank of a masternode based on current block\n"
" status - Print masternode status: ENABLED / EXPIRED / VIN_SPENT / REMOVE / POS_ERROR\n"
" (can be additionally filtered, partial match)\n"
" vin - Print vin associated with a masternode (can be additionally filtered, partial match)\n"
" addr - Print ip address associated with a masternode (can be additionally filtered, partial match)\n"
" votes - Print all masternode votes for a Dash initiative (can be additionally filtered,\n"
" partial match)\n"
" lastpaid - The last time a node was paid on the network\n"
);
}
@ -760,24 +761,24 @@ Value masternodelist(const Array& params, bool fHelp)
if (strMode == "rank") {
std::vector<pair<int, CMasternode> > vMasternodeRanks = mnodeman.GetMasternodeRanks(chainActive.Tip()->nHeight);
BOOST_FOREACH(PAIRTYPE(int, CMasternode)& s, vMasternodeRanks) {
std::string strAddr = s.second.addr.ToString();
if(strFilter !="" && strAddr.find(strFilter) == string::npos) continue;
obj.push_back(Pair(strAddr, s.first));
std::string strVin = s.second.vin.prevout.ToStringShort();
if(strFilter !="" && strVin.find(strFilter) == string::npos) continue;
obj.push_back(Pair(strVin, s.first));
}
} else {
std::vector<CMasternode> vMasternodes = mnodeman.GetFullMasternodeVector();
BOOST_FOREACH(CMasternode& mn, vMasternodes) {
std::string strAddr = mn.addr.ToString();
std::string strVin = mn.vin.prevout.ToStringShort();
if (strMode == "activeseconds") {
if(strFilter !="" && strAddr.find(strFilter) == string::npos) continue;
obj.push_back(Pair(strAddr, (int64_t)(mn.lastTimeSeen - mn.sigTime)));
if(strFilter !="" && strVin.find(strFilter) == string::npos) continue;
obj.push_back(Pair(strVin, (int64_t)(mn.lastTimeSeen - mn.sigTime)));
} else if (strMode == "donation") {
CTxDestination address1;
ExtractDestination(mn.donationAddress, address1);
CBitcoinAddress address2(address1);
if(strFilter !="" && address2.ToString().find(strFilter) == string::npos &&
strAddr.find(strFilter) == string::npos) continue;
strVin.find(strFilter) == string::npos) continue;
std::string strOut = "";
@ -786,7 +787,7 @@ Value masternodelist(const Array& params, bool fHelp)
strOut += ":";
strOut += boost::lexical_cast<std::string>(mn.donationPercentage);
}
obj.push_back(Pair(strAddr, strOut.c_str()));
obj.push_back(Pair(strVin, strOut.c_str()));
} else if (strMode == "full") {
CScript pubkey;
pubkey = GetScriptForDestination(mn.pubkey.GetID());
@ -795,28 +796,29 @@ Value masternodelist(const Array& params, bool fHelp)
CBitcoinAddress address2(address1);
std::ostringstream addrStream;
addrStream << setw(21) << strAddr;
addrStream << setw(21) << strVin;
std::ostringstream stringStream;
stringStream << setw(10) <<
mn.Status() << " " <<
mn.protocolVersion << " " <<
address2.ToString() << " " <<
mn.vin.prevout.hash.ToString() << " " <<
mn.addr.ToString() << " " <<
mn.lastTimeSeen << " " << setw(8) <<
(mn.lastTimeSeen - mn.sigTime);
(mn.lastTimeSeen - mn.sigTime) << " " <<
mn.nLastPaid;
std::string output = stringStream.str();
stringStream << " " << strAddr;
stringStream << " " << strVin;
if(strFilter !="" && stringStream.str().find(strFilter) == string::npos &&
strAddr.find(strFilter) == string::npos) continue;
strVin.find(strFilter) == string::npos) continue;
obj.push_back(Pair(addrStream.str(), output));
} else if (strMode == "lastseen") {
if(strFilter !="" && strAddr.find(strFilter) == string::npos) continue;
obj.push_back(Pair(strAddr, (int64_t)mn.lastTimeSeen));
if(strFilter !="" && strVin.find(strFilter) == string::npos) continue;
obj.push_back(Pair(strVin, (int64_t)mn.lastTimeSeen));
} else if (strMode == "protocol") {
if(strFilter !="" && strFilter != boost::lexical_cast<std::string>(mn.protocolVersion) &&
strAddr.find(strFilter) == string::npos) continue;
obj.push_back(Pair(strAddr, (int64_t)mn.protocolVersion));
strVin.find(strFilter) == string::npos) continue;
obj.push_back(Pair(strVin, (int64_t)mn.protocolVersion));
} else if (strMode == "pubkey") {
CScript pubkey;
pubkey = GetScriptForDestination(mn.pubkey.GetID());
@ -825,20 +827,20 @@ Value masternodelist(const Array& params, bool fHelp)
CBitcoinAddress address2(address1);
if(strFilter !="" && address2.ToString().find(strFilter) == string::npos &&
strAddr.find(strFilter) == string::npos) continue;
obj.push_back(Pair(strAddr, address2.ToString().c_str()));
strVin.find(strFilter) == string::npos) continue;
obj.push_back(Pair(strVin, address2.ToString().c_str()));
} else if (strMode == "pose") {
if(strFilter !="" && strAddr.find(strFilter) == string::npos) continue;
if(strFilter !="" && strVin.find(strFilter) == string::npos) continue;
std::string strOut = boost::lexical_cast<std::string>(mn.nScanningErrorCount);
obj.push_back(Pair(strAddr, strOut.c_str()));
obj.push_back(Pair(strVin, strOut.c_str()));
} else if(strMode == "status") {
std::string strStatus = mn.Status();
if(strFilter !="" && strAddr.find(strFilter) == string::npos && strStatus.find(strFilter) == string::npos) continue;
obj.push_back(Pair(strAddr, strStatus.c_str()));
} else if (strMode == "vin") {
if(strFilter !="" && strVin.find(strFilter) == string::npos && strStatus.find(strFilter) == string::npos) continue;
obj.push_back(Pair(strVin, strStatus.c_str()));
} else if (strMode == "addr") {
if(strFilter !="" && mn.vin.prevout.hash.ToString().find(strFilter) == string::npos &&
strAddr.find(strFilter) == string::npos) continue;
obj.push_back(Pair(strAddr, mn.vin.prevout.hash.ToString().c_str()));
strVin.find(strFilter) == string::npos) continue;
obj.push_back(Pair(strVin, mn.addr.ToString().c_str()));
} else if(strMode == "votes"){
std::string strStatus = "ABSTAIN";
@ -849,8 +851,12 @@ Value masternodelist(const Array& params, bool fHelp)
if(mn.nVote == 1) strStatus = "YEA";
}
if(strFilter !="" && (strAddr.find(strFilter) == string::npos && strStatus.find(strFilter) == string::npos)) continue;
obj.push_back(Pair(strAddr, strStatus.c_str()));
if(strFilter !="" && (strVin.find(strFilter) == string::npos && strStatus.find(strFilter) == string::npos)) continue;
obj.push_back(Pair(strVin, strStatus.c_str()));
} else if(strMode == "lastpaid"){
if(strFilter !="" && mn.vin.prevout.hash.ToString().find(strFilter) == string::npos &&
strVin.find(strFilter) == string::npos) continue;
obj.push_back(Pair(strVin, (int64_t)mn.nLastPaid));
}
}
}