#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;
}
// ask wallets to resend their transactions
-void ResendWalletTransactions()
+void ResendWalletTransactions(bool fForceResend)
{
BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
- pwallet->ResendWalletTransactions();
+ pwallet->ResendWalletTransactions(fForceResend);
}
CTransaction::GetLegacySigOpCount() const
{
unsigned int nSigOps = 0;
- if (!IsCoinBase() || nTime < COINBASE_SIGOPS_SWITCH_TIME)
+ if (!IsCoinBase())
{
// Coinbase scriptsigs are never executed, so there is
// no sense in calculation of sigops.
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");
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 (!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);
}
while (pfork != plonger)
{
while (plonger->nHeight > pfork->nHeight)
- if (!(plonger = plonger->pprev))
+ if ((plonger = plonger->pprev) == NULL)
return error("Reorganize() : plonger->pprev is null");
if (pfork == plonger)
break;
- if (!(pfork = pfork->pprev))
+ if ((pfork = pfork->pprev) == NULL)
return error("Reorganize() : pfork->pprev is null");
}
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 * nOneHour; // 12 hours
+ if (fTestNet || pindexPrev->nTime < 1450569600)
+ nMaxOffset = 7 * nOneWeek; // 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 (mapOrphanBlocks.count(hash))
return error("ProcessBlock() : already have block (orphan) %s", hash.ToString().substr(0,20).c_str());
+ // Check that block isn't listed as unconditionally banned.
+ if (!Checkpoints::CheckBanned(hash)) {
+ if (pfrom)
+ pfrom->Misbehaving(100);
+ return error("ProcessBlock() : block %s is rejected by hard-coded banlist", hash.GetHex().substr(0,20).c_str());
+ }
+
// Check proof-of-stake
// Limited duplicity on stake: prevents block flood attack
// Duplicate stake allowed only when there is orphan child block
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;