2015-03-18 00:06:58 +01:00
|
|
|
// Copyright (c) 2014-2015 The Dash developers
|
2015-02-24 15:02:22 +01:00
|
|
|
// Distributed under the MIT/X11 software license, see the accompanying
|
|
|
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
|
|
|
2014-12-09 02:17:57 +01:00
|
|
|
#include "masternode.h"
|
2015-02-23 21:01:21 +01:00
|
|
|
#include "masternodeman.h"
|
2014-12-09 02:17:57 +01:00
|
|
|
#include "darksend.h"
|
|
|
|
#include "util.h"
|
2015-03-22 04:26:48 +01:00
|
|
|
#include "sync.h"
|
2014-12-09 02:17:57 +01:00
|
|
|
#include "addrman.h"
|
|
|
|
#include <boost/lexical_cast.hpp>
|
|
|
|
|
|
|
|
// keep track of the scanning errors I've seen
|
|
|
|
map<uint256, int> mapSeenMasternodeScanningErrors;
|
2015-02-05 23:56:59 +01:00
|
|
|
// cache block hashes as we calculate them
|
|
|
|
std::map<int64_t, uint256> mapCacheBlockHashes;
|
2014-12-09 02:17:57 +01:00
|
|
|
|
|
|
|
|
|
|
|
struct CompareValueOnly
|
|
|
|
{
|
|
|
|
bool operator()(const pair<int64_t, CTxIn>& t1,
|
|
|
|
const pair<int64_t, CTxIn>& t2) const
|
|
|
|
{
|
|
|
|
return t1.first < t2.first;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2015-02-05 23:56:59 +01:00
|
|
|
//Get the last hash that matches the modulus given. Processed in reverse order
|
|
|
|
bool GetBlockHash(uint256& hash, int nBlockHeight)
|
|
|
|
{
|
2015-02-13 15:55:08 +01:00
|
|
|
if (chainActive.Tip() == NULL) return false;
|
|
|
|
|
|
|
|
if(nBlockHeight == 0)
|
|
|
|
nBlockHeight = chainActive.Tip()->nHeight;
|
|
|
|
|
2015-02-05 23:56:59 +01:00
|
|
|
if(mapCacheBlockHashes.count(nBlockHeight)){
|
|
|
|
hash = mapCacheBlockHashes[nBlockHeight];
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
const CBlockIndex *BlockLastSolved = chainActive.Tip();
|
|
|
|
const CBlockIndex *BlockReading = chainActive.Tip();
|
|
|
|
|
|
|
|
if (BlockLastSolved == NULL || BlockLastSolved->nHeight == 0 || chainActive.Tip()->nHeight+1 < nBlockHeight) return false;
|
|
|
|
|
|
|
|
int nBlocksAgo = 0;
|
|
|
|
if(nBlockHeight > 0) nBlocksAgo = (chainActive.Tip()->nHeight+1)-nBlockHeight;
|
|
|
|
assert(nBlocksAgo >= 0);
|
|
|
|
|
|
|
|
int n = 0;
|
|
|
|
for (unsigned int i = 1; BlockReading && BlockReading->nHeight > 0; i++) {
|
|
|
|
if(n >= nBlocksAgo){
|
|
|
|
hash = BlockReading->GetBlockHash();
|
2015-02-09 21:36:45 +01:00
|
|
|
mapCacheBlockHashes[nBlockHeight] = hash;
|
2015-02-05 23:56:59 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
n++;
|
|
|
|
|
|
|
|
if (BlockReading->pprev == NULL) { assert(BlockReading); break; }
|
|
|
|
BlockReading = BlockReading->pprev;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-02-23 21:01:21 +01:00
|
|
|
CMasternode::CMasternode()
|
|
|
|
{
|
|
|
|
LOCK(cs);
|
|
|
|
vin = CTxIn();
|
|
|
|
addr = CService();
|
|
|
|
pubkey = CPubKey();
|
|
|
|
pubkey2 = CPubKey();
|
|
|
|
sig = std::vector<unsigned char>();
|
|
|
|
activeState = MASTERNODE_ENABLED;
|
2015-03-01 16:38:53 +01:00
|
|
|
sigTime = GetAdjustedTime();
|
2015-02-23 21:01:21 +01:00
|
|
|
lastDseep = 0;
|
|
|
|
lastTimeSeen = 0;
|
|
|
|
cacheInputAge = 0;
|
|
|
|
cacheInputAgeBlock = 0;
|
|
|
|
unitTest = false;
|
|
|
|
allowFreeTx = true;
|
|
|
|
protocolVersion = MIN_PEER_PROTO_VERSION;
|
|
|
|
nLastDsq = 0;
|
2015-03-16 20:01:11 +01:00
|
|
|
donationAddress = CScript();
|
|
|
|
donationPercentage = 0;
|
2015-03-20 19:24:11 +01:00
|
|
|
nVote = 0;
|
|
|
|
lastVote = 0;
|
2015-03-24 02:52:27 +01:00
|
|
|
nScanningErrorCount = 0;
|
|
|
|
nLastScanningErrorBlockHeight = 0;
|
2015-04-16 16:08:06 +02:00
|
|
|
|
|
|
|
//mark last paid as current for new entries
|
|
|
|
nLastPaid = GetAdjustedTime();
|
2015-02-23 21:01:21 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
CMasternode::CMasternode(const CMasternode& other)
|
|
|
|
{
|
|
|
|
LOCK(cs);
|
|
|
|
vin = other.vin;
|
|
|
|
addr = other.addr;
|
|
|
|
pubkey = other.pubkey;
|
|
|
|
pubkey2 = other.pubkey2;
|
|
|
|
sig = other.sig;
|
|
|
|
activeState = other.activeState;
|
2015-03-01 16:38:53 +01:00
|
|
|
sigTime = other.sigTime;
|
2015-02-23 21:01:21 +01:00
|
|
|
lastDseep = other.lastDseep;
|
|
|
|
lastTimeSeen = other.lastTimeSeen;
|
|
|
|
cacheInputAge = other.cacheInputAge;
|
|
|
|
cacheInputAgeBlock = other.cacheInputAgeBlock;
|
|
|
|
unitTest = other.unitTest;
|
|
|
|
allowFreeTx = other.allowFreeTx;
|
|
|
|
protocolVersion = other.protocolVersion;
|
|
|
|
nLastDsq = other.nLastDsq;
|
2015-03-16 20:01:11 +01:00
|
|
|
donationAddress = other.donationAddress;
|
|
|
|
donationPercentage = other.donationPercentage;
|
2015-03-20 19:24:11 +01:00
|
|
|
nVote = other.nVote;
|
|
|
|
lastVote = other.lastVote;
|
2015-03-24 02:52:27 +01:00
|
|
|
nScanningErrorCount = other.nScanningErrorCount;
|
|
|
|
nLastScanningErrorBlockHeight = other.nLastScanningErrorBlockHeight;
|
2015-04-16 16:08:06 +02:00
|
|
|
nLastPaid = other.nLastPaid;
|
2015-02-23 21:01:21 +01:00
|
|
|
}
|
|
|
|
|
2015-03-16 20:01:11 +01:00
|
|
|
CMasternode::CMasternode(CService newAddr, CTxIn newVin, CPubKey newPubkey, std::vector<unsigned char> newSig, int64_t newSigTime, CPubKey newPubkey2, int protocolVersionIn, CScript newDonationAddress, int newDonationPercentage)
|
2015-02-23 21:01:21 +01:00
|
|
|
{
|
|
|
|
LOCK(cs);
|
|
|
|
vin = newVin;
|
|
|
|
addr = newAddr;
|
|
|
|
pubkey = newPubkey;
|
|
|
|
pubkey2 = newPubkey2;
|
|
|
|
sig = newSig;
|
|
|
|
activeState = MASTERNODE_ENABLED;
|
2015-03-01 16:38:53 +01:00
|
|
|
sigTime = newSigTime;
|
2015-02-23 21:01:21 +01:00
|
|
|
lastDseep = 0;
|
|
|
|
lastTimeSeen = 0;
|
|
|
|
cacheInputAge = 0;
|
|
|
|
cacheInputAgeBlock = 0;
|
|
|
|
unitTest = false;
|
|
|
|
allowFreeTx = true;
|
|
|
|
protocolVersion = protocolVersionIn;
|
|
|
|
nLastDsq = 0;
|
2015-03-16 20:01:11 +01:00
|
|
|
donationAddress = newDonationAddress;
|
|
|
|
donationPercentage = newDonationPercentage;
|
2015-03-21 04:34:36 +01:00
|
|
|
nVote = 0;
|
|
|
|
lastVote = 0;
|
2015-03-24 02:52:27 +01:00
|
|
|
nScanningErrorCount = 0;
|
|
|
|
nLastScanningErrorBlockHeight = 0;
|
2015-04-16 16:08:06 +02:00
|
|
|
nLastPaid = GetAdjustedTime();
|
2015-02-23 21:01:21 +01:00
|
|
|
}
|
|
|
|
|
2014-12-09 02:17:57 +01:00
|
|
|
//
|
2015-03-05 09:11:56 +01:00
|
|
|
// Deterministically calculate a given "score" for a Masternode depending on how close it's hash is to
|
2014-12-09 02:17:57 +01:00
|
|
|
// the proof of work for that block. The further away they are the better, the furthest will win the election
|
|
|
|
// and get paid this block
|
|
|
|
//
|
2015-02-23 21:01:21 +01:00
|
|
|
uint256 CMasternode::CalculateScore(int mod, int64_t nBlockHeight)
|
2014-12-09 02:17:57 +01:00
|
|
|
{
|
|
|
|
if(chainActive.Tip() == NULL) return 0;
|
|
|
|
|
|
|
|
uint256 hash = 0;
|
2015-02-07 20:35:33 +01:00
|
|
|
uint256 aux = vin.prevout.hash + vin.prevout.n;
|
2015-02-05 23:56:59 +01:00
|
|
|
|
|
|
|
if(!GetBlockHash(hash, nBlockHeight)) return 0;
|
2015-02-07 19:31:15 +01:00
|
|
|
|
2015-02-09 05:57:50 +01:00
|
|
|
uint256 hash2 = Hash(BEGIN(hash), END(hash));
|
2015-03-23 18:28:36 +01:00
|
|
|
uint256 hash3 = Hash(BEGIN(hash), END(hash), BEGIN(aux), END(aux));
|
2015-02-07 19:31:15 +01:00
|
|
|
|
|
|
|
uint256 r = (hash3 > hash2 ? hash3 - hash2 : hash2 - hash3);
|
|
|
|
|
|
|
|
return r;
|
2014-12-09 02:17:57 +01:00
|
|
|
}
|
|
|
|
|
2015-02-23 21:01:21 +01:00
|
|
|
void CMasternode::Check()
|
2014-12-09 02:17:57 +01:00
|
|
|
{
|
2015-03-22 04:26:48 +01:00
|
|
|
//TODO: Random segfault with this line removed
|
|
|
|
TRY_LOCK(cs_main, lockRecv);
|
|
|
|
if(!lockRecv) return;
|
2015-03-06 23:17:51 +01:00
|
|
|
|
2015-03-22 04:10:34 +01:00
|
|
|
if(nScanningErrorCount >= MASTERNODE_SCANNING_ERROR_THESHOLD)
|
2015-03-13 10:28:20 +01:00
|
|
|
{
|
|
|
|
activeState = MASTERNODE_POS_ERROR;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-12-09 02:17:57 +01:00
|
|
|
//once spent, stop doing the checks
|
2015-02-23 21:01:21 +01:00
|
|
|
if(activeState == MASTERNODE_VIN_SPENT) return;
|
2014-12-09 02:17:57 +01:00
|
|
|
|
|
|
|
|
|
|
|
if(!UpdatedWithin(MASTERNODE_REMOVAL_SECONDS)){
|
2015-02-23 21:01:21 +01:00
|
|
|
activeState = MASTERNODE_REMOVE;
|
2014-12-09 02:17:57 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!UpdatedWithin(MASTERNODE_EXPIRATION_SECONDS)){
|
2015-02-23 21:01:21 +01:00
|
|
|
activeState = MASTERNODE_EXPIRED;
|
2014-12-09 02:17:57 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!unitTest){
|
|
|
|
CValidationState state;
|
2015-04-03 00:51:08 +02:00
|
|
|
CMutableTransaction tx = CMutableTransaction();
|
2014-12-09 02:17:57 +01:00
|
|
|
CTxOut vout = CTxOut(999.99*COIN, darkSendPool.collateralPubKey);
|
|
|
|
tx.vin.push_back(vin);
|
|
|
|
tx.vout.push_back(vout);
|
|
|
|
|
2015-04-07 04:56:10 +02:00
|
|
|
if(!AcceptableInputs(mempool, state, CTransaction(tx), false, NULL)){
|
2015-02-23 21:01:21 +01:00
|
|
|
activeState = MASTERNODE_VIN_SPENT;
|
2014-12-09 02:17:57 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-23 21:01:21 +01:00
|
|
|
activeState = MASTERNODE_ENABLED; // OK
|
2015-04-16 21:58:09 +02:00
|
|
|
}
|