Skip to content

Commit

Permalink
block index checking on load, extra redundant checks, misc refactoring
Browse files Browse the repository at this point in the history
git-svn-id: https://bitcoin.svn.sourceforge.net/svnroot/bitcoin/trunk@140 1a98c847-1fd6-4fd8-948a-caf3550aa51b
  • Loading branch information
non-github-bitcoin committed Aug 19, 2010
1 parent 44a0de1 commit 0545481
Show file tree
Hide file tree
Showing 5 changed files with 126 additions and 62 deletions.
11 changes: 8 additions & 3 deletions db.cpp
Expand Up @@ -419,6 +419,9 @@ bool CTxDB::LoadBlockIndex()
// Watch for genesis block // Watch for genesis block
if (pindexGenesisBlock == NULL && diskindex.GetBlockHash() == hashGenesisBlock) if (pindexGenesisBlock == NULL && diskindex.GetBlockHash() == hashGenesisBlock)
pindexGenesisBlock = pindexNew; pindexGenesisBlock = pindexNew;

if (!pindexNew->CheckIndex())
return error("LoadBlockIndex() : CheckIndex failed at %d", pindexNew->nHeight);
} }
else else
{ {
Expand Down Expand Up @@ -454,7 +457,7 @@ bool CTxDB::LoadBlockIndex()
pindexBest = mapBlockIndex[hashBestChain]; pindexBest = mapBlockIndex[hashBestChain];
nBestHeight = pindexBest->nHeight; nBestHeight = pindexBest->nHeight;
bnBestChainWork = pindexBest->bnChainWork; bnBestChainWork = pindexBest->bnChainWork;
printf("LoadBlockIndex(): hashBestChain=%s height=%d\n", hashBestChain.ToString().substr(0,16).c_str(), nBestHeight); printf("LoadBlockIndex(): hashBestChain=%s height=%d\n", hashBestChain.ToString().substr(0,20).c_str(), nBestHeight);


// Load bnBestInvalidWork, OK if it doesn't exist // Load bnBestInvalidWork, OK if it doesn't exist
ReadBestInvalidWork(bnBestInvalidWork); ReadBestInvalidWork(bnBestInvalidWork);
Expand All @@ -463,6 +466,8 @@ bool CTxDB::LoadBlockIndex()
CBlockIndex* pindexFork = NULL; CBlockIndex* pindexFork = NULL;
for (CBlockIndex* pindex = pindexBest; pindex && pindex->pprev; pindex = pindex->pprev) for (CBlockIndex* pindex = pindexBest; pindex && pindex->pprev; pindex = pindex->pprev)
{ {
if (pindex->nHeight < 74000 && !mapArgs.count("-checkblocks"))
break;
CBlock block; CBlock block;
if (!block.ReadFromDisk(pindex)) if (!block.ReadFromDisk(pindex))
return error("LoadBlockIndex() : block.ReadFromDisk failed"); return error("LoadBlockIndex() : block.ReadFromDisk failed");
Expand Down Expand Up @@ -629,8 +634,8 @@ bool CWalletDB::LoadWallet()
//printf("LoadWallet %s\n", wtx.GetHash().ToString().c_str()); //printf("LoadWallet %s\n", wtx.GetHash().ToString().c_str());
//printf(" %12I64d %s %s %s\n", //printf(" %12I64d %s %s %s\n",
// wtx.vout[0].nValue, // wtx.vout[0].nValue,
// DateTimeStrFormat("%x %H:%M:%S", wtx.nTime).c_str(), // DateTimeStrFormat("%x %H:%M:%S", wtx.GetBlockTime()).c_str(),
// wtx.hashBlock.ToString().substr(0,16).c_str(), // wtx.hashBlock.ToString().substr(0,20).c_str(),
// wtx.mapValue["message"].c_str()); // wtx.mapValue["message"].c_str());
} }
else if (strType == "key" || strType == "wkey") else if (strType == "key" || strType == "wkey")
Expand Down
98 changes: 62 additions & 36 deletions main.cpp
Expand Up @@ -500,8 +500,8 @@ bool CTransaction::AcceptTransaction(CTxDB& txdb, bool fCheckInputs, bool* pfMis
return error("AcceptTransaction() : CheckTransaction failed"); return error("AcceptTransaction() : CheckTransaction failed");


// To help v0.1.5 clients who would see it as a negative number // To help v0.1.5 clients who would see it as a negative number
if (nLockTime > INT_MAX) if ((int64)nLockTime > INT_MAX)
return error("AcceptTransaction() : not accepting nLockTime beyond 2038"); return error("AcceptTransaction() : not accepting nLockTime beyond 2038 yet");


// Do we already have it? // Do we already have it?
uint256 hash = GetHash(); uint256 hash = GetHash();
Expand All @@ -519,6 +519,9 @@ bool CTransaction::AcceptTransaction(CTxDB& txdb, bool fCheckInputs, bool* pfMis
COutPoint outpoint = vin[i].prevout; COutPoint outpoint = vin[i].prevout;
if (mapNextTx.count(outpoint)) if (mapNextTx.count(outpoint))
{ {
// Disable replacement feature for now

This comment has been minimized.

Copy link
@rebroad

rebroad Mar 3, 2016

Contributor

Was a reason given for this commit?

This comment has been minimized.

Copy link
@maflcko

maflcko Mar 3, 2016

Member

https://github.com/bitcoin/bips/blob/master/bip-0125.mediawiki#motivation

In that implementation, replacement transactions did not have to pay additional fees, so there was no direct incentive for miners to include the replacement and no built-in rate limiting that prevented overuse of relay node bandwidth. Nakamoto removed replacement from Bitcoin version 0.3.12, leaving only the comment, "Disable replacement feature for now".

return false;

// Allow replacing with a newer version of the same transaction // Allow replacing with a newer version of the same transaction
if (i != 0) if (i != 0)
return false; return false;
Expand Down Expand Up @@ -550,8 +553,8 @@ bool CTransaction::AcceptTransaction(CTxDB& txdb, bool fCheckInputs, bool* pfMis
{ {
if (ptxOld) if (ptxOld)
{ {
printf("mapTransaction.erase(%s) replacing with new version\n", ptxOld->GetHash().ToString().c_str()); printf("AcceptTransaction() : replacing tx %s with new version\n", ptxOld->GetHash().ToString().c_str());
mapTransactions.erase(ptxOld->GetHash()); ptxOld->RemoveFromMemoryPool();
} }
AddToMemoryPool(); AddToMemoryPool();
} }
Expand Down Expand Up @@ -748,6 +751,12 @@ void ResendWalletTransactions()
if (fFirst) if (fFirst)
return; return;


// Only do it if there's been a new block since last time
static int64 nLastTime;
if (nTimeBestReceived < nLastTime)
return;
nLastTime = GetTime();

// Rebroadcast any of our txes that aren't in a block yet // Rebroadcast any of our txes that aren't in a block yet
printf("ResendWalletTransactions()\n"); printf("ResendWalletTransactions()\n");
CTxDB txdb("r"); CTxDB txdb("r");
Expand Down Expand Up @@ -785,9 +794,13 @@ void ResendWalletTransactions()
// CBlock and CBlockIndex // CBlock and CBlockIndex
// //


bool CBlock::ReadFromDisk(const CBlockIndex* pblockindex, bool fReadTransactions) bool CBlock::ReadFromDisk(const CBlockIndex* pindex, bool fReadTransactions)
{ {
return ReadFromDisk(pblockindex->nFile, pblockindex->nBlockPos, fReadTransactions); if (!ReadFromDisk(pindex->nFile, pindex->nBlockPos, fReadTransactions))
return false;
if (GetHash() != pindex->GetBlockHash())
return error("CBlock::ReadFromDisk() : GetHash() doesn't match index");
return true;
} }


uint256 GetOrphanRoot(const CBlock* pblock) uint256 GetOrphanRoot(const CBlock* pblock)
Expand Down Expand Up @@ -829,7 +842,7 @@ unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast)
assert(pindexFirst); assert(pindexFirst);


// Limit adjustment step // Limit adjustment step
int64 nActualTimespan = (int64)pindexLast->nTime - (int64)pindexFirst->nTime; int64 nActualTimespan = pindexLast->GetBlockTime() - pindexFirst->GetBlockTime();
printf(" nActualTimespan = %"PRI64d" before bounds\n", nActualTimespan); printf(" nActualTimespan = %"PRI64d" before bounds\n", nActualTimespan);
if (nActualTimespan < nTargetTimespan/4) if (nActualTimespan < nTargetTimespan/4)
nActualTimespan = nTargetTimespan/4; nActualTimespan = nTargetTimespan/4;
Expand All @@ -854,6 +867,22 @@ unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast)
return bnNew.GetCompact(); return bnNew.GetCompact();
} }


bool CheckProofOfWork(uint256 hash, unsigned int nBits)
{
CBigNum bnTarget;
bnTarget.SetCompact(nBits);

// Check range
if (bnTarget <= 0 || bnTarget > bnProofOfWorkLimit)
return error("CheckProofOfWork() : nBits below minimum work");

// Check proof of work matches claimed amount
if (hash > bnTarget.getuint256())
return error("CheckProofOfWork() : hash doesn't match nBits");

return true;
}

bool IsInitialBlockDownload() bool IsInitialBlockDownload()
{ {
if (pindexBest == NULL) if (pindexBest == NULL)
Expand All @@ -866,7 +895,7 @@ bool IsInitialBlockDownload()
nLastUpdate = GetTime(); nLastUpdate = GetTime();
} }
return (GetTime() - nLastUpdate < 10 && return (GetTime() - nLastUpdate < 10 &&
pindexBest->nTime < GetTime() - 24 * 60 * 60); pindexBest->GetBlockTime() < GetTime() - 24 * 60 * 60);
} }


bool IsLockdown() bool IsLockdown()
Expand All @@ -884,8 +913,8 @@ void Lockdown(CBlockIndex* pindexNew)
CTxDB().WriteBestInvalidWork(bnBestInvalidWork); CTxDB().WriteBestInvalidWork(bnBestInvalidWork);
MainFrameRepaint(); MainFrameRepaint();
} }
printf("Lockdown: invalid block=%s height=%d work=%s\n", pindexNew->GetBlockHash().ToString().substr(0,22).c_str(), pindexNew->nHeight, pindexNew->bnChainWork.ToString().c_str()); printf("Lockdown: invalid block=%s height=%d work=%s\n", pindexNew->GetBlockHash().ToString().substr(0,20).c_str(), pindexNew->nHeight, pindexNew->bnChainWork.ToString().c_str());
printf("Lockdown: current best=%s height=%d work=%s\n", hashBestChain.ToString().substr(0,22).c_str(), nBestHeight, bnBestChainWork.ToString().c_str()); printf("Lockdown: current best=%s height=%d work=%s\n", hashBestChain.ToString().substr(0,20).c_str(), nBestHeight, bnBestChainWork.ToString().c_str());
printf("Lockdown: IsLockdown()=%d\n", (IsLockdown() ? 1 : 0)); printf("Lockdown: IsLockdown()=%d\n", (IsLockdown() ? 1 : 0));
if (IsLockdown()) if (IsLockdown())
printf("Lockdown: WARNING: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade.\n"); printf("Lockdown: WARNING: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade.\n");
Expand Down Expand Up @@ -1008,14 +1037,13 @@ bool CTransaction::ConnectInputs(CTxDB& txdb, map<uint256, CTxIndex>& mapTestPoo
nValueIn += txPrev.vout[prevout.n].nValue; nValueIn += txPrev.vout[prevout.n].nValue;


// Check for negative or overflow input values // Check for negative or overflow input values
if (txPrev.vout[prevout.n].nValue < 0) if (!MoneyRange(txPrev.vout[prevout.n].nValue) || !MoneyRange(nValueIn))
return error("ConnectInputs() : txin.nValue negative"); return error("ConnectInputs() : txin values out of range");
if (txPrev.vout[prevout.n].nValue > MAX_MONEY)
return error("ConnectInputs() : txin.nValue too high");
if (nValueIn > MAX_MONEY)
return error("ConnectInputs() : txin total too high");
} }


if (nValueIn < GetValueOut())
return error("ConnectInputs() : %s value in < value out", GetHash().ToString().substr(0,6).c_str());

// Tally transaction fees // Tally transaction fees
int64 nTxFee = nValueIn - GetValueOut(); int64 nTxFee = nValueIn - GetValueOut();
if (nTxFee < 0) if (nTxFee < 0)
Expand Down Expand Up @@ -1180,7 +1208,7 @@ bool Reorganize(CTxDB& txdb, CBlockIndex* pindexNew)
foreach(CBlockIndex* pindex, vDisconnect) foreach(CBlockIndex* pindex, vDisconnect)
{ {
CBlock block; CBlock block;
if (!block.ReadFromDisk(pindex->nFile, pindex->nBlockPos)) if (!block.ReadFromDisk(pindex))
return error("Reorganize() : ReadFromDisk for disconnect failed"); return error("Reorganize() : ReadFromDisk for disconnect failed");
if (!block.DisconnectBlock(txdb, pindex)) if (!block.DisconnectBlock(txdb, pindex))
return error("Reorganize() : DisconnectBlock failed"); return error("Reorganize() : DisconnectBlock failed");
Expand All @@ -1197,7 +1225,7 @@ bool Reorganize(CTxDB& txdb, CBlockIndex* pindexNew)
{ {
CBlockIndex* pindex = vConnect[i]; CBlockIndex* pindex = vConnect[i];
CBlock block; CBlock block;
if (!block.ReadFromDisk(pindex->nFile, pindex->nBlockPos)) if (!block.ReadFromDisk(pindex))
return error("Reorganize() : ReadFromDisk for connect failed"); return error("Reorganize() : ReadFromDisk for connect failed");
if (!block.ConnectBlock(txdb, pindex)) if (!block.ConnectBlock(txdb, pindex))
{ {
Expand Down Expand Up @@ -1283,7 +1311,7 @@ bool CBlock::SetBestChain(CTxDB& txdb, CBlockIndex* pindexNew)
bnBestChainWork = pindexNew->bnChainWork; bnBestChainWork = pindexNew->bnChainWork;
nTimeBestReceived = GetTime(); nTimeBestReceived = GetTime();
nTransactionsUpdated++; nTransactionsUpdated++;
printf("SetBestChain: new best=%s height=%d work=%s\n", hashBestChain.ToString().substr(0,22).c_str(), nBestHeight, bnBestChainWork.ToString().c_str()); printf("SetBestChain: new best=%s height=%d work=%s\n", hashBestChain.ToString().substr(0,20).c_str(), nBestHeight, bnBestChainWork.ToString().c_str());


return true; return true;
} }
Expand All @@ -1294,7 +1322,7 @@ bool CBlock::AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos)
// Check for duplicate // Check for duplicate
uint256 hash = GetHash(); uint256 hash = GetHash();
if (mapBlockIndex.count(hash)) if (mapBlockIndex.count(hash))
return error("AddToBlockIndex() : %s already exists", hash.ToString().substr(0,16).c_str()); return error("AddToBlockIndex() : %s already exists", hash.ToString().substr(0,20).c_str());


// Construct new block index object // Construct new block index object
CBlockIndex* pindexNew = new CBlockIndex(nFile, nBlockPos, *this); CBlockIndex* pindexNew = new CBlockIndex(nFile, nBlockPos, *this);
Expand Down Expand Up @@ -1346,7 +1374,7 @@ bool CBlock::CheckBlock() const
return error("CheckBlock() : size limits failed"); return error("CheckBlock() : size limits failed");


// Check timestamp // Check timestamp
if (nTime > GetAdjustedTime() + 2 * 60 * 60) if (GetBlockTime() > GetAdjustedTime() + 2 * 60 * 60)
return error("CheckBlock() : block timestamp too far in the future"); return error("CheckBlock() : block timestamp too far in the future");


// First transaction must be coinbase, the rest must not be // First transaction must be coinbase, the rest must not be
Expand All @@ -1362,10 +1390,8 @@ bool CBlock::CheckBlock() const
return error("CheckBlock() : CheckTransaction failed"); return error("CheckBlock() : CheckTransaction failed");


// Check proof of work matches claimed amount // Check proof of work matches claimed amount
if (CBigNum().SetCompact(nBits) > bnProofOfWorkLimit) if (!CheckProofOfWork(GetHash(), nBits))
return error("CheckBlock() : nBits below minimum work"); return error("CheckBlock() : proof of work failed");
if (GetHash() > CBigNum().SetCompact(nBits).getuint256())
return error("CheckBlock() : hash doesn't match nBits");


// Check merkleroot // Check merkleroot
if (hashMerkleRoot != BuildMerkleTree()) if (hashMerkleRoot != BuildMerkleTree())
Expand All @@ -1388,12 +1414,12 @@ bool CBlock::AcceptBlock()
CBlockIndex* pindexPrev = (*mi).second; CBlockIndex* pindexPrev = (*mi).second;


// Check timestamp against prev // Check timestamp against prev
if (nTime <= pindexPrev->GetMedianTimePast()) if (GetBlockTime() <= pindexPrev->GetMedianTimePast())
return error("AcceptBlock() : block's timestamp is too early"); return error("AcceptBlock() : block's timestamp is too early");


// Check that all transactions are finalized // Check that all transactions are finalized
foreach(const CTransaction& tx, vtx) foreach(const CTransaction& tx, vtx)
if (!tx.IsFinal(pindexPrev->nHeight+1, nTime)) if (!tx.IsFinal(pindexPrev->nHeight+1, GetBlockTime()))
return error("AcceptBlock() : contains a non-final transaction"); return error("AcceptBlock() : contains a non-final transaction");


// Check proof of work // Check proof of work
Expand Down Expand Up @@ -1442,9 +1468,9 @@ bool ProcessBlock(CNode* pfrom, CBlock* pblock)
// Check for duplicate // Check for duplicate
uint256 hash = pblock->GetHash(); uint256 hash = pblock->GetHash();
if (mapBlockIndex.count(hash)) if (mapBlockIndex.count(hash))
return error("ProcessBlock() : already have block %d %s", mapBlockIndex[hash]->nHeight, hash.ToString().substr(0,16).c_str()); return error("ProcessBlock() : already have block %d %s", mapBlockIndex[hash]->nHeight, hash.ToString().substr(0,20).c_str());
if (mapOrphanBlocks.count(hash)) if (mapOrphanBlocks.count(hash))
return error("ProcessBlock() : already have block (orphan) %s", hash.ToString().substr(0,16).c_str()); return error("ProcessBlock() : already have block (orphan) %s", hash.ToString().substr(0,20).c_str());


// Preliminary checks // Preliminary checks
if (!pblock->CheckBlock()) if (!pblock->CheckBlock())
Expand All @@ -1456,7 +1482,7 @@ bool ProcessBlock(CNode* pfrom, CBlock* pblock)
// If don't already have its previous block, shunt it off to holding area until we get it // If don't already have its previous block, shunt it off to holding area until we get it
if (!mapBlockIndex.count(pblock->hashPrevBlock)) if (!mapBlockIndex.count(pblock->hashPrevBlock))
{ {
printf("ProcessBlock: ORPHAN BLOCK, prev=%s\n", pblock->hashPrevBlock.ToString().substr(0,16).c_str()); printf("ProcessBlock: ORPHAN BLOCK, prev=%s\n", pblock->hashPrevBlock.ToString().substr(0,20).c_str());
mapOrphanBlocks.insert(make_pair(hash, pblock)); mapOrphanBlocks.insert(make_pair(hash, pblock));
mapOrphanBlocksByPrev.insert(make_pair(pblock->hashPrevBlock, pblock)); mapOrphanBlocksByPrev.insert(make_pair(pblock->hashPrevBlock, pblock));


Expand Down Expand Up @@ -1731,8 +1757,8 @@ void PrintBlockTree()
pindex->nHeight, pindex->nHeight,
pindex->nFile, pindex->nFile,
pindex->nBlockPos, pindex->nBlockPos,
block.GetHash().ToString().substr(0,16).c_str(), block.GetHash().ToString().substr(0,20).c_str(),
DateTimeStrFormat("%x %H:%M:%S", block.nTime).c_str(), DateTimeStrFormat("%x %H:%M:%S", block.GetBlockTime()).c_str(),
block.vtx.size()); block.vtx.size());


CRITICAL_BLOCK(cs_mapWallet) CRITICAL_BLOCK(cs_mapWallet)
Expand Down Expand Up @@ -2157,20 +2183,20 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
if (pindex) if (pindex)
pindex = pindex->pnext; pindex = pindex->pnext;
int nLimit = 500 + locator.GetDistanceBack(); int nLimit = 500 + locator.GetDistanceBack();
printf("getblocks %d to %s limit %d\n", (pindex ? pindex->nHeight : -1), hashStop.ToString().substr(0,16).c_str(), nLimit); printf("getblocks %d to %s limit %d\n", (pindex ? pindex->nHeight : -1), hashStop.ToString().substr(0,20).c_str(), nLimit);
for (; pindex; pindex = pindex->pnext) for (; pindex; pindex = pindex->pnext)
{ {
if (pindex->GetBlockHash() == hashStop) if (pindex->GetBlockHash() == hashStop)
{ {
printf(" getblocks stopping at %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString().substr(0,16).c_str()); printf(" getblocks stopping at %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString().substr(0,20).c_str());
break; break;
} }
pfrom->PushInventory(CInv(MSG_BLOCK, pindex->GetBlockHash())); pfrom->PushInventory(CInv(MSG_BLOCK, pindex->GetBlockHash()));
if (--nLimit <= 0) if (--nLimit <= 0)
{ {
// When this block is requested, we'll send an inv that'll make them // When this block is requested, we'll send an inv that'll make them
// getblocks the next batch of inventory. // getblocks the next batch of inventory.
printf(" getblocks stopping at limit %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString().substr(0,16).c_str()); printf(" getblocks stopping at limit %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString().substr(0,20).c_str());
pfrom->hashContinue = pindex->GetBlockHash(); pfrom->hashContinue = pindex->GetBlockHash();
break; break;
} }
Expand Down Expand Up @@ -2237,7 +2263,7 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
vRecv >> *pblock; vRecv >> *pblock;


//// debug print //// debug print
printf("received block %s\n", pblock->GetHash().ToString().substr(0,16).c_str()); printf("received block %s\n", pblock->GetHash().ToString().substr(0,20).c_str());
// pblock->print(); // pblock->print();


CInv inv(MSG_BLOCK, pblock->GetHash()); CInv inv(MSG_BLOCK, pblock->GetHash());
Expand Down

0 comments on commit 0545481

Please sign in to comment.