Version 26 / New masternode consensus system

- Consensus system selects 1/10 of the oldest masternodes by payment, then selects payee by score from those. This fixes various race conditions when blocks are close together or inconsistant historical winner lists.
- Ask for up to 2 cycles of history
- Keep up to 5 cycles of history locally
This commit is contained in:
Evan Duffield 2015-07-21 20:07:23 -07:00
parent cbe2bae130
commit 388f22c576
8 changed files with 51 additions and 21 deletions

View File

@ -3,7 +3,7 @@ AC_PREREQ([2.60])
define(_CLIENT_VERSION_MAJOR, 0) define(_CLIENT_VERSION_MAJOR, 0)
define(_CLIENT_VERSION_MINOR, 12) define(_CLIENT_VERSION_MINOR, 12)
define(_CLIENT_VERSION_REVISION, 0) define(_CLIENT_VERSION_REVISION, 0)
define(_CLIENT_VERSION_BUILD, 25) define(_CLIENT_VERSION_BUILD, 26)
define(_CLIENT_VERSION_IS_RELEASE, true) define(_CLIENT_VERSION_IS_RELEASE, true)
define(_COPYRIGHT_YEAR, 2015) define(_COPYRIGHT_YEAR, 2015)
AC_INIT([Dash Core],[_CLIENT_VERSION_MAJOR._CLIENT_VERSION_MINOR._CLIENT_VERSION_REVISION],[info@dashpay.io],[dash]) AC_INIT([Dash Core],[_CLIENT_VERSION_MAJOR._CLIENT_VERSION_MINOR._CLIENT_VERSION_REVISION],[info@dashpay.io],[dash])

View File

@ -17,7 +17,7 @@
#define CLIENT_VERSION_MAJOR 0 #define CLIENT_VERSION_MAJOR 0
#define CLIENT_VERSION_MINOR 12 #define CLIENT_VERSION_MINOR 12
#define CLIENT_VERSION_REVISION 0 #define CLIENT_VERSION_REVISION 0
#define CLIENT_VERSION_BUILD 25 #define CLIENT_VERSION_BUILD 26
//! Set to true for release, false for prerelease or test build //! Set to true for release, false for prerelease or test build
#define CLIENT_VERSION_IS_RELEASE true #define CLIENT_VERSION_IS_RELEASE true

View File

@ -27,7 +27,7 @@ class CConsensusVote;
class CTransaction; class CTransaction;
class CTransactionLock; class CTransactionLock;
static const int MIN_INSTANTX_PROTO_VERSION = 70093; static const int MIN_INSTANTX_PROTO_VERSION = 70094;
extern map<uint256, CTransaction> mapTxLockReq; extern map<uint256, CTransaction> mapTxLockReq;
extern map<uint256, CTransaction> mapTxLockReqRejected; extern map<uint256, CTransaction> mapTxLockReqRejected;

View File

@ -365,7 +365,7 @@ void CMasternodePayments::ProcessMessageMasternodePayments(CNode* pfrom, std::st
return; return;
} }
int nFirstBlock = (masternodeSync.IsSynced() ? (chainActive.Tip()->nHeight - (mnodeman.CountEnabled()*1.1)) : chainActive.Tip()->nHeight - 10); int nFirstBlock = chainActive.Tip()->nHeight - (mnodeman.CountEnabled()*2);
if(winner.nBlockHeight < nFirstBlock || winner.nBlockHeight > chainActive.Tip()->nHeight+20){ if(winner.nBlockHeight < nFirstBlock || winner.nBlockHeight > chainActive.Tip()->nHeight+20){
LogPrintf("mnw - winner out of range - FirstBlock %d Height %d bestHeight %d\n", nFirstBlock, winner.nBlockHeight, chainActive.Tip()->nHeight); LogPrintf("mnw - winner out of range - FirstBlock %d Height %d bestHeight %d\n", nFirstBlock, winner.nBlockHeight, chainActive.Tip()->nHeight);
return; return;
@ -427,6 +427,8 @@ bool CMasternodePayments::GetBlockPayee(int nBlockHeight, CScript& payee)
return false; return false;
} }
// Is this masternode scheduled to get paid soon?
// -- Only look ahead up to 7 blocks to allow for propagation
bool CMasternodePayments::IsScheduled(CMasternode& mn, int nNotBlockHeight) bool CMasternodePayments::IsScheduled(CMasternode& mn, int nNotBlockHeight)
{ {
CBlockIndex* pindexPrev = chainActive.Tip(); CBlockIndex* pindexPrev = chainActive.Tip();
@ -436,7 +438,7 @@ bool CMasternodePayments::IsScheduled(CMasternode& mn, int nNotBlockHeight)
mnpayee = GetScriptForDestination(mn.pubkey.GetID()); mnpayee = GetScriptForDestination(mn.pubkey.GetID());
CScript payee; CScript payee;
for(int64_t h = pindexPrev->nHeight-1; h <= pindexPrev->nHeight+11; h++){ for(int64_t h = pindexPrev->nHeight; h <= pindexPrev->nHeight+7; h++){
if(h == nNotBlockHeight) continue; if(h == nNotBlockHeight) continue;
if(mapMasternodeBlocks.count(h)){ if(mapMasternodeBlocks.count(h)){
if(mapMasternodeBlocks[h].GetPayee(payee)){ if(mapMasternodeBlocks[h].GetPayee(payee)){
@ -564,7 +566,8 @@ void CMasternodePayments::CleanPaymentList()
if(chainActive.Tip() == NULL) return; if(chainActive.Tip() == NULL) return;
int nLimit = std::max(((int)mnodeman.size())*2, 1000); //keep up to five cycles for historical sake
int nLimit = std::max(((int)mnodeman.size())*5, 1000);
std::map<uint256, CMasternodePaymentWinner>::iterator it = mapMasternodePayeeVotes.begin(); std::map<uint256, CMasternodePaymentWinner>::iterator it = mapMasternodePayeeVotes.begin();
while(it != mapMasternodePayeeVotes.end()) { while(it != mapMasternodePayeeVotes.end()) {
@ -742,7 +745,7 @@ void CMasternodePayments::Sync(CNode* node, int nCountNeeded)
if(chainActive.Tip() == NULL) return; if(chainActive.Tip() == NULL) return;
int nCount = (mnodeman.CountEnabled()*1.1); int nCount = (mnodeman.CountEnabled()*2);
if(nCountNeeded > nCount) nCountNeeded = nCount; if(nCountNeeded > nCount) nCountNeeded = nCount;
std::map<uint256, CMasternodePaymentWinner>::iterator it = mapMasternodePayeeVotes.begin(); std::map<uint256, CMasternodePaymentWinner>::iterator it = mapMasternodePayeeVotes.begin();

View File

@ -174,7 +174,7 @@ void CMasternodeSync::Process()
CBlockIndex* pindexPrev = chainActive.Tip(); CBlockIndex* pindexPrev = chainActive.Tip();
if(pindexPrev == NULL) return; if(pindexPrev == NULL) return;
int nMnCount = mnodeman.CountEnabled()*1.1; int nMnCount = mnodeman.CountEnabled()*2;
int nCountNeeded = (pindexPrev->nHeight - masternodePayments.GetNewestBlock()); int nCountNeeded = (pindexPrev->nHeight - masternodePayments.GetNewestBlock());
int nHaveBlocks = (pindexPrev->nHeight - masternodePayments.GetOldestBlock()); int nHaveBlocks = (pindexPrev->nHeight - masternodePayments.GetOldestBlock());
if(nHaveBlocks < nMnCount || nCountNeeded > nMnCount) { if(nHaveBlocks < nMnCount || nCountNeeded > nMnCount) {

View File

@ -241,7 +241,7 @@ int64_t CMasternode::GetLastPaid() {
const CBlockIndex *BlockReading = chainActive.Tip(); const CBlockIndex *BlockReading = chainActive.Tip();
int nMnCount = mnodeman.CountEnabled()*1.1; int nMnCount = mnodeman.CountEnabled()*2;
int n = 0; int n = 0;
for (unsigned int i = 1; BlockReading && BlockReading->nHeight > 0; i++) { for (unsigned int i = 1; BlockReading && BlockReading->nHeight > 0; i++) {
if(n >= nMnCount){ if(n >= nMnCount){

View File

@ -29,6 +29,7 @@ struct CompareValueOnly
return t1.first < t2.first; return t1.first < t2.first;
} }
}; };
struct CompareValueOnlyMN struct CompareValueOnlyMN
{ {
bool operator()(const pair<int64_t, CMasternode>& t1, bool operator()(const pair<int64_t, CMasternode>& t1,
@ -384,11 +385,19 @@ CMasternode *CMasternodeMan::Find(const CPubKey &pubKeyMasternode)
return NULL; return NULL;
} }
//
// Deterministically select the oldest/best masternode to pay on the network
//
CMasternode* CMasternodeMan::GetNextMasternodeInQueueForPayment(int nBlockHeight) CMasternode* CMasternodeMan::GetNextMasternodeInQueueForPayment(int nBlockHeight)
{ {
LOCK(cs); LOCK(cs);
CMasternode *pOldestMasternode = NULL; CMasternode *pBestMasternode = NULL;
std::vector<pair<int64_t, CTxIn> > vecMasternodeLastPaid;
/*
Make a vector with all of the last paid times
*/
BOOST_FOREACH(CMasternode &mn, vMasternodes) BOOST_FOREACH(CMasternode &mn, vMasternodes)
{ {
@ -398,18 +407,37 @@ CMasternode* CMasternodeMan::GetNextMasternodeInQueueForPayment(int nBlockHeight
// //check protocol version // //check protocol version
if(mn.protocolVersion < masternodePayments.GetMinMasternodePaymentsProto()) continue; if(mn.protocolVersion < masternodePayments.GetMinMasternodePaymentsProto()) continue;
//it's in the list -- so let's skip it //it's in the list (up to 7 entries ahead of current block to allow propagation) -- so let's skip it
if(masternodePayments.IsScheduled(mn, nBlockHeight)) continue; if(masternodePayments.IsScheduled(mn, nBlockHeight)) continue;
//make sure it has as many confirmations as there are masternodes //make sure it has as many confirmations as there are masternodes
if(mn.GetMasternodeInputAge() < CountEnabled()) continue; if(mn.GetMasternodeInputAge() < CountEnabled()) continue;
if(pOldestMasternode == NULL || pOldestMasternode->SecondsSincePayment() < mn.SecondsSincePayment()){ vecMasternodeLastPaid.push_back(make_pair(mn.SecondsSincePayment(), mn.vin));
pOldestMasternode = &mn;
}
} }
return pOldestMasternode; // Sort them low to high
sort(vecMasternodeLastPaid.rbegin(), vecMasternodeLastPaid.rend(), CompareValueOnly());
// Look at 1/10 of the oldest nodes (by last payment), calculate their scores and pay the best one
// -- This doesn't look at who is being paid in the +7-10 blocks, allowing for double payments very rarely
// -- 1/100 payments should be a double payment on mainnet - (1/(3000/10))*3 --(chance per block * chances before IsScheduled will fire)
int nTenthNetwork = mnodeman.CountEnabled()/10;
int nCount = 0;
uint256 nHigh = 0;
BOOST_FOREACH (PAIRTYPE(int64_t, CTxIn)& s, vecMasternodeLastPaid){
CMasternode* pmn = mnodeman.Find(s.second);
if(!pmn) break;
uint256 n = pmn->CalculateScore(1, nBlockHeight-100);
if(n > nHigh){
nHigh = n;
pBestMasternode = pmn;
}
nCount++;
if(nCount >= nTenthNetwork) break;
}
return pBestMasternode;
} }
CMasternode *CMasternodeMan::FindRandom() CMasternode *CMasternodeMan::FindRandom()
@ -682,7 +710,6 @@ void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CData
} }
} }
int64_t askAgain = GetTime() + MASTERNODES_DSEG_SECONDS; int64_t askAgain = GetTime() + MASTERNODES_DSEG_SECONDS;
mAskedUsForMasternodeList[pfrom->addr] = askAgain; mAskedUsForMasternodeList[pfrom->addr] = askAgain;
} }
} //else, asking for a specific node which is ok } //else, asking for a specific node which is ok

View File

@ -10,7 +10,7 @@
* network protocol versioning * network protocol versioning
*/ */
static const int PROTOCOL_VERSION = 70093; static const int PROTOCOL_VERSION = 70094;
//! initial proto version, to be increased after version/verack negotiation //! initial proto version, to be increased after version/verack negotiation
static const int INIT_PROTO_VERSION = 209; static const int INIT_PROTO_VERSION = 209;
@ -22,19 +22,19 @@ static const int GETHEADERS_VERSION = 70077;
static const int MIN_PEER_PROTO_VERSION = 70066; static const int MIN_PEER_PROTO_VERSION = 70066;
//! minimum peer version accepted by DarksendPool //! minimum peer version accepted by DarksendPool
static const int MIN_POOL_PEER_PROTO_VERSION = 70093; static const int MIN_POOL_PEER_PROTO_VERSION = 70094;
//! minimum peer version for masternode budgets //! minimum peer version for masternode budgets
static const int MIN_BUDGET_PEER_PROTO_VERSION = 70093; static const int MIN_BUDGET_PEER_PROTO_VERSION = 70094;
//! minimum peer version for masternode winner broadcasts //! minimum peer version for masternode winner broadcasts
static const int MIN_MNW_PEER_PROTO_VERSION = 70093; static const int MIN_MNW_PEER_PROTO_VERSION = 70094;
//! minimum peer version that can receive masternode payments //! minimum peer version that can receive masternode payments
// V1 - Last protocol version before update // V1 - Last protocol version before update
// V2 - Newest protocol version // V2 - Newest protocol version
static const int MIN_MASTERNODE_PAYMENT_PROTO_VERSION_1 = 70066; static const int MIN_MASTERNODE_PAYMENT_PROTO_VERSION_1 = 70066;
static const int MIN_MASTERNODE_PAYMENT_PROTO_VERSION_2 = 70093; static const int MIN_MASTERNODE_PAYMENT_PROTO_VERSION_2 = 70094;
//! nTime field added to CAddress, starting with this version; //! nTime field added to CAddress, starting with this version;
//! if possible, avoid requesting addresses nodes older than this //! if possible, avoid requesting addresses nodes older than this