block index checking on load, extra redundant checks, misc refactoring
authorSatoshi Nakamoto <satoshin@gmx.com>
Sat, 28 Aug 2010 00:49:30 +0000 (00:49 +0000)
committerGavin Andresen <gavinandresen@gmail.com>
Sat, 28 Aug 2010 00:49:30 +0000 (00:49 +0000)
db.cpp
main.cpp
main.h
net.h
serialize.h

diff --git a/db.cpp b/db.cpp
index 8be1e20..6717c04 100644 (file)
--- a/db.cpp
+++ b/db.cpp
@@ -419,6 +419,9 @@ bool CTxDB::LoadBlockIndex()
             // Watch for genesis block
             if (pindexGenesisBlock == NULL && diskindex.GetBlockHash() == hashGenesisBlock)
                 pindexGenesisBlock = pindexNew;
+
+            if (!pindexNew->CheckIndex())
+                return error("LoadBlockIndex() : CheckIndex failed at %d", pindexNew->nHeight);
         }
         else
         {
@@ -454,7 +457,7 @@ bool CTxDB::LoadBlockIndex()
     pindexBest = mapBlockIndex[hashBestChain];
     nBestHeight = pindexBest->nHeight;
     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
     ReadBestInvalidWork(bnBestInvalidWork);
@@ -463,6 +466,8 @@ bool CTxDB::LoadBlockIndex()
     CBlockIndex* pindexFork = NULL;
     for (CBlockIndex* pindex = pindexBest; pindex && pindex->pprev; pindex = pindex->pprev)
     {
+        if (pindex->nHeight < 74000 && !mapArgs.count("-checkblocks"))
+            break;
         CBlock block;
         if (!block.ReadFromDisk(pindex))
             return error("LoadBlockIndex() : block.ReadFromDisk failed");
@@ -629,8 +634,8 @@ bool CWalletDB::LoadWallet()
                 //printf("LoadWallet  %s\n", wtx.GetHash().ToString().c_str());
                 //printf(" %12I64d  %s  %s  %s\n",
                 //    wtx.vout[0].nValue,
-                //    DateTimeStrFormat("%x %H:%M:%S", wtx.nTime).c_str(),
-                //    wtx.hashBlock.ToString().substr(0,16).c_str(),
+                //    DateTimeStrFormat("%x %H:%M:%S", wtx.GetBlockTime()).c_str(),
+                //    wtx.hashBlock.ToString().substr(0,20).c_str(),
                 //    wtx.mapValue["message"].c_str());
             }
             else if (strType == "key" || strType == "wkey")
index 953a43f..f5a3555 100644 (file)
--- a/main.cpp
+++ b/main.cpp
@@ -500,8 +500,8 @@ bool CTransaction::AcceptTransaction(CTxDB& txdb, bool fCheckInputs, bool* pfMis
         return error("AcceptTransaction() : CheckTransaction failed");
 
     // To help v0.1.5 clients who would see it as a negative number
-    if (nLockTime > INT_MAX)
-        return error("AcceptTransaction() : not accepting nLockTime beyond 2038");
+    if ((int64)nLockTime > INT_MAX)
+        return error("AcceptTransaction() : not accepting nLockTime beyond 2038 yet");
 
     // Do we already have it?
     uint256 hash = GetHash();
@@ -519,6 +519,9 @@ bool CTransaction::AcceptTransaction(CTxDB& txdb, bool fCheckInputs, bool* pfMis
         COutPoint outpoint = vin[i].prevout;
         if (mapNextTx.count(outpoint))
         {
+            // Disable replacement feature for now
+            return false;
+
             // Allow replacing with a newer version of the same transaction
             if (i != 0)
                 return false;
@@ -550,8 +553,8 @@ bool CTransaction::AcceptTransaction(CTxDB& txdb, bool fCheckInputs, bool* pfMis
     {
         if (ptxOld)
         {
-            printf("mapTransaction.erase(%s) replacing with new version\n", ptxOld->GetHash().ToString().c_str());
-            mapTransactions.erase(ptxOld->GetHash());
+            printf("AcceptTransaction() : replacing tx %s with new version\n", ptxOld->GetHash().ToString().c_str());
+            ptxOld->RemoveFromMemoryPool();
         }
         AddToMemoryPool();
     }
@@ -748,6 +751,12 @@ void ResendWalletTransactions()
     if (fFirst)
         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
     printf("ResendWalletTransactions()\n");
     CTxDB txdb("r");
@@ -785,9 +794,13 @@ void ResendWalletTransactions()
 // 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)
@@ -829,7 +842,7 @@ unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast)
     assert(pindexFirst);
 
     // Limit adjustment step
-    int64 nActualTimespan = (int64)pindexLast->nTime - (int64)pindexFirst->nTime;
+    int64 nActualTimespan = pindexLast->GetBlockTime() - pindexFirst->GetBlockTime();
     printf("  nActualTimespan = %"PRI64d"  before bounds\n", nActualTimespan);
     if (nActualTimespan < nTargetTimespan/4)
         nActualTimespan = nTargetTimespan/4;
@@ -854,6 +867,22 @@ unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast)
     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()
 {
     if (pindexBest == NULL)
@@ -866,7 +895,7 @@ bool IsInitialBlockDownload()
         nLastUpdate = GetTime();
     }
     return (GetTime() - nLastUpdate < 10 &&
-            pindexBest->nTime < GetTime() - 24 * 60 * 60);
+            pindexBest->GetBlockTime() < GetTime() - 24 * 60 * 60);
 }
 
 bool IsLockdown()
@@ -884,8 +913,8 @@ void Lockdown(CBlockIndex* pindexNew)
         CTxDB().WriteBestInvalidWork(bnBestInvalidWork);
         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:  current best=%s  height=%d  work=%s\n", hashBestChain.ToString().substr(0,22).c_str(), nBestHeight, bnBestChainWork.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,20).c_str(), nBestHeight, bnBestChainWork.ToString().c_str());
     printf("Lockdown: IsLockdown()=%d\n", (IsLockdown() ? 1 : 0));
     if (IsLockdown())
         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;
 
             // Check for negative or overflow input values
-            if (txPrev.vout[prevout.n].nValue < 0)
-                return error("ConnectInputs() : txin.nValue negative");
-            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 (!MoneyRange(txPrev.vout[prevout.n].nValue) || !MoneyRange(nValueIn))
+                return error("ConnectInputs() : txin values out of range");
         }
 
+        if (nValueIn < GetValueOut())
+            return error("ConnectInputs() : %s value in < value out", GetHash().ToString().substr(0,6).c_str());
+
         // Tally transaction fees
         int64 nTxFee = nValueIn - GetValueOut();
         if (nTxFee < 0)
@@ -1180,7 +1208,7 @@ bool Reorganize(CTxDB& txdb, CBlockIndex* pindexNew)
     foreach(CBlockIndex* pindex, vDisconnect)
     {
         CBlock block;
-        if (!block.ReadFromDisk(pindex->nFile, pindex->nBlockPos))
+        if (!block.ReadFromDisk(pindex))
             return error("Reorganize() : ReadFromDisk for disconnect failed");
         if (!block.DisconnectBlock(txdb, pindex))
             return error("Reorganize() : DisconnectBlock failed");
@@ -1197,7 +1225,7 @@ bool Reorganize(CTxDB& txdb, CBlockIndex* pindexNew)
     {
         CBlockIndex* pindex = vConnect[i];
         CBlock block;
-        if (!block.ReadFromDisk(pindex->nFile, pindex->nBlockPos))
+        if (!block.ReadFromDisk(pindex))
             return error("Reorganize() : ReadFromDisk for connect failed");
         if (!block.ConnectBlock(txdb, pindex))
         {
@@ -1283,7 +1311,7 @@ bool CBlock::SetBestChain(CTxDB& txdb, CBlockIndex* pindexNew)
     bnBestChainWork = pindexNew->bnChainWork;
     nTimeBestReceived = GetTime();
     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;
 }
@@ -1294,7 +1322,7 @@ bool CBlock::AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos)
     // Check for duplicate
     uint256 hash = GetHash();
     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
     CBlockIndex* pindexNew = new CBlockIndex(nFile, nBlockPos, *this);
@@ -1346,7 +1374,7 @@ bool CBlock::CheckBlock() const
         return error("CheckBlock() : size limits failed");
 
     // Check timestamp
-    if (nTime > GetAdjustedTime() + 2 * 60 * 60)
+    if (GetBlockTime() > GetAdjustedTime() + 2 * 60 * 60)
         return error("CheckBlock() : block timestamp too far in the future");
 
     // First transaction must be coinbase, the rest must not be
@@ -1362,10 +1390,8 @@ bool CBlock::CheckBlock() const
             return error("CheckBlock() : CheckTransaction failed");
 
     // Check proof of work matches claimed amount
-    if (CBigNum().SetCompact(nBits) > bnProofOfWorkLimit)
-        return error("CheckBlock() : nBits below minimum work");
-    if (GetHash() > CBigNum().SetCompact(nBits).getuint256())
-        return error("CheckBlock() : hash doesn't match nBits");
+    if (!CheckProofOfWork(GetHash(), nBits))
+        return error("CheckBlock() : proof of work failed");
 
     // Check merkleroot
     if (hashMerkleRoot != BuildMerkleTree())
@@ -1388,12 +1414,12 @@ bool CBlock::AcceptBlock()
     CBlockIndex* pindexPrev = (*mi).second;
 
     // Check timestamp against prev
-    if (nTime <= pindexPrev->GetMedianTimePast())
+    if (GetBlockTime() <= pindexPrev->GetMedianTimePast())
         return error("AcceptBlock() : block's timestamp is too early");
 
     // Check that all transactions are finalized
     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");
 
     // Check proof of work
@@ -1442,9 +1468,9 @@ bool ProcessBlock(CNode* pfrom, CBlock* pblock)
     // Check for duplicate
     uint256 hash = pblock->GetHash();
     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))
-        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
     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 (!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));
         mapOrphanBlocksByPrev.insert(make_pair(pblock->hashPrevBlock, pblock));
 
@@ -1731,8 +1757,8 @@ void PrintBlockTree()
             pindex->nHeight,
             pindex->nFile,
             pindex->nBlockPos,
-            block.GetHash().ToString().substr(0,16).c_str(),
-            DateTimeStrFormat("%x %H:%M:%S", block.nTime).c_str(),
+            block.GetHash().ToString().substr(0,20).c_str(),
+            DateTimeStrFormat("%x %H:%M:%S", block.GetBlockTime()).c_str(),
             block.vtx.size());
 
         CRITICAL_BLOCK(cs_mapWallet)
@@ -2157,12 +2183,12 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
         if (pindex)
             pindex = pindex->pnext;
         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)
         {
             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;
             }
             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
                 // 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();
                 break;
             }
@@ -2237,7 +2263,7 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
         vRecv >> *pblock;
 
         //// 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();
 
         CInv inv(MSG_BLOCK, pblock->GetHash());
diff --git a/main.h b/main.h
index f5467d1..333fa83 100644 (file)
--- a/main.h
+++ b/main.h
@@ -19,8 +19,8 @@ static const unsigned int MAX_BLOCK_SIZE = 1000000;
 static const int64 COIN = 100000000;
 static const int64 CENT = 1000000;
 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 CBigNum bnProofOfWorkLimit(~uint256(0) >> 32);
 
 
@@ -83,6 +83,7 @@ string SendMoneyToBitcoinAddress(string strAddress, int64 nValue, CWalletTx& wtx
 void GenerateBitcoins(bool fGenerate);
 void ThreadBitcoinMiner(void* parg);
 void BitcoinMiner();
+bool CheckProofOfWork(uint256 hash, unsigned int nBits);
 bool IsInitialBlockDownload();
 bool IsLockdown();
 
@@ -338,6 +339,8 @@ public:
 
     int64 GetCredit() const
     {
+        if (!MoneyRange(nValue))
+            throw runtime_error("CTxOut::GetCredit() : value out of range");
         if (IsMine())
             return nValue;
         return 0;
@@ -424,7 +427,7 @@ public:
             nBlockHeight = nBestHeight;
         if (nBlockTime == 0)
             nBlockTime = GetAdjustedTime();
-        if (nLockTime < (nLockTime < 500000000 ? nBlockHeight : nBlockTime))
+        if ((int64)nLockTime < (nLockTime < 500000000 ? (int64)nBlockHeight : nBlockTime))
             return true;
         foreach(const CTxIn& txin, vin)
             if (!txin.IsFinal())
@@ -481,8 +484,8 @@ public:
             if (txout.nValue > MAX_MONEY)
                 return error("CTransaction::CheckTransaction() : txout.nValue too high");
             nValueOut += txout.nValue;
-            if (nValueOut > MAX_MONEY)
-                return error("CTransaction::CheckTransaction() : txout total too high");
+            if (!MoneyRange(nValueOut))
+                return error("CTransaction::CheckTransaction() : txout total out of range");
         }
 
         if (IsCoinBase())
@@ -512,7 +515,11 @@ public:
     {
         int64 nDebit = 0;
         foreach(const CTxIn& txin, vin)
+        {
             nDebit += txin.GetDebit();
+            if (!MoneyRange(nDebit))
+                throw runtime_error("CTransaction::GetDebit() : value out of range");
+        }
         return nDebit;
     }
 
@@ -520,7 +527,11 @@ public:
     {
         int64 nCredit = 0;
         foreach(const CTxOut& txout, vout)
+        {
             nCredit += txout.GetCredit();
+            if (!MoneyRange(nCredit))
+                throw runtime_error("CTransaction::GetCredit() : value out of range");
+        }
         return nCredit;
     }
 
@@ -529,9 +540,9 @@ public:
         int64 nValueOut = 0;
         foreach(const CTxOut& txout, vout)
         {
-            if (txout.nValue < 0)
-                throw runtime_error("CTransaction::GetValueOut() : negative value");
             nValueOut += txout.nValue;
+            if (!MoneyRange(txout.nValue) || !MoneyRange(nValueOut))
+                throw runtime_error("CTransaction::GetValueOut() : value out of range");
         }
         return nValueOut;
     }
@@ -930,6 +941,11 @@ public:
         return Hash(BEGIN(nVersion), END(nNonce));
     }
 
+    int64 GetBlockTime() const
+    {
+        return (int64)nTime;
+    }
+
 
     uint256 BuildMerkleTree() const
     {
@@ -1030,10 +1046,8 @@ public:
         filein >> *this;
 
         // Check the header
-        if (CBigNum().SetCompact(nBits) > bnProofOfWorkLimit)
-            return error("CBlock::ReadFromDisk() : nBits errors in block header");
-        if (GetHash() > CBigNum().SetCompact(nBits).getuint256())
-            return error("CBlock::ReadFromDisk() : GetHash() errors in block header");
+        if (!CheckProofOfWork(GetHash(), nBits))
+            return error("CBlock::ReadFromDisk() : errors in block header");
 
         return true;
     }
@@ -1043,9 +1057,9 @@ public:
     void print() const
     {
         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,
-            hashPrevBlock.ToString().substr(0,16).c_str(),
+            hashPrevBlock.ToString().substr(0,20).c_str(),
             hashMerkleRoot.ToString().substr(0,6).c_str(),
             nTime, nBits, nNonce,
             vtx.size());
@@ -1064,7 +1078,7 @@ public:
     int64 GetBlockValue(int nHeight, int64 nFees) const;
     bool DisconnectBlock(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 AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos);
     bool CheckBlock() const;
@@ -1142,8 +1156,15 @@ public:
         return *phashBlock;
     }
 
+    int64 GetBlockTime() const
+    {
+        return (int64)nTime;
+    }
+
     CBigNum GetBlockWork() const
     {
+        if (CBigNum().SetCompact(nBits) <= 0)
+            return 0;
         return (CBigNum(1)<<256) / (CBigNum().SetCompact(nBits)+1);
     }
 
@@ -1152,6 +1173,11 @@ public:
         return (pnext || this == pindexBest);
     }
 
+    bool CheckIndex() const
+    {
+        return CheckProofOfWork(GetBlockHash(), nBits);
+    }
+
     bool EraseBlockFromDisk()
     {
         // Open history file
@@ -1171,13 +1197,13 @@ public:
 
     int64 GetMedianTimePast() const
     {
-        unsigned int pmedian[nMedianTimeSpan];
-        unsigned int* pbegin = &pmedian[nMedianTimeSpan];
-        unsigned int* pend = &pmedian[nMedianTimeSpan];
+        int64 pmedian[nMedianTimeSpan];
+        int64* pbegin = &pmedian[nMedianTimeSpan];
+        int64* pend = &pmedian[nMedianTimeSpan];
 
         const CBlockIndex* pindex = this;
         for (int i = 0; i < nMedianTimeSpan && pindex; i++, pindex = pindex->pprev)
-            *(--pbegin) = pindex->nTime;
+            *(--pbegin) = pindex->GetBlockTime();
 
         sort(pbegin, pend);
         return pbegin[(pend - pbegin)/2];
@@ -1189,7 +1215,7 @@ public:
         for (int i = 0; i < nMedianTimeSpan/2; i++)
         {
             if (!pindex->pnext)
-                return nTime;
+                return GetBlockTime();
             pindex = pindex->pnext;
         }
         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)",
             pprev, pnext, nFile, nBlockPos, nHeight,
             hashMerkleRoot.ToString().substr(0,6).c_str(),
-            GetBlockHash().ToString().substr(0,16).c_str());
+            GetBlockHash().ToString().substr(0,20).c_str());
     }
 
     void print() const
@@ -1272,8 +1298,8 @@ public:
         str += CBlockIndex::ToString();
         str += strprintf("\n                hashBlock=%s, hashPrev=%s, hashNext=%s)",
             GetBlockHash().ToString().c_str(),
-            hashPrev.ToString().substr(0,16).c_str(),
-            hashNext.ToString().substr(0,16).c_str());
+            hashPrev.ToString().substr(0,20).c_str(),
+            hashNext.ToString().substr(0,20).c_str());
         return str;
     }
 
diff --git a/net.h b/net.h
index 5a52077..5b24f7a 100644 (file)
--- a/net.h
+++ b/net.h
@@ -424,7 +424,7 @@ public:
 
     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
index d65fe71..6495cfe 100644 (file)
@@ -20,7 +20,7 @@ class CDataStream;
 class CAutoFile;
 
 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 READWRITEVER(obj)       \
+    do {                        \
+        READWRITE((obj));       \
+        if ((obj) == 10300)     \
+            (obj) = 300;        \
+    } while (false)
+