Browse Source

block index checking on load, extra redundant checks, misc refactoring

0.8
Satoshi Nakamoto 14 years ago committed by Gavin Andresen
parent
commit
7a37c906a1
  1. 11
      db.cpp
  2. 98
      main.cpp
  3. 68
      main.h
  4. 2
      net.h
  5. 9
      serialize.h

11
db.cpp

@ -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
{ {
@ -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);
@ -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");
@ -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")

98
main.cpp

@ -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();
@ -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
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;
@ -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();
} }
@ -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");
@ -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)
@ -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;
@ -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)
@ -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()
@ -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");
@ -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)
@ -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");
@ -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))
{ {
@ -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;
} }
@ -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);
@ -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
@ -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())
@ -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
@ -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())
@ -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));
@ -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)
@ -2157,12 +2183,12 @@ 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()));
@ -2170,7 +2196,7 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
{ {
// 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;
} }
@ -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());

68
main.h

@ -19,8 +19,8 @@ static const unsigned int MAX_BLOCK_SIZE = 1000000;
static const int64 COIN = 100000000; static const int64 COIN = 100000000;
static const int64 CENT = 1000000; static const int64 CENT = 1000000;
static const int64 MAX_MONEY = 21000000 * COIN; static const int64 MAX_MONEY = 21000000 * COIN;
inline bool MoneyRange(int64 nValue) { return (nValue >= 0 && nValue <= MAX_MONEY); }
static const int COINBASE_MATURITY = 100; static const int COINBASE_MATURITY = 100;
static const CBigNum bnProofOfWorkLimit(~uint256(0) >> 32); static const CBigNum bnProofOfWorkLimit(~uint256(0) >> 32);
@ -83,6 +83,7 @@ string SendMoneyToBitcoinAddress(string strAddress, int64 nValue, CWalletTx& wtx
void GenerateBitcoins(bool fGenerate); void GenerateBitcoins(bool fGenerate);
void ThreadBitcoinMiner(void* parg); void ThreadBitcoinMiner(void* parg);
void BitcoinMiner(); void BitcoinMiner();
bool CheckProofOfWork(uint256 hash, unsigned int nBits);
bool IsInitialBlockDownload(); bool IsInitialBlockDownload();
bool IsLockdown(); bool IsLockdown();
@ -338,6 +339,8 @@ public:
int64 GetCredit() const int64 GetCredit() const
{ {
if (!MoneyRange(nValue))
throw runtime_error("CTxOut::GetCredit() : value out of range");
if (IsMine()) if (IsMine())
return nValue; return nValue;
return 0; return 0;
@ -424,7 +427,7 @@ public:
nBlockHeight = nBestHeight; nBlockHeight = nBestHeight;
if (nBlockTime == 0) if (nBlockTime == 0)
nBlockTime = GetAdjustedTime(); nBlockTime = GetAdjustedTime();
if (nLockTime < (nLockTime < 500000000 ? nBlockHeight : nBlockTime)) if ((int64)nLockTime < (nLockTime < 500000000 ? (int64)nBlockHeight : nBlockTime))
return true; return true;
foreach(const CTxIn& txin, vin) foreach(const CTxIn& txin, vin)
if (!txin.IsFinal()) if (!txin.IsFinal())
@ -481,8 +484,8 @@ public:
if (txout.nValue > MAX_MONEY) if (txout.nValue > MAX_MONEY)
return error("CTransaction::CheckTransaction() : txout.nValue too high"); return error("CTransaction::CheckTransaction() : txout.nValue too high");
nValueOut += txout.nValue; nValueOut += txout.nValue;
if (nValueOut > MAX_MONEY) if (!MoneyRange(nValueOut))
return error("CTransaction::CheckTransaction() : txout total too high"); return error("CTransaction::CheckTransaction() : txout total out of range");
} }
if (IsCoinBase()) if (IsCoinBase())
@ -512,7 +515,11 @@ public:
{ {
int64 nDebit = 0; int64 nDebit = 0;
foreach(const CTxIn& txin, vin) foreach(const CTxIn& txin, vin)
{
nDebit += txin.GetDebit(); nDebit += txin.GetDebit();
if (!MoneyRange(nDebit))
throw runtime_error("CTransaction::GetDebit() : value out of range");
}
return nDebit; return nDebit;
} }
@ -520,7 +527,11 @@ public:
{ {
int64 nCredit = 0; int64 nCredit = 0;
foreach(const CTxOut& txout, vout) foreach(const CTxOut& txout, vout)
{
nCredit += txout.GetCredit(); nCredit += txout.GetCredit();
if (!MoneyRange(nCredit))
throw runtime_error("CTransaction::GetCredit() : value out of range");
}
return nCredit; return nCredit;
} }
@ -529,9 +540,9 @@ public:
int64 nValueOut = 0; int64 nValueOut = 0;
foreach(const CTxOut& txout, vout) foreach(const CTxOut& txout, vout)
{ {
if (txout.nValue < 0)
throw runtime_error("CTransaction::GetValueOut() : negative value");
nValueOut += txout.nValue; nValueOut += txout.nValue;
if (!MoneyRange(txout.nValue) || !MoneyRange(nValueOut))
throw runtime_error("CTransaction::GetValueOut() : value out of range");
} }
return nValueOut; return nValueOut;
} }
@ -930,6 +941,11 @@ public:
return Hash(BEGIN(nVersion), END(nNonce)); return Hash(BEGIN(nVersion), END(nNonce));
} }
int64 GetBlockTime() const
{
return (int64)nTime;
}
uint256 BuildMerkleTree() const uint256 BuildMerkleTree() const
{ {
@ -1030,10 +1046,8 @@ public:
filein >> *this; filein >> *this;
// Check the header // Check the header
if (CBigNum().SetCompact(nBits) > bnProofOfWorkLimit) if (!CheckProofOfWork(GetHash(), nBits))
return error("CBlock::ReadFromDisk() : nBits errors in block header"); return error("CBlock::ReadFromDisk() : errors in block header");
if (GetHash() > CBigNum().SetCompact(nBits).getuint256())
return error("CBlock::ReadFromDisk() : GetHash() errors in block header");
return true; return true;
} }
@ -1043,9 +1057,9 @@ public:
void print() const void print() const
{ {
printf("CBlock(hash=%s, ver=%d, hashPrevBlock=%s, hashMerkleRoot=%s, nTime=%u, nBits=%08x, nNonce=%u, vtx=%d)\n", printf("CBlock(hash=%s, ver=%d, hashPrevBlock=%s, hashMerkleRoot=%s, nTime=%u, nBits=%08x, nNonce=%u, vtx=%d)\n",
GetHash().ToString().substr(0,16).c_str(), GetHash().ToString().substr(0,20).c_str(),
nVersion, nVersion,
hashPrevBlock.ToString().substr(0,16).c_str(), hashPrevBlock.ToString().substr(0,20).c_str(),
hashMerkleRoot.ToString().substr(0,6).c_str(), hashMerkleRoot.ToString().substr(0,6).c_str(),
nTime, nBits, nNonce, nTime, nBits, nNonce,
vtx.size()); vtx.size());
@ -1064,7 +1078,7 @@ public:
int64 GetBlockValue(int nHeight, int64 nFees) const; int64 GetBlockValue(int nHeight, int64 nFees) const;
bool DisconnectBlock(CTxDB& txdb, CBlockIndex* pindex); bool DisconnectBlock(CTxDB& txdb, CBlockIndex* pindex);
bool ConnectBlock(CTxDB& txdb, CBlockIndex* pindex); bool ConnectBlock(CTxDB& txdb, CBlockIndex* pindex);
bool ReadFromDisk(const CBlockIndex* blockindex, bool fReadTransactions=true); bool ReadFromDisk(const CBlockIndex* pindex, bool fReadTransactions=true);
bool SetBestChain(CTxDB& txdb, CBlockIndex* pindexNew); bool SetBestChain(CTxDB& txdb, CBlockIndex* pindexNew);
bool AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos); bool AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos);
bool CheckBlock() const; bool CheckBlock() const;
@ -1142,8 +1156,15 @@ public:
return *phashBlock; return *phashBlock;
} }
int64 GetBlockTime() const
{
return (int64)nTime;
}
CBigNum GetBlockWork() const CBigNum GetBlockWork() const
{ {
if (CBigNum().SetCompact(nBits) <= 0)
return 0;
return (CBigNum(1)<<256) / (CBigNum().SetCompact(nBits)+1); return (CBigNum(1)<<256) / (CBigNum().SetCompact(nBits)+1);
} }
@ -1152,6 +1173,11 @@ public:
return (pnext || this == pindexBest); return (pnext || this == pindexBest);
} }
bool CheckIndex() const
{
return CheckProofOfWork(GetBlockHash(), nBits);
}
bool EraseBlockFromDisk() bool EraseBlockFromDisk()
{ {
// Open history file // Open history file
@ -1171,13 +1197,13 @@ public:
int64 GetMedianTimePast() const int64 GetMedianTimePast() const
{ {
unsigned int pmedian[nMedianTimeSpan]; int64 pmedian[nMedianTimeSpan];
unsigned int* pbegin = &pmedian[nMedianTimeSpan]; int64* pbegin = &pmedian[nMedianTimeSpan];
unsigned int* pend = &pmedian[nMedianTimeSpan]; int64* pend = &pmedian[nMedianTimeSpan];
const CBlockIndex* pindex = this; const CBlockIndex* pindex = this;
for (int i = 0; i < nMedianTimeSpan && pindex; i++, pindex = pindex->pprev) for (int i = 0; i < nMedianTimeSpan && pindex; i++, pindex = pindex->pprev)
*(--pbegin) = pindex->nTime; *(--pbegin) = pindex->GetBlockTime();
sort(pbegin, pend); sort(pbegin, pend);
return pbegin[(pend - pbegin)/2]; return pbegin[(pend - pbegin)/2];
@ -1189,7 +1215,7 @@ public:
for (int i = 0; i < nMedianTimeSpan/2; i++) for (int i = 0; i < nMedianTimeSpan/2; i++)
{ {
if (!pindex->pnext) if (!pindex->pnext)
return nTime; return GetBlockTime();
pindex = pindex->pnext; pindex = pindex->pnext;
} }
return pindex->GetMedianTimePast(); return pindex->GetMedianTimePast();
@ -1202,7 +1228,7 @@ public:
return strprintf("CBlockIndex(nprev=%08x, pnext=%08x, nFile=%d, nBlockPos=%-6d nHeight=%d, merkle=%s, hashBlock=%s)", return strprintf("CBlockIndex(nprev=%08x, pnext=%08x, nFile=%d, nBlockPos=%-6d nHeight=%d, merkle=%s, hashBlock=%s)",
pprev, pnext, nFile, nBlockPos, nHeight, pprev, pnext, nFile, nBlockPos, nHeight,
hashMerkleRoot.ToString().substr(0,6).c_str(), hashMerkleRoot.ToString().substr(0,6).c_str(),
GetBlockHash().ToString().substr(0,16).c_str()); GetBlockHash().ToString().substr(0,20).c_str());
} }
void print() const void print() const
@ -1272,8 +1298,8 @@ public:
str += CBlockIndex::ToString(); str += CBlockIndex::ToString();
str += strprintf("\n hashBlock=%s, hashPrev=%s, hashNext=%s)", str += strprintf("\n hashBlock=%s, hashPrev=%s, hashNext=%s)",
GetBlockHash().ToString().c_str(), GetBlockHash().ToString().c_str(),
hashPrev.ToString().substr(0,16).c_str(), hashPrev.ToString().substr(0,20).c_str(),
hashNext.ToString().substr(0,16).c_str()); hashNext.ToString().substr(0,20).c_str());
return str; return str;
} }

2
net.h

@ -424,7 +424,7 @@ public:
string ToString() const string ToString() const
{ {
return strprintf("%s %s", GetCommand(), hash.ToString().substr(0,16).c_str()); return strprintf("%s %s", GetCommand(), hash.ToString().substr(0,20).c_str());
} }
void print() const void print() const

9
serialize.h

@ -20,7 +20,7 @@ class CDataStream;
class CAutoFile; class CAutoFile;
static const int VERSION = 310; static const int VERSION = 310;
static const char* pszSubVer = ".3"; static const char* pszSubVer = ".4";
@ -81,6 +81,13 @@ enum
#define READWRITE(obj) (nSerSize += ::SerReadWrite(s, (obj), nType, nVersion, ser_action)) #define READWRITE(obj) (nSerSize += ::SerReadWrite(s, (obj), nType, nVersion, ser_action))
#define READWRITEVER(obj) \
do { \
READWRITE((obj)); \
if ((obj) == 10300) \
(obj) = 300; \
} while (false)

Loading…
Cancel
Save