// Copyright (c) 2011 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file license.txt or http://www.opensource.org/licenses/mit-license.php.
-
-#include <stdint.h>
-
#include "headers.h"
#include "checkpoints.h"
#include "db.h"
#include "net.h"
#include "init.h"
+#include <boost/algorithm/string/replace.hpp>
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
map<uint256, CBlockIndex*> mapBlockIndex;
uint256 hashGenesisBlock("0x000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f");
static CBigNum bnProofOfWorkLimit(~uint256(0) >> 32);
-const int nInitialBlockThreshold = 120; // Regard blocks up until N-threshold as "initial download"
CBlockIndex* pindexGenesisBlock = NULL;
int nBestHeight = -1;
CBigNum bnBestChainWork = 0;
CBigNum bnBestInvalidWork = 0;
uint256 hashBestChain = 0;
CBlockIndex* pindexBest = NULL;
-int64_t nTimeBestReceived = 0;
+int64 nTimeBestReceived = 0;
CMedianFilter<int> cPeerBlockCounts(5, 0); // Amount of blocks that other nodes claim to have
double dHashesPerSec;
-int64_t nHPSTimerStart;
+int64 nHPSTimerStart;
// Settings
int fGenerateBitcoins = false;
-int64_t nTransactionFee = 0;
+int64 nTransactionFee = 0;
int fLimitProcessors = false;
int nLimitProcessors = 1;
int fMinimizeToTray = true;
COutPoint prevout = vin[i].prevout;
assert(mapInputs.count(prevout.hash) > 0);
CTransaction& txPrev = mapInputs[prevout.hash].second;
+ assert(prevout.n < txPrev.vout.size());
vector<vector<unsigned char> > vSolutions;
txnouttype whichType;
return DoS(100, error("CTransaction::CheckTransaction() : size limits failed"));
// Check for negative or overflow output values
- int64_t nValueOut = 0;
+ int64 nValueOut = 0;
BOOST_FOREACH(const CTxOut& txout, vout)
{
if (txout.nValue < 0)
return DoS(100, error("AcceptToMemoryPool() : coinbase as individual tx"));
// To help v0.1.5 clients who would see it as a negative number
- if ((int64_t)nLockTime > std::numeric_limits<int>::max())
+ if ((int64)nLockTime > std::numeric_limits<int>::max())
return error("AcceptToMemoryPool() : not accepting nLockTime beyond 2038 yet");
// Rather not work on nonstandard transactions (unless -testnet)
return error("AcceptToMemoryPool() : nonstandard transaction input");
// Check against previous transactions
- int64_t nFees = 0;
+ int64 nFees = 0;
int nSigOps = 0;
if (!ConnectInputs(mapInputs, mapUnused, CDiskTxPos(1,1,1), pindexBest, nFees, false, false, nSigOps))
{
{
static CCriticalSection cs;
static double dFreeCount;
- static int64_t nLastTime;
- int64_t nNow = GetTime();
+ static int64 nLastTime;
+ int64 nNow = GetTime();
CRITICAL_BLOCK(cs)
{
return AcceptToMemoryPool(txdb, fCheckInputs, pfMissingInputs);
}
+uint64 nPooledTx = 0;
+
bool CTransaction::AddToMemoryPoolUnchecked()
{
+ printf("AcceptToMemoryPoolUnchecked(): size %lu\n", mapTransactions.size());
// Add to memory pool without checking anything. Don't call this directly,
// call AcceptToMemoryPool to properly check the transaction first.
CRITICAL_BLOCK(cs_mapTransactions)
for (int i = 0; i < vin.size(); i++)
mapNextTx[vin[i].prevout] = CInPoint(&mapTransactions[hash], i);
nTransactionsUpdated++;
+ ++nPooledTx;
}
return true;
}
mapNextTx.erase(txin.prevout);
mapTransactions.erase(GetHash());
nTransactionsUpdated++;
+ --nPooledTx;
}
return true;
}
return pblock->GetHash();
}
-int64_t static GetBlockValue(int nHeight, int64_t nFees)
+int64 static GetBlockValue(int nHeight, int64 nFees)
{
- int64_t nSubsidy = 50 * COIN;
+ int64 nSubsidy = 50 * COIN;
// Subsidy is cut in half every 4 years
nSubsidy >>= (nHeight / 210000);
return nSubsidy + nFees;
}
-static const int64_t nTargetTimespan = 14 * 24 * 60 * 60; // two weeks
-static const int64_t nTargetSpacing = 10 * 60;
-static const int64_t nInterval = nTargetTimespan / nTargetSpacing;
+static const int64 nTargetTimespan = 14 * 24 * 60 * 60; // two weeks
+static const int64 nTargetSpacing = 10 * 60;
+static const int64 nInterval = nTargetTimespan / nTargetSpacing;
//
// minimum amount of work that could possibly be required nTime after
// minimum work required was nBase
//
-unsigned int ComputeMinWork(unsigned int nBase, int64_t nTime)
+unsigned int ComputeMinWork(unsigned int nBase, int64 nTime)
{
CBigNum bnResult;
bnResult.SetCompact(nBase);
assert(pindexFirst);
// Limit adjustment step
- int64_t nActualTimespan = pindexLast->GetBlockTime() - pindexFirst->GetBlockTime();
+ int64 nActualTimespan = pindexLast->GetBlockTime() - pindexFirst->GetBlockTime();
printf(" nActualTimespan = %"PRI64d" before bounds\n", nActualTimespan);
if (nActualTimespan < nTargetTimespan/4)
nActualTimespan = nTargetTimespan/4;
bool IsInitialBlockDownload()
{
- if (pindexBest == NULL || nBestHeight < (Checkpoints::GetTotalBlocksEstimate()-nInitialBlockThreshold))
+ if (pindexBest == NULL || nBestHeight < Checkpoints::GetTotalBlocksEstimate())
return true;
- static int64_t nLastUpdate;
+ static int64 nLastUpdate;
static CBlockIndex* pindexLastBest;
if (pindexBest != pindexLastBest)
{
return error("FetchInputs() : %s ReadFromDisk prev tx %s failed", GetHash().ToString().substr(0,10).c_str(), prevout.hash.ToString().substr(0,10).c_str());
}
}
+
+ // Make sure all prevout.n's are valid:
+ for (int i = 0; i < vin.size(); i++)
+ {
+ const COutPoint prevout = vin[i].prevout;
+ const CTxIndex& txindex = inputsRet[prevout.hash].first;
+ const CTransaction& txPrev = inputsRet[prevout.hash].second;
+ if (prevout.n >= txPrev.vout.size() || prevout.n >= txindex.vSpent.size())
+ return DoS(100, error("FetchInputs() : %s prevout.n out of range %d %d %d prev tx %s\n%s", GetHash().ToString().substr(0,10).c_str(), prevout.n, txPrev.vout.size(), txindex.vSpent.size(), prevout.hash.ToString().substr(0,10).c_str(), txPrev.ToString().c_str()));
+ }
+
return true;
}
bool CTransaction::ConnectInputs(map<uint256, pair<CTxIndex, CTransaction> > inputs,
map<uint256, CTxIndex>& mapTestPool, CDiskTxPos posThisTx,
- CBlockIndex* pindexBlock, int64_t& nFees, bool fBlock, bool fMiner, int& nSigOpsRet, int64_t nMinFee)
+ CBlockIndex* pindexBlock, int64& nFees, bool fBlock, bool fMiner, int& nSigOpsRet, int64 nMinFee)
{
// Take over previous transactions' spent pointers
// fBlock is true when this is called from AcceptBlock when a new best-block is added to the blockchain
// ... both are false when called from CTransaction::AcceptToMemoryPool
if (!IsCoinBase())
{
- int64_t nValueIn = 0;
+ int64 nValueIn = 0;
for (int i = 0; i < vin.size(); i++)
{
COutPoint prevout = vin[i].prevout;
if (pindex->nBlockPos == txindex.pos.nBlockPos && pindex->nFile == txindex.pos.nFile)
return error("ConnectInputs() : tried to spend coinbase at depth %d", pindexBlock->nHeight - pindex->nHeight);
- // Skip ECDSA signature verification when connecting blocks (fBlock=true) during initial download
- // (before the last blockchain checkpoint). This is safe because block merkle hashes are
+ // Skip ECDSA signature verification when connecting blocks (fBlock=true)
+ // before the last blockchain checkpoint. This is safe because block merkle hashes are
// still computed and checked, and any change will be caught at the next checkpoint.
- if (!(fBlock && IsInitialBlockDownload()))
+ if (!(fBlock && (nBestHeight < Checkpoints::GetTotalBlocksEstimate())))
{
bool fStrictOpEval = true;
// This code should be removed when OP_EVAL has
// To avoid being on the short end of a block-chain split,
// interpret OP_EVAL as a NO_OP until blocks with timestamps
// after opevaltime:
- int64_t nEvalSwitchTime = GetArg("opevaltime", 1328054400); // Feb 1, 2012
+ int64 nEvalSwitchTime = GetArg("opevaltime", 1328054400); // Feb 1, 2012
fStrictOpEval = (pindexBlock->nTime >= nEvalSwitchTime);
}
// if !fBlock, then always be strict-- don't accept
return DoS(100, error("ConnectInputs() : %s value in < value out", GetHash().ToString().substr(0,10).c_str()));
// Tally transaction fees
- int64_t nTxFee = nValueIn - GetValueOut();
+ int64 nTxFee = nValueIn - GetValueOut();
if (nTxFee < 0)
return DoS(100, error("ConnectInputs() : %s nTxFee < 0", GetHash().ToString().substr(0,10).c_str()));
if (nTxFee < nMinFee)
// Take over previous transactions' spent pointers
CRITICAL_BLOCK(cs_mapTransactions)
{
- int64_t nValueIn = 0;
+ int64 nValueIn = 0;
for (int i = 0; i < vin.size(); i++)
{
// Get prev tx from single transactions in memory
unsigned int nTxPos = pindex->nBlockPos + ::GetSerializeSize(CBlock(), SER_DISK) - 1 + GetSizeOfCompactSize(vtx.size());
map<uint256, CTxIndex> mapQueuedChanges;
- int64_t nFees = 0;
+ int64 nFees = 0;
int nSigOps = 0;
BOOST_FOREACH(CTransaction& tx, vtx)
{
}
+static void
+runCommand(std::string strCommand)
+{
+ int nErr = ::system(strCommand.c_str());
+ if (nErr)
+ printf("runCommand error: system(%s) returned %d\n", strCommand.c_str(), nErr);
+}
+
bool CBlock::SetBestChain(CTxDB& txdb, CBlockIndex* pindexNew)
{
uint256 hash = GetHash();
}
// Update best block in wallet (so we can detect restored wallets)
- if (!IsInitialBlockDownload())
+ bool fIsInitialDownload = IsInitialBlockDownload();
+ if (!fIsInitialDownload)
{
const CBlockLocator locator(pindexNew);
::SetBestChain(locator);
nTransactionsUpdated++;
printf("SetBestChain: new best=%s height=%d work=%s\n", hashBestChain.ToString().substr(0,20).c_str(), nBestHeight, bnBestChainWork.ToString().c_str());
+ std::string strCmd = GetArg("-blocknotify", "");
+
+ if (!fIsInitialDownload && !strCmd.empty())
+ {
+ boost::replace_all(strCmd, "%s", hashBestChain.GetHex());
+ boost::thread t(runCommand, strCmd); // thread runs free
+ }
+
return true;
}
if (pcheckpoint && pblock->hashPrevBlock != hashBestChain)
{
// Extra checks to prevent "fill up memory by spamming with bogus blocks"
- int64_t deltaTime = pblock->GetBlockTime() - pcheckpoint->nTime;
+ int64 deltaTime = pblock->GetBlockTime() - pcheckpoint->nTime;
if (deltaTime < 0)
{
pfrom->Misbehaving(100);
-bool CheckDiskSpace(uint64_t nAdditionalBytes)
+bool CheckDiskSpace(uint64 nAdditionalBytes)
{
- uint64_t nFreeBytesAvailable = filesystem::space(GetDataDir()).available;
+ uint64 nFreeBytesAvailable = filesystem::space(GetDataDir()).available;
// Check for 15MB because database could create another 10MB log file at any time
- if (nFreeBytesAvailable < (uint64_t)15000000 + nAdditionalBytes)
+ if (nFreeBytesAvailable < (uint64)15000000 + nAdditionalBytes)
{
fShutdown = true;
string strMessage = _("Warning: Disk space is low ");
bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
{
- static map<unsigned int, vector<unsigned char> > mapReuseKey;
+ static map<CService, vector<unsigned char> > mapReuseKey;
RandAddSeedPerfmon();
if (fDebug) {
printf("%s ", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str());
return false;
}
- int64_t nTime;
+ int64 nTime;
CAddress addrMe;
CAddress addrFrom;
- uint64_t nNonce = 1;
+ uint64 nNonce = 1;
vRecv >> pfrom->nVersion >> pfrom->nServices >> nTime >> addrMe;
if (pfrom->nVersion == 10300)
pfrom->nVersion = 300;
pfrom->fClient = !(pfrom->nServices & NODE_NETWORK);
- AddTimeData(pfrom->addr.ip, nTime);
+ AddTimeData(pfrom->addr, nTime);
// Change version
if (pfrom->nVersion >= 209)
// Store the new addresses
CAddrDB addrDB;
addrDB.TxnBegin();
- int64_t nNow = GetAdjustedTime();
- int64_t nSince = nNow - 10 * 60;
+ int64 nNow = GetAdjustedTime();
+ int64 nSince = nNow - 10 * 60;
BOOST_FOREACH(CAddress& addr, vAddr)
{
if (fShutdown)
static uint256 hashSalt;
if (hashSalt == 0)
RAND_bytes((unsigned char*)&hashSalt, sizeof(hashSalt));
- uint256 hashRand = hashSalt ^ (((int64_t)addr.ip)<<32) ^ ((GetTime()+addr.ip)/(24*60*60));
+ int64 hashAddr = addr.GetHash();
+ uint256 hashRand = hashSalt ^ (hashAddr<<32) ^ ((GetTime()+hashAddr)/(24*60*60));
hashRand = Hash(BEGIN(hashRand), END(hashRand));
multimap<uint256, CNode*> mapMix;
BOOST_FOREACH(CNode* pnode, vNodes)
{
// Nodes rebroadcast an addr every 24 hours
pfrom->vAddrToSend.clear();
- int64_t nSince = GetAdjustedTime() - 3 * 60 * 60; // in the last 3 hours
+ int64 nSince = GetAdjustedTime() - 3 * 60 * 60; // in the last 3 hours
CRITICAL_BLOCK(cs_mapAddresses)
{
unsigned int nCount = 0;
/// we have a chance to check the order here
// Keep giving the same key to the same ip until they use it
- if (!mapReuseKey.count(pfrom->addr.ip))
- pwalletMain->GetKeyFromPool(mapReuseKey[pfrom->addr.ip], true);
+ if (!mapReuseKey.count(pfrom->addr))
+ pwalletMain->GetKeyFromPool(mapReuseKey[pfrom->addr], true);
// Send back approval of order and pubkey to use
CScript scriptPubKey;
- scriptPubKey << mapReuseKey[pfrom->addr.ip] << OP_CHECKSIG;
+ scriptPubKey << mapReuseKey[pfrom->addr] << OP_CHECKSIG;
pfrom->PushMessage("reply", hashReply, (int)0, scriptPubKey);
}
ResendWalletTransactions();
// Address refresh broadcast
- static int64_t nLastRebroadcast;
+ static int64 nLastRebroadcast;
if (GetTime() - nLastRebroadcast > 24 * 60 * 60)
{
nLastRebroadcast = GetTime();
}
// Clear out old addresses periodically so it's not too much work at once
- static int64_t nLastClear;
+ static int64 nLastClear;
if (nLastClear == 0)
nLastClear = GetTime();
if (GetTime() - nLastClear > 10 * 60 && vNodes.size() >= 3)
CRITICAL_BLOCK(cs_mapAddresses)
{
CAddrDB addrdb;
- int64_t nSince = GetAdjustedTime() - 14 * 24 * 60 * 60;
+ int64 nSince = GetAdjustedTime() - 14 * 24 * 60 * 60;
for (map<vector<unsigned char>, CAddress>::iterator mi = mapAddresses.begin();
mi != mapAddresses.end();)
{
// Message: getdata
//
vector<CInv> vGetData;
- int64_t nNow = GetTime() * 1000000;
+ int64 nNow = GetTime() * 1000000;
CTxDB txdb("r");
while (!pto->mapAskFor.empty() && (*pto->mapAskFor.begin()).first <= nNow)
{
};
+uint64 nLastBlockTx = 0;
+uint64 nLastBlockSize = 0;
+
CBlock* CreateNewBlock(CReserveKey& reservekey)
{
CBlockIndex* pindexPrev = pindexBest;
pblock->vtx.push_back(txNew);
// Collect memory pool transactions into the block
- int64_t nFees = 0;
+ int64 nFees = 0;
CRITICAL_BLOCK(cs_main)
CRITICAL_BLOCK(cs_mapTransactions)
{
porphan->setDependsOn.insert(txin.prevout.hash);
continue;
}
- int64_t nValueIn = txPrev.vout[txin.prevout.n].nValue;
+ int64 nValueIn = txPrev.vout[txin.prevout.n].nValue;
// Read block header
int nConf = txindex.GetDepthInMainChain();
// Collect transactions into block
map<uint256, CTxIndex> mapTestPool;
- uint64_t nBlockSize = 1000;
+ uint64 nBlockSize = 1000;
+ uint64 nBlockTx = 0;
int nBlockSigOps = 100;
while (!mapPriority.empty())
{
// Transaction fee required depends on block size
bool fAllowFree = (nBlockSize + nTxSize < 4000 || CTransaction::AllowFree(dPriority));
- int64_t nMinFee = tx.GetMinFee(nBlockSize, fAllowFree, GMF_BLOCK);
+ int64 nMinFee = tx.GetMinFee(nBlockSize, fAllowFree, GMF_BLOCK);
// Connecting shouldn't fail due to dependency on other memory pool transactions
// because we're already processing them in order of dependency
pblock->vtx.push_back(tx);
nBlockSize += nTxSize;
nBlockSigOps += nTxSigOps;
+ ++nBlockTx;
// Add transactions that depend on this one to the priority queue
uint256 hash = tx.GetHash();
}
}
}
+
+ nLastBlockTx = nBlockTx;
+ nLastBlockSize = nBlockSize;
+ printf("CreateNewBlock(): total size %lu\n", nBlockSize);
+
}
pblock->vtx[0].vout[0].nValue = GetBlockValue(pindexPrev->nHeight+1, nFees);
//
// Search
//
- int64_t nStart = GetTime();
+ int64 nStart = GetTime();
uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
uint256 hashbuf[2];
uint256& hash = *alignup<16>(hashbuf);
}
// Meter hashes/sec
- static int64_t nHashCounter;
+ static int64 nHashCounter;
if (nHPSTimerStart == 0)
{
nHPSTimerStart = GetTimeMillis();
nHashCounter = 0;
string strStatus = strprintf(" %.0f khash/s", dHashesPerSec/1000.0);
UIThreadCall(boost::bind(CalledSetStatusBar, strStatus, 0));
- static int64_t nLogTime;
+ static int64 nLogTime;
if (GetTime() - nLogTime > 30 * 60)
{
nLogTime = GetTime();