#include "checkpoints.h"
#include "db.h"
#include "txdb.h"
-#include "net.h"
#include "init.h"
#include "ui_interface.h"
#include "checkqueue.h"
CBigNum bnProofOfWorkLimitTestNet(~uint256(0) >> 16);
-unsigned int nStakeMinAge = 60 * 60 * 24 * 30; // 30 days as zero time weight
-unsigned int nStakeMaxAge = 60 * 60 * 24 * 90; // 90 days as full weight
+unsigned int nStakeMinAge = 30 * nOneDay; // 30 days as zero time weight
+unsigned int nStakeMaxAge = 90 * nOneDay; // 90 days as full weight
unsigned int nStakeTargetSpacing = 10 * 60; // 10-minute stakes spacing
-unsigned int nModifierInterval = 6 * 60 * 60; // time to elapse before new modifier is computed
+unsigned int nModifierInterval = 6 * nOneHour; // time to elapse before new modifier is computed
int nCoinbaseMaturity = 500;
// Ping and address broadcast intervals
int64_t nPingInterval = 30 * 60;
-int64_t nBroadcastInterval = 24 * 60 * 60;
+int64_t nBroadcastInterval = nOneDay;
extern enum Checkpoints::CPMode CheckpointsMode;
{
if (!fConnect)
{
- // ppcoin: wallets need to refund inputs when disconnecting coinstake
+ // wallets need to refund inputs when disconnecting coinstake
if (tx.IsCoinStake())
{
BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
CTransaction::GetLegacySigOpCount() const
{
unsigned int nSigOps = 0;
- BOOST_FOREACH(const CTxIn& txin, vin)
+ if (!IsCoinBase())
{
- nSigOps += txin.scriptSig.GetSigOpCount(false);
+ // Coinbase scriptsigs are never executed, so there is
+ // no sense in calculation of sigops.
+ BOOST_FOREACH(const CTxIn& txin, vin)
+ {
+ nSigOps += txin.scriptSig.GetSigOpCount(false);
+ }
}
BOOST_FOREACH(const CTxOut& txout, vout)
{
if(IsCoinStake())
{
- // Enforce 0.01 as minimum fee for old approach or coinstake
+ // Enforce 0.01 as minimum fee for coinstake
nMinTxFee = CENT;
nMinRelayTxFee = CENT;
}
if (pfMissingInputs)
*pfMissingInputs = false;
+ // Time (prevent mempool memory exhaustion attack)
+ if (tx.nTime > FutureDrift(GetAdjustedTime()))
+ return tx.DoS(10, error("CTxMemPool::accept() : transaction timestamp is too far in the future"));
+
if (!tx.CheckTransaction())
return error("CTxMemPool::accept() : CheckTransaction failed");
{
int64_t nRewardCoinYear, nSubsidy, nSubsidyLimit = 10 * COIN;
- if(fTestNet || nTime > STAKE_SWITCH_TIME)
- {
- // Stage 2 of emission process is PoS-based. It will be active on mainNet since 20 Jun 2013.
+ // Stage 2 of emission process is mostly PoS-based.
- CBigNum bnRewardCoinYearLimit = MAX_MINT_PROOF_OF_STAKE; // Base stake mint rate, 100% year interest
- CBigNum bnTarget;
- bnTarget.SetCompact(nBits);
- CBigNum bnTargetLimit = GetProofOfStakeLimit(0, nTime);
- bnTargetLimit.SetCompact(bnTargetLimit.GetCompact());
+ CBigNum bnRewardCoinYearLimit = MAX_MINT_PROOF_OF_STAKE; // Base stake mint rate, 100% year interest
+ CBigNum bnTarget;
+ bnTarget.SetCompact(nBits);
+ CBigNum bnTargetLimit = GetProofOfStakeLimit(0, nTime);
+ bnTargetLimit.SetCompact(bnTargetLimit.GetCompact());
- // NovaCoin: A reasonably continuous curve is used to avoid shock to market
+ // A reasonably continuous curve is used to avoid shock to market
- CBigNum bnLowerBound = 1 * CENT, // Lower interest bound is 1% per year
- bnUpperBound = bnRewardCoinYearLimit, // Upper interest bound is 100% per year
- bnMidPart, bnRewardPart;
+ CBigNum bnLowerBound = 1 * CENT, // Lower interest bound is 1% per year
+ bnUpperBound = bnRewardCoinYearLimit, // Upper interest bound is 100% per year
+ bnMidPart, bnRewardPart;
- while (bnLowerBound + CENT <= bnUpperBound)
- {
- CBigNum bnMidValue = (bnLowerBound + bnUpperBound) / 2;
- if(!fTestNet && nTime < STAKECURVE_SWITCH_TIME)
- {
- //
- // Until 20 Oct 2013: reward for coin-year is cut in half every 64x multiply of PoS difficulty
- //
- // (nRewardCoinYearLimit / nRewardCoinYear) ** 6 == bnProofOfStakeLimit / bnTarget
- //
- // Human readable form: nRewardCoinYear = 1 / (posdiff ^ 1/6)
- //
-
- bnMidPart = bnMidValue * bnMidValue * bnMidValue * bnMidValue * bnMidValue * bnMidValue;
- bnRewardPart = bnRewardCoinYearLimit * bnRewardCoinYearLimit * bnRewardCoinYearLimit * bnRewardCoinYearLimit * bnRewardCoinYearLimit * bnRewardCoinYearLimit;
- }
- else
- {
- //
- // Since 20 Oct 2013: reward for coin-year is cut in half every 8x multiply of PoS difficulty
- //
- // (nRewardCoinYearLimit / nRewardCoinYear) ** 3 == bnProofOfStakeLimit / bnTarget
- //
- // Human readable form: nRewardCoinYear = 1 / (posdiff ^ 1/3)
- //
-
- bnMidPart = bnMidValue * bnMidValue * bnMidValue;
- bnRewardPart = bnRewardCoinYearLimit * bnRewardCoinYearLimit * bnRewardCoinYearLimit;
- }
+ while (bnLowerBound + CENT <= bnUpperBound)
+ {
+ CBigNum bnMidValue = (bnLowerBound + bnUpperBound) / 2;
- if (bnMidPart * bnTargetLimit > bnRewardPart * bnTarget)
- bnUpperBound = bnMidValue;
- else
- bnLowerBound = bnMidValue;
- }
+ //
+ // Reward for coin-year is cut in half every 8x multiply of PoS difficulty
+ //
+ // (nRewardCoinYearLimit / nRewardCoinYear) ** 3 == bnProofOfStakeLimit / bnTarget
+ //
+ // Human readable form: nRewardCoinYear = 1 / (posdiff ^ 1/3)
+ //
- nRewardCoinYear = bnUpperBound.getuint64();
- nRewardCoinYear = min((nRewardCoinYear / CENT) * CENT, MAX_MINT_PROOF_OF_STAKE);
- }
- else
- {
- // Old creation amount per coin-year, 5% fixed stake mint rate
- nRewardCoinYear = 5 * CENT;
+ bnMidPart = bnMidValue * bnMidValue * bnMidValue;
+ bnRewardPart = bnRewardCoinYearLimit * bnRewardCoinYearLimit * bnRewardCoinYearLimit;
+
+ if (bnMidPart * bnTargetLimit > bnRewardPart * bnTarget)
+ bnUpperBound = bnMidValue;
+ else
+ bnLowerBound = bnMidValue;
}
+ nRewardCoinYear = bnUpperBound.getuint64();
+ nRewardCoinYear = min((nRewardCoinYear / CENT) * CENT, MAX_MINT_PROOF_OF_STAKE);
+
if(bCoinYearOnly)
return nRewardCoinYear;
nSubsidy = nCoinAge * nRewardCoinYear * 33 / (365 * 33 + 8);
- // Set reasonable reward limit for large inputs since 20 Oct 2013
+ // Set reasonable reward limit for large inputs
//
// This will stimulate large holders to use smaller inputs, that's good for the network protection
- if(fTestNet || STAKECURVE_SWITCH_TIME < nTime)
- {
- if (fDebug && GetBoolArg("-printcreation") && nSubsidyLimit < nSubsidy)
- printf("GetProofOfStakeReward(): %s is greater than %s, coinstake reward will be truncated\n", FormatMoney(nSubsidy).c_str(), FormatMoney(nSubsidyLimit).c_str());
- nSubsidy = min(nSubsidy, nSubsidyLimit);
- }
+ if (fDebug && GetBoolArg("-printcreation") && nSubsidyLimit < nSubsidy)
+ printf("GetProofOfStakeReward(): %s is greater than %s, coinstake reward will be truncated\n", FormatMoney(nSubsidy).c_str(), FormatMoney(nSubsidyLimit).c_str());
+
+ nSubsidy = min(nSubsidy, nSubsidyLimit);
if (fDebug && GetBoolArg("-printcreation"))
printf("GetProofOfStakeReward(): create=%s nCoinAge=%" PRId64 " nBits=%d\n", FormatMoney(nSubsidy).c_str(), nCoinAge, nBits);
+
return nSubsidy;
}
-static const int64_t nTargetTimespan = 7 * 24 * 60 * 60; // one week
+static const int64_t nTargetTimespan = 7 * nOneDay; // one week
// get proof of work blocks max spacing according to hard-coded conditions
int64_t inline GetTargetSpacingWorkMax(int nHeight, unsigned int nTime)
{
// Maximum 200% adjustment per day...
bnResult *= 2;
- nTime -= 24 * 60 * 60;
+ nTime -= nOneDay;
}
if (bnResult > bnTargetLimit)
bnResult = bnTargetLimit;
unsigned int GetNextTargetRequired(const CBlockIndex* pindexLast, bool fProofOfStake)
{
- CBigNum bnTargetLimit = !fProofOfStake ? bnProofOfWorkLimit : GetProofOfStakeLimit(pindexLast->nHeight, pindexLast->nTime);
-
if (pindexLast == NULL)
- return bnTargetLimit.GetCompact(); // genesis block
+ return bnProofOfWorkLimit.GetCompact(); // genesis block
+
+ CBigNum bnTargetLimit = !fProofOfStake ? bnProofOfWorkLimit : GetProofOfStakeLimit(pindexLast->nHeight, pindexLast->nTime);
const CBlockIndex* pindexPrev = GetLastBlockIndex(pindexLast, fProofOfStake);
if (pindexPrev->pprev == NULL)
nLastUpdate = nCurrentTime;
}
return (nCurrentTime - nLastUpdate < 10 &&
- pindexBest->GetBlockTime() < nCurrentTime - 24 * 60 * 60);
+ pindexBest->GetBlockTime() < nCurrentTime - nOneDay);
}
void static InvalidChainFound(CBlockIndex* pindexNew)
if (IsCoinStake())
{
- // ppcoin: coin stake tx earns reward instead of paying fee
- uint64_t nCoinAge;
- if (!GetCoinAge(txdb, nCoinAge))
- return error("ConnectInputs() : %s unable to get coin age for coinstake", GetHash().ToString().substr(0,10).c_str());
+ if (nTime > Checkpoints::GetLastCheckpointTime())
+ {
+ unsigned int nTxSize = GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION);
- unsigned int nTxSize = (nTime > VALIDATION_SWITCH_TIME || fTestNet) ? GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION) : 0;
+ // coin stake tx earns reward instead of paying fee
+ uint64_t nCoinAge;
+ if (!GetCoinAge(txdb, nCoinAge))
+ return error("ConnectInputs() : %s unable to get coin age for coinstake", GetHash().ToString().substr(0,10).c_str());
- int64_t nReward = GetValueOut() - nValueIn;
- int64_t nCalculatedReward = GetProofOfStakeReward(nCoinAge, pindexBlock->nBits, nTime) - GetMinFee(1, false, GMF_BLOCK, nTxSize) + CENT;
+ int64_t nReward = GetValueOut() - nValueIn;
+ int64_t nCalculatedReward = GetProofOfStakeReward(nCoinAge, pindexBlock->nBits, nTime) - GetMinFee(1, false, GMF_BLOCK, nTxSize) + CENT;
- if (nReward > nCalculatedReward)
- return DoS(100, error("ConnectInputs() : coinstake pays too much(actual=%" PRId64 " vs calculated=%" PRId64 ")", nReward, nCalculatedReward));
+ if (nReward > nCalculatedReward)
+ return DoS(100, error("ConnectInputs() : coinstake pays too much(actual=%" PRId64 " vs calculated=%" PRId64 ")", nReward, nCalculatedReward));
+ }
}
else
{
if (!tx.IsCoinStake())
nFees += nTxValueIn - nTxValueOut;
+ unsigned int nFlags = SCRIPT_VERIFY_NOCACHE | SCRIPT_VERIFY_P2SH;
+
+ if (tx.nTime >= CHECKLOCKTIMEVERIFY_SWITCH_TIME) {
+ nFlags |= SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY;
+ // OP_CHECKSEQUENCEVERIFY is senseless without BIP68, so we're going disable it for now.
+ // nFlags |= SCRIPT_VERIFY_CHECKSEQUENCEVERIFY;
+ }
+
std::vector<CScriptCheck> vChecks;
- if (!tx.ConnectInputs(txdb, mapInputs, mapQueuedChanges, posThisTx, pindex, true, false, fScriptChecks, SCRIPT_VERIFY_NOCACHE | SCRIPT_VERIFY_P2SH, nScriptCheckThreads ? &vChecks : NULL))
+ if (!tx.ConnectInputs(txdb, mapInputs, mapQueuedChanges, posThisTx, pindex, true, false, fScriptChecks, nFlags, nScriptCheckThreads ? &vChecks : NULL))
return false;
control.Add(vChecks);
}
printf("coin age nValueIn=%" PRId64 " nTimeDiff=%d bnCentSecond=%s\n", nValueIn, nTime - txPrev.nTime, bnCentSecond.ToString().c_str());
}
- CBigNum bnCoinDay = bnCentSecond * CENT / COIN / (24 * 60 * 60);
+ CBigNum bnCoinDay = bnCentSecond * CENT / COIN / nOneDay;
if (fDebug && GetBoolArg("-printcoinage"))
printf("coin age bnCoinDay=%s\n", bnCoinDay.ToString().c_str());
nCoinAge = bnCoinDay.getuint64();
return error("AddToBlockIndex() : %s already exists", hash.ToString().substr(0,20).c_str());
// Construct new block index object
- CBlockIndex* pindexNew = new CBlockIndex(nFile, nBlockPos, *this);
+ CBlockIndex* pindexNew = new(nothrow) CBlockIndex(nFile, nBlockPos, *this);
if (!pindexNew)
return error("AddToBlockIndex() : new CBlockIndex failed");
pindexNew->phashBlock = &hash;
if (nBits != GetNextTargetRequired(pindexPrev, IsProofOfStake()))
return DoS(100, error("AcceptBlock() : incorrect %s", IsProofOfWork() ? "proof-of-work" : "proof-of-stake"));
+ int64_t nMedianTimePast = pindexPrev->GetMedianTimePast();
+ int nMaxOffset = 12 * 3600; // 12 hours
+ if (fTestNet || pindexPrev->nTime < 1450569600)
+ nMaxOffset = 7 * 86400; // One week (permanently on testNet or until 20 Dec, 2015 on mainNet)
+
// Check timestamp against prev
- if (GetBlockTime() <= pindexPrev->GetMedianTimePast() || FutureDrift(GetBlockTime()) < pindexPrev->GetBlockTime())
+ if (GetBlockTime() <= nMedianTimePast || FutureDrift(GetBlockTime()) < pindexPrev->GetBlockTime())
return error("AcceptBlock() : block's timestamp is too early");
+ // Don't accept blocks with future timestamps
+ if (pindexPrev->nHeight > 1 && nMedianTimePast + nMaxOffset < GetBlockTime())
+ return error("AcceptBlock() : block's timestamp is too far in the future");
+
// Check that all transactions are finalized
BOOST_FOREACH(const CTransaction& tx, vtx)
if (!tx.IsFinal(nHeight, GetBlockTime()))
if (bnTarget <= 0)
return 0;
- /* Old protocol */
- if (!fTestNet && GetBlockTime() < CHAINCHECKS_SWITCH_TIME)
- return (IsProofOfStake()? ((CBigNum(1)<<256) / (bnTarget+1)).getuint256() : 1);
-
- /* New protocol */
-
- // Calculate work amount for block
- uint256 nPoWTrust = (CBigNum(nPoWBase) / (bnTarget+1)).getuint256();
-
- // Set nPowTrust to 1 if we are checking PoS block or PoW difficulty is too low
- nPoWTrust = (IsProofOfStake() || nPoWTrust < 1) ? 1 : nPoWTrust;
-
- // Return nPoWTrust for the first 12 blocks
+ // Return 1 for the first 12 blocks
if (pprev == NULL || pprev->nHeight < 12)
- return nPoWTrust;
+ return 1;
const CBlockIndex* currentIndex = pprev;
}
else
{
+ // Calculate work amount for block
+ CBigNum bnPoWTrust = CBigNum(nPoWBase) / (bnTarget+1);
+
+ // Set nPowTrust to 1 if PoW difficulty is too low
+ if (bnPoWTrust < 1)
+ bnPoWTrust = 1;
+
CBigNum bnLastBlockTrust = CBigNum(pprev->nChainTrust - pprev->pprev->nChainTrust);
// Return nPoWTrust + 2/3 of previous block score if two parent blocks are not PoS blocks
if (!(pprev->IsProofOfStake() && pprev->pprev->IsProofOfStake()))
- return nPoWTrust + (2 * bnLastBlockTrust / 3).getuint256();
+ return (bnPoWTrust + 2 * bnLastBlockTrust / 3).getuint256();
int nPoSCount = 0;
// Return nPoWTrust + 2/3 of previous block score if less than 7 PoS blocks found
if (nPoSCount < 7)
- return nPoWTrust + (2 * bnLastBlockTrust / 3).getuint256();
+ return (bnPoWTrust + 2 * bnLastBlockTrust / 3).getuint256();
bnTarget.SetCompact(pprev->nBits);
CBigNum bnNewTrust = (CBigNum(1)<<256) / (bnTarget+1);
// Return nPoWTrust + full trust score for previous block nBits
- return nPoWTrust + bnNewTrust.getuint256();
+ return (bnPoWTrust + bnNewTrust).getuint256();
}
}
FILE* OpenBlockFile(unsigned int nFile, unsigned int nBlockPos, const char* pszMode)
{
- if ((nFile < 1) || (nFile == (unsigned int) -1))
+ if ((nFile < 1) || (nFile == std::numeric_limits<uint32_t>::max()))
return NULL;
FILE* file = fopen(BlockFilePath(nFile).string().c_str(), pszMode);
if (!file)
pchMessageStart[3] = 0xef;
bnProofOfWorkLimit = bnProofOfWorkLimitTestNet; // 16 bits PoW target limit for testnet
- nStakeMinAge = 2 * 60 * 60; // test net min age is 2 hours
+ nStakeMinAge = 2 * nOneHour; // test net min age is 2 hours
nModifierInterval = 20 * 60; // test modifier interval is 20 minutes
nCoinbaseMaturity = 10; // test maturity is 10 blocks
nStakeTargetSpacing = 5 * 60; // test block spacing is 5 minutes
try {
CAutoFile blkdat(fileIn, SER_DISK, CLIENT_VERSION);
unsigned int nPos = 0;
- while (nPos != (unsigned int)-1 && blkdat.good() && !fRequestShutdown)
+ while (nPos != std::numeric_limits<uint32_t>::max() && blkdat.good() && !fRequestShutdown)
{
unsigned char pchData[65536];
do {
int nRead = fread(pchData, 1, sizeof(pchData), blkdat);
if (nRead <= 8)
{
- nPos = (unsigned int)-1;
+ nPos = std::numeric_limits<uint32_t>::max();
break;
}
void* nFind = memchr(pchData, pchMessageStart[0], nRead+1-sizeof(pchMessageStart));
else
nPos += sizeof(pchData) - sizeof(pchMessageStart) + 1;
} while(!fRequestShutdown);
- if (nPos == (unsigned int)-1)
+ if (nPos == std::numeric_limits<uint32_t>::max())
break;
fseek(blkdat, nPos, SEEK_SET);
unsigned int nSize;
// if detected unmet upgrade requirement enter safe mode
// Note: Modifier upgrade requires blockchain redownload if past protocol switch
- if (IsFixedModifierInterval(nModifierUpgradeTime + 60*60*24)) // 1 day margin
+ if (IsFixedModifierInterval(nModifierUpgradeTime + nOneDay)) // 1 day margin
{
nPriority = 5000;
strStatusBar = strRPC = "WARNING: Blockchain redownload required approaching or past v.0.4.4.6u4 upgrade deadline.";
if (fShutdown)
return true;
if (addr.nTime <= 100000000 || addr.nTime > nNow + 10 * 60)
- addr.nTime = nNow - 5 * 24 * 60 * 60;
+ addr.nTime = nNow - 5 * nOneDay;
pfrom->AddAddressKnown(addr);
bool fReachable = IsReachable(addr);
if (addr.nTime > nSince && !pfrom->fGetAddr && vAddr.size() <= 10 && addr.IsRoutable())
if (hashSalt == 0)
hashSalt = GetRandHash();
uint64_t hashAddr = addr.GetHash();
- uint256 hashRand = hashSalt ^ (hashAddr<<32) ^ ((GetTime()+hashAddr)/(24*60*60));
+ uint256 hashRand = hashSalt ^ (hashAddr<<32) ^ ((GetTime()+hashAddr)/nOneDay);
hashRand = Hash(BEGIN(hashRand), END(hashRand));
multimap<uint256, CNode*> mapMix;
BOOST_FOREACH(CNode* pnode, vNodes)
if (fReachable)
vAddrOk.push_back(addr);
}
- addrman.Add(vAddrOk, pfrom->addr, 2 * 60 * 60);
+ addrman.Add(vAddrOk, pfrom->addr, 2 * nOneHour);
if (vAddr.size() < 1000)
pfrom->fGetAddr = false;
if (pfrom->fOneShot)
}
// find last block in inv vector
- unsigned int nLastBlock = (unsigned int)(-1);
+ unsigned int nLastBlock = std::numeric_limits<uint32_t>::max();
for (unsigned int nInv = 0; nInv < vInv.size(); nInv++) {
if (vInv[vInv.size() - 1 - nInv].type == MSG_BLOCK) {
nLastBlock = vInv.size() - 1 - nInv;
}
- else if (strCommand == "getaddr")
+ // This asymmetric behavior for inbound and outbound connections was introduced
+ // to prevent a fingerprinting attack: an attacker can send specific fake addresses
+ // to users' AddrMan and later request them by sending getaddr messages.
+ // Making users (which are behind NAT and can only make outgoing connections) ignore
+ // getaddr message mitigates the attack.
+ else if ((strCommand == "getaddr") && (pfrom->fInbound))
{
// Don't return addresses older than nCutOff timestamp
- int64_t nCutOff = GetTime() - (nNodeLifespan * 24 * 60 * 60);
+ int64_t nCutOff = GetTime() - (nNodeLifespan * nOneDay);
pfrom->vAddrToSend.clear();
vector<CAddress> vAddr = addrman.GetAddr();
BOOST_FOREACH(const CAddress &addr, vAddr)
if (!GetBoolArg("-allowreceivebyip"))
{
- pfrom->PushMessage("reply", hashReply, (int)2, string(""));
+ pfrom->PushMessage("reply", hashReply, 2, string(""));
return true;
}
// Send back approval of order and pubkey to use
CScript scriptPubKey;
scriptPubKey << mapReuseKey[pfrom->addr] << OP_CHECKSIG;
- pfrom->PushMessage("reply", hashReply, (int)0, scriptPubKey);
+ pfrom->PushMessage("reply", hashReply, 0, scriptPubKey);
}
else if (strCommand == "ping")
{
- if (pfrom->nVersion > BIP0031_VERSION)
- {
- uint64_t nonce = 0;
- vRecv >> nonce;
- // Echo the message back with the nonce. This allows for two useful features:
- //
- // 1) A remote node can quickly check if the connection is operational
- // 2) Remote nodes can measure the latency of the network thread. If this node
- // is overloaded it won't respond to pings quickly and the remote node can
- // avoid sending us more work, like chain download requests.
- //
- // The nonce stops the remote getting confused between different pings: without
- // it, if the remote node sends a ping once per second and this node takes 5
- // seconds to respond to each, the 5th ping the remote sends would appear to
- // return very quickly.
- pfrom->PushMessage("pong", nonce);
- }
+ uint64_t nonce = 0;
+ vRecv >> nonce;
+ // Echo the message back with the nonce. This allows for two useful features:
+ //
+ // 1) A remote node can quickly check if the connection is operational
+ // 2) Remote nodes can measure the latency of the network thread. If this node
+ // is overloaded it won't respond to pings quickly and the remote node can
+ // avoid sending us more work, like chain download requests.
+ //
+ // The nonce stops the remote getting confused between different pings: without
+ // it, if the remote node sends a ping once per second and this node takes 5
+ // seconds to respond to each, the 5th ping the remote sends would appear to
+ // return very quickly.
+ pfrom->PushMessage("pong", nonce);
}
// right now.
if (pto->nLastSend && GetTime() - pto->nLastSend > nPingInterval && pto->vSend.empty()) {
uint64_t nonce = 0;
- if (pto->nVersion > BIP0031_VERSION)
- pto->PushMessage("ping", nonce);
- else
- pto->PushMessage("ping");
+ pto->PushMessage("ping", nonce);
}
// Start block sync
// orphan transactions
}
-} instance_of_cmaincleanup;
\ No newline at end of file
+} instance_of_cmaincleanup;