aboutsummaryrefslogtreecommitdiff
path: root/src/main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.cpp')
-rw-r--r--src/main.cpp102
1 files changed, 70 insertions, 32 deletions
diff --git a/src/main.cpp b/src/main.cpp
index f6fce00e6..fe35fbaf2 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -45,6 +45,7 @@ int nScriptCheckThreads = 0;
bool fImporting = false;
bool fReindex = false;
bool fBenchmark = false;
+bool fTxIndex = false;
unsigned int nCoinCacheSize = 5000;
CMedianFilter<int> cPeerBlockCounts(8, 0); // Amount of blocks that other nodes claim to have
@@ -367,6 +368,9 @@ bool CTransaction::IsStandard() const
if (nVersion > CTransaction::CURRENT_VERSION)
return false;
+ if (!IsFinal())
+ return false;
+
BOOST_FOREACH(const CTxIn& txin, vin)
{
// Biggest 'standard' txin is a 3-signature 3-of-3 CHECKMULTISIG
@@ -629,7 +633,7 @@ void CTxMemPool::pruneSpent(const uint256 &hashTx, CCoins &coins)
}
}
-bool CTxMemPool::accept(CTransaction &tx, bool fCheckInputs,
+bool CTxMemPool::accept(CTransaction &tx, bool fCheckInputs, bool fLimitFree,
bool* pfMissingInputs)
{
if (pfMissingInputs)
@@ -735,7 +739,7 @@ bool CTxMemPool::accept(CTransaction &tx, bool fCheckInputs,
// Don't accept it if it can't get into a block
int64 txMinFee = tx.GetMinFee(1000, true, GMF_RELAY);
- if (nFees < txMinFee)
+ if (fLimitFree && nFees < txMinFee)
return error("CTxMemPool::accept() : not enough fees %s, %"PRI64d" < %"PRI64d,
hash.ToString().c_str(),
nFees, txMinFee);
@@ -743,25 +747,24 @@ bool CTxMemPool::accept(CTransaction &tx, bool fCheckInputs,
// Continuously rate-limit free transactions
// This mitigates 'penny-flooding' -- sending thousands of free transactions just to
// be annoying or make others' transactions take longer to confirm.
- if (nFees < MIN_RELAY_TX_FEE)
+ if (fLimitFree && nFees < MIN_RELAY_TX_FEE)
{
- static CCriticalSection cs;
static double dFreeCount;
static int64 nLastTime;
int64 nNow = GetTime();
- {
- // Use an exponentially decaying ~10-minute window:
- dFreeCount *= pow(1.0 - 1.0/600.0, (double)(nNow - nLastTime));
- nLastTime = nNow;
- // -limitfreerelay unit is thousand-bytes-per-minute
- // At default rate it would take over a month to fill 1GB
- if (dFreeCount > GetArg("-limitfreerelay", 15)*10*1000 && !IsFromMe(tx))
- return error("CTxMemPool::accept() : free transaction rejected by rate limiter");
- if (fDebug)
- printf("Rate limit dFreeCount: %g => %g\n", dFreeCount, dFreeCount+nSize);
- dFreeCount += nSize;
- }
+ LOCK(cs);
+
+ // Use an exponentially decaying ~10-minute window:
+ dFreeCount *= pow(1.0 - 1.0/600.0, (double)(nNow - nLastTime));
+ nLastTime = nNow;
+ // -limitfreerelay unit is thousand-bytes-per-minute
+ // At default rate it would take over a month to fill 1GB
+ if (dFreeCount >= GetArg("-limitfreerelay", 15)*10*1000)
+ return error("CTxMemPool::accept() : free transaction rejected by rate limiter");
+ if (fDebug)
+ printf("Rate limit dFreeCount: %g => %g\n", dFreeCount, dFreeCount+nSize);
+ dFreeCount += nSize;
}
// Check against previous transactions
@@ -795,9 +798,9 @@ bool CTxMemPool::accept(CTransaction &tx, bool fCheckInputs,
return true;
}
-bool CTransaction::AcceptToMemoryPool(bool fCheckInputs, bool* pfMissingInputs)
+bool CTransaction::AcceptToMemoryPool(bool fCheckInputs, bool fLimitFree, bool* pfMissingInputs)
{
- return mempool.accept(*this, fCheckInputs, pfMissingInputs);
+ return mempool.accept(*this, fCheckInputs, fLimitFree, pfMissingInputs);
}
bool CTxMemPool::addUnchecked(const uint256& hash, CTransaction &tx)
@@ -908,9 +911,9 @@ int CMerkleTx::GetBlocksToMaturity() const
}
-bool CMerkleTx::AcceptToMemoryPool(bool fCheckInputs)
+bool CMerkleTx::AcceptToMemoryPool(bool fCheckInputs, bool fLimitFree)
{
- return CTransaction::AcceptToMemoryPool(fCheckInputs);
+ return CTransaction::AcceptToMemoryPool(fCheckInputs, fLimitFree);
}
@@ -926,10 +929,10 @@ bool CWalletTx::AcceptWalletTransaction(bool fCheckInputs)
{
uint256 hash = tx.GetHash();
if (!mempool.exists(hash) && pcoinsTip->HaveCoins(hash))
- tx.AcceptToMemoryPool(fCheckInputs);
+ tx.AcceptToMemoryPool(fCheckInputs, false);
}
}
- return AcceptToMemoryPool(fCheckInputs);
+ return AcceptToMemoryPool(fCheckInputs, false);
}
return false;
}
@@ -950,6 +953,25 @@ bool GetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock
}
}
+ if (fTxIndex) {
+ CDiskTxPos postx;
+ if (pblocktree->ReadTxIndex(hash, postx)) {
+ CAutoFile file(OpenBlockFile(postx, true), SER_DISK, CLIENT_VERSION);
+ CBlockHeader header;
+ try {
+ file >> header;
+ fseek(file, postx.nTxOffset, SEEK_CUR);
+ file >> txOut;
+ } catch (std::exception &e) {
+ return error("%s() : deserialize or I/O error", __PRETTY_FUNCTION__);
+ }
+ hashBlock = header.GetHash();
+ if (txOut.GetHash() != hash)
+ return error("%s() : txid mismatch", __PRETTY_FUNCTION__);
+ return true;
+ }
+ }
+
if (fAllowSlow) { // use coin database to locate block that contains transaction, and scan it
int nHeight = -1;
{
@@ -1641,6 +1663,9 @@ bool CBlock::ConnectBlock(CBlockIndex* pindex, CCoinsViewCache &view, bool fJust
int64 nFees = 0;
int nInputs = 0;
unsigned int nSigOps = 0;
+ CDiskTxPos pos(pindex->GetBlockPos(), GetSizeOfCompactSize(vtx.size()));
+ std::vector<std::pair<uint256, CDiskTxPos> > vPos;
+ vPos.reserve(vtx.size());
for (unsigned int i=0; i<vtx.size(); i++)
{
@@ -1680,6 +1705,8 @@ bool CBlock::ConnectBlock(CBlockIndex* pindex, CCoinsViewCache &view, bool fJust
if (!tx.IsCoinBase())
blockundo.vtxundo.push_back(txundo);
+ vPos.push_back(std::make_pair(GetTxHash(i), pos));
+ pos.nTxOffset += ::GetSerializeSize(tx, SER_DISK, CLIENT_VERSION);
}
int64 nTime = GetTimeMicros() - nStart;
if (fBenchmark)
@@ -1719,6 +1746,9 @@ bool CBlock::ConnectBlock(CBlockIndex* pindex, CCoinsViewCache &view, bool fJust
return error("ConnectBlock() : WriteBlockIndex failed");
}
+ if (fTxIndex)
+ pblocktree->WriteTxIndex(vPos);
+
// add this block to the view's block chain
if (!view.SetBestBlock(pindex))
return false;
@@ -1839,7 +1869,7 @@ bool SetBestChain(CBlockIndex* pindexNew)
// Resurrect memory transactions that were in the disconnected branch
BOOST_FOREACH(CTransaction& tx, vResurrect)
- tx.AcceptToMemoryPool();
+ tx.AcceptToMemoryPool(true, false);
// Delete redundant memory transactions that are in the connected branch
BOOST_FOREACH(CTransaction& tx, vDelete) {
@@ -2548,6 +2578,10 @@ bool static LoadBlockIndexDB()
pblocktree->ReadReindexing(fReindexing);
fReindex |= fReindexing;
+ // Check whether we have a transaction index
+ pblocktree->ReadFlag("txindex", fTxIndex);
+ printf("LoadBlockIndex(): transaction index %s\n", fTxIndex ? "enabled" : "disabled");
+
// Load hashBestChain pointer to end of best chain
pindexBest = pcoinsTip->GetBestBlock();
if (pindexBest == NULL)
@@ -2576,7 +2610,7 @@ bool VerifyDB() {
// Verify blocks in the best chain
int nCheckLevel = GetArg("-checklevel", 3);
- int nCheckDepth = GetArg( "-checkblocks", 2500);
+ int nCheckDepth = GetArg( "-checkblocks", 288);
if (nCheckDepth == 0)
nCheckDepth = 1000000000; // suffices until the year 19000
if (nCheckDepth > nBestHeight)
@@ -2652,13 +2686,10 @@ bool LoadBlockIndex()
hashGenesisBlock = uint256("000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943");
}
- if (fReindex)
- return true;
-
//
// Load block index from databases
//
- if (!LoadBlockIndexDB())
+ if (!fReindex && !LoadBlockIndexDB())
return false;
//
@@ -2666,6 +2697,13 @@ bool LoadBlockIndex()
//
if (mapBlockIndex.empty())
{
+ fTxIndex = GetBoolArg("-txindex", false);
+ pblocktree->WriteFlag("txindex", fTxIndex);
+ printf("Initializing databases...\n");
+
+ if (fReindex)
+ return true;
+
// Genesis Block:
// CBlock(hash=000000000019d6, ver=1, hashPrevBlock=00000000000000, hashMerkleRoot=4a5e1e, nTime=1231006505, nBits=1d00ffff, nNonce=2083236893, vtx=1)
// CTransaction(hash=4a5e1e, ver=1, vin.size=1, vout.size=1, nLockTime=0)
@@ -3419,7 +3457,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
pfrom->AddInventoryKnown(inv);
bool fMissingInputs = false;
- if (tx.AcceptToMemoryPool(true, &fMissingInputs))
+ if (tx.AcceptToMemoryPool(true, true, &fMissingInputs))
{
RelayTransaction(tx, inv.hash, vMsg);
mapAlreadyAskedFor.erase(inv);
@@ -3440,7 +3478,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
CInv inv(MSG_TX, tx.GetHash());
bool fMissingInputs2 = false;
- if (tx.AcceptToMemoryPool(true, &fMissingInputs2))
+ if (tx.AcceptToMemoryPool(true, true, &fMissingInputs2))
{
printf(" accepted orphan tx %s\n", inv.hash.ToString().substr(0,10).c_str());
RelayTransaction(tx, inv.hash, vMsg);
@@ -3450,9 +3488,9 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
}
else if (!fMissingInputs2)
{
- // invalid orphan
+ // invalid or too-little-fee orphan
vEraseQueue.push_back(inv.hash);
- printf(" removed invalid orphan tx %s\n", inv.hash.ToString().substr(0,10).c_str());
+ printf(" removed orphan tx %s\n", inv.hash.ToString().substr(0,10).c_str());
}
}
}