changeset 193:83513e9c3f0c draft

new safety feature displays a warning message and locks down RPC if it detects a problem that may require an upgrade -- version 0.3.8
author Satoshi Nakamoto <satoshin@gmx.com>
date Wed, 04 Aug 2010 01:51:34 +0000
parents 2f1d353a4b54
children 82bdb6a60e94
files db.cpp db.h main.cpp main.h rpc.cpp serialize.h setup.nsi ui.cpp
diffstat 8 files changed, 81 insertions(+), 34 deletions(-) [+]
line wrap: on
line diff
--- a/db.cpp
+++ b/db.cpp
@@ -342,6 +342,16 @@
     return Write(string("hashBestChain"), hashBestChain);
 }
 
+bool CTxDB::ReadBestInvalidWork(CBigNum& bnBestInvalidWork)
+{
+    return Read(string("bnBestInvalidWork"), bnBestInvalidWork);
+}
+
+bool CTxDB::WriteBestInvalidWork(CBigNum bnBestInvalidWork)
+{
+    return Write(string("bnBestInvalidWork"), bnBestInvalidWork);
+}
+
 CBlockIndex* InsertBlockIndex(uint256 hash)
 {
     if (hash == 0)
@@ -446,6 +456,9 @@
     bnBestChainWork = pindexBest->bnChainWork;
     printf("LoadBlockIndex(): hashBestChain=%s  height=%d\n", hashBestChain.ToString().substr(0,16).c_str(), nBestHeight);
 
+    // Load bnBestInvalidWork, OK if it doesn't exist
+    ReadBestInvalidWork(bnBestInvalidWork);
+
     return true;
 }
 
--- a/db.h
+++ b/db.h
@@ -280,6 +280,8 @@
     bool EraseBlockIndex(uint256 hash);
     bool ReadHashBestChain(uint256& hashBestChain);
     bool WriteHashBestChain(uint256 hashBestChain);
+    bool ReadBestInvalidWork(CBigNum& bnBestInvalidWork);
+    bool WriteBestInvalidWork(CBigNum bnBestInvalidWork);
     bool LoadBlockIndex();
 };
 
--- a/main.cpp
+++ b/main.cpp
@@ -25,6 +25,7 @@
 CBlockIndex* pindexGenesisBlock = NULL;
 int nBestHeight = -1;
 CBigNum bnBestChainWork = 0;
+CBigNum bnBestInvalidWork = 0;
 uint256 hashBestChain = 0;
 CBlockIndex* pindexBest = NULL;
 int64 nTimeBestReceived = 0;
@@ -794,12 +795,12 @@
     return pblock->GetHash();
 }
 
-int64 CBlock::GetBlockValue(int64 nFees) const
+int64 CBlock::GetBlockValue(int nHeight, int64 nFees) const
 {
     int64 nSubsidy = 50 * COIN;
 
     // Subsidy is cut in half every 4 years
-    nSubsidy >>= (nBestHeight / 210000);
+    nSubsidy >>= (nHeight / 210000);
 
     return nSubsidy + nFees;
 }
@@ -865,6 +866,28 @@
             pindexBest->nTime < GetTime() - 24 * 60 * 60);
 }
 
+bool IsLockdown()
+{
+    if (!pindexBest)
+        return false;
+    return (bnBestInvalidWork > bnBestChainWork + pindexBest->GetBlockWork() * 6);
+}
+
+void Lockdown(CBlockIndex* pindexNew)
+{
+    if (pindexNew->bnChainWork > bnBestInvalidWork)
+    {
+        bnBestInvalidWork = pindexNew->bnChainWork;
+        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: IsLockdown()=%d\n", (IsLockdown() ? 1 : 0));
+    if (IsLockdown())
+        printf("Lockdown: WARNING: Displayed transactions may not be correct!  You may need to upgrade.\n");
+}
+
 
 
 
@@ -1086,7 +1109,7 @@
             return false;
     }
 
-    if (vtx[0].GetValueOut() > GetBlockValue(nFees))
+    if (vtx[0].GetValueOut() > GetBlockValue(pindex->nHeight, nFees))
         return false;
 
     // Update block index on disk without changing it in memory.
@@ -1116,11 +1139,13 @@
     CBlockIndex* plonger = pindexNew;
     while (pfork != plonger)
     {
-        if (!(pfork = pfork->pprev))
-            return error("Reorganize() : pfork->pprev is null");
         while (plonger->nHeight > pfork->nHeight)
             if (!(plonger = plonger->pprev))
                 return error("Reorganize() : plonger->pprev is null");
+        if (pfork == plonger)
+            break;
+        if (!(pfork = pfork->pprev))
+            return error("Reorganize() : pfork->pprev is null");
     }
 
     // List of what to disconnect
@@ -1160,16 +1185,8 @@
             return error("Reorganize() : ReadFromDisk for connect failed");
         if (!block.ConnectBlock(txdb, pindex))
         {
-            // Invalid block, delete the rest of this branch
+            // Invalid block
             txdb.TxnAbort();
-            for (int j = i; j < vConnect.size(); j++)
-            {
-                CBlockIndex* pindex = vConnect[j];
-                pindex->EraseBlockFromDisk();
-                txdb.EraseBlockIndex(pindex->GetBlockHash());
-                mapBlockIndex.erase(pindex->GetBlockHash());
-                delete pindex;
-            }
             return error("Reorganize() : ConnectBlock failed");
         }
 
@@ -1227,12 +1244,12 @@
     pindexNew->bnChainWork = (pindexNew->pprev ? pindexNew->pprev->bnChainWork : 0) + pindexNew->GetBlockWork();
 
     CTxDB txdb;
-    txdb.TxnBegin();
     txdb.WriteBlockIndex(CDiskBlockIndex(pindexNew));
 
     // New best
     if (pindexNew->bnChainWork > bnBestChainWork)
     {
+        txdb.TxnBegin();
         if (pindexGenesisBlock == NULL && hash == hashGenesisBlock)
         {
             pindexGenesisBlock = pindexNew;
@@ -1244,9 +1261,7 @@
             if (!ConnectBlock(txdb, pindexNew) || !txdb.WriteHashBestChain(hash))
             {
                 txdb.TxnAbort();
-                pindexNew->EraseBlockFromDisk();
-                mapBlockIndex.erase(pindexNew->GetBlockHash());
-                delete pindexNew;
+                Lockdown(pindexNew);
                 return error("AddToBlockIndex() : ConnectBlock failed");
             }
             txdb.TxnCommit();
@@ -1262,9 +1277,11 @@
             if (!Reorganize(txdb, pindexNew))
             {
                 txdb.TxnAbort();
+                Lockdown(pindexNew);
                 return error("AddToBlockIndex() : Reorganize failed");
             }
         }
+        txdb.TxnCommit();
 
         // New best block
         hashBestChain = hash;
@@ -1273,10 +1290,9 @@
         bnBestChainWork = pindexNew->bnChainWork;
         nTimeBestReceived = GetTime();
         nTransactionsUpdated++;
-        printf("AddToBlockIndex: new best=%s  height=%d\n", hashBestChain.ToString().substr(0,16).c_str(), nBestHeight);
+        printf("AddToBlockIndex: new best=%s  height=%d  work=%s\n", hashBestChain.ToString().substr(0,22).c_str(), nBestHeight, bnBestChainWork.ToString().c_str());
     }
 
-    txdb.TxnCommit();
     txdb.Close();
 
     if (pindexNew == pindexBest)
@@ -1352,7 +1368,7 @@
 
     // Check that all transactions are finalized
     foreach(const CTransaction& tx, vtx)
-        if (!tx.IsFinal(nTime))
+        if (!tx.IsFinal(pindexPrev->nHeight+1, nTime))
             return error("AcceptBlock() : contains a non-final transaction");
 
     // Check proof of work
@@ -2648,7 +2664,7 @@
             }
         }
         pblock->nBits = nBits;
-        pblock->vtx[0].vout[0].nValue = pblock->GetBlockValue(nFees);
+        pblock->vtx[0].vout[0].nValue = pblock->GetBlockValue(pindexPrev->nHeight+1, nFees);
         printf("Running BitcoinMiner with %d transactions in block\n", pblock->vtx.size());
 
 
--- a/main.h
+++ b/main.h
@@ -33,6 +33,7 @@
 extern CBlockIndex* pindexGenesisBlock;
 extern int nBestHeight;
 extern CBigNum bnBestChainWork;
+extern CBigNum bnBestInvalidWork;
 extern uint256 hashBestChain;
 extern CBlockIndex* pindexBest;
 extern unsigned int nTransactionsUpdated;
@@ -80,6 +81,7 @@
 void ThreadBitcoinMiner(void* parg);
 void BitcoinMiner();
 bool IsInitialBlockDownload();
+bool IsLockdown();
 
 
 
@@ -410,15 +412,16 @@
         return SerializeHash(*this);
     }
 
-    bool IsFinal(int64 nBlockTime=0) const
+    bool IsFinal(int nBlockHeight=0, int64 nBlockTime=0) const
     {
-        // Time based nLockTime implemented in 0.1.6,
-        // do not use time based until most 0.1.5 nodes have upgraded.
+        // Time based nLockTime implemented in 0.1.6
         if (nLockTime == 0)
             return true;
+        if (nBlockHeight == 0)
+            nBlockHeight = nBestHeight;
         if (nBlockTime == 0)
             nBlockTime = GetAdjustedTime();
-        if (nLockTime < (nLockTime < 500000000 ? nBestHeight : nBlockTime))
+        if (nLockTime < (nLockTime < 500000000 ? nBlockHeight : nBlockTime))
             return true;
         foreach(const CTxIn& txin, vin)
             if (!txin.IsFinal())
@@ -1046,7 +1049,7 @@
     }
 
 
-    int64 GetBlockValue(int64 nFees) const;
+    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);
--- a/rpc.cpp
+++ b/rpc.cpp
@@ -946,6 +946,10 @@
 
                 printf("ThreadRPCServer method=%s\n", strMethod.c_str());
 
+                // Observe lockdown
+                if (IsLockdown() && strMethod != "help" && strMethod != "stop" && strMethod != "getgenerate" && strMethod != "setgenerate")
+                    throw runtime_error("WARNING: Displayed transactions may not be correct!  You may need to upgrade.");
+
                 // Execute
                 map<string, rpcfn_type>::iterator mi = mapCallTable.find(strMethod);
                 if (mi == mapCallTable.end())
--- a/serialize.h
+++ b/serialize.h
@@ -19,7 +19,7 @@
 class CDataStream;
 class CAutoFile;
 
-static const int VERSION = 307;
+static const int VERSION = 308;
 static const char* pszSubVer = "";
 
 
--- a/setup.nsi
+++ b/setup.nsi
@@ -7,7 +7,7 @@
 
 # General Symbol Definitions
 !define REGKEY "SOFTWARE\$(^Name)"
-!define VERSION 0.3.7
+!define VERSION 0.3.8
 !define COMPANY "Bitcoin project"
 !define URL http://www.bitcoin.org/
 
@@ -42,12 +42,12 @@
 !insertmacro MUI_LANGUAGE English
 
 # Installer attributes
-OutFile bitcoin-0.3.7-win32-setup.exe
+OutFile bitcoin-0.3.8-win32-setup.exe
 InstallDir $PROGRAMFILES\Bitcoin
 CRCCheck on
 XPStyle on
 ShowInstDetails show
-VIProductVersion 0.3.7.0
+VIProductVersion 0.3.8.0
 VIAddVersionKey ProductName Bitcoin
 VIAddVersionKey ProductVersion "${VERSION}"
 VIAddVersionKey CompanyName "${COMPANY}"
--- a/ui.cpp
+++ b/ui.cpp
@@ -196,6 +196,8 @@
 
 void CalledSetStatusBar(const string& strText, int nField)
 {
+    if (nField == 0 && IsLockdown())
+        return;
     if (pframeMain && pframeMain->m_statusBar)
         pframeMain->m_statusBar->SetStatusText(strText, nField);
 }
@@ -376,7 +378,7 @@
     // to get rid of the deprecated warning.  Just ignore it.
     if (!event.Iconized())
         fClosedToTray = false;
-#ifdef __WXGTK__
+#if defined(__WXGTK__) || defined(__WXMAC_OSX__)
     if (mapArgs.count("-minimizetotray")) {
 #endif
     // The tray icon sometimes disappears on ubuntu karmic
@@ -1011,6 +1013,13 @@
     RefreshStatusColumn();
 
     // Update status bar
+    static bool fPrevLockdown;
+    if (IsLockdown())
+        m_statusBar->SetStatusText(string("    ") + _("WARNING: Displayed transactions may not be correct!  You may need to upgrade."), 0);
+    else if (fPrevLockdown)
+        m_statusBar->SetStatusText("", 0);
+    fPrevLockdown = IsLockdown();
+
     string strGen = "";
     if (fGenerateBitcoins)
         strGen = _("    Generating");
@@ -1598,7 +1607,7 @@
     //m_listBox->Append(_("Test 2"));
     m_listBox->SetSelection(0);
     SelectPage(0);
-#ifdef __WXGTK__
+#if defined(__WXGTK__) || defined(__WXMAC_OSX__)
     m_checkBoxStartOnSystemStartup->SetLabel(_("&Start Bitcoin on window system startup"));
     if (!mapArgs.count("-minimizetotray"))
     {
@@ -2697,7 +2706,7 @@
     pframeMain = new CMainFrame(NULL);
     if (mapArgs.count("-min"))
         pframeMain->Iconize(true);
-#ifdef __WXGTK__
+#if defined(__WXGTK__) || defined(__WXMAC_OSX__)
     if (!mapArgs.count("-minimizetotray"))
         fMinimizeToTray = false;
 #endif