new safety feature displays a warning message and locks down RPC if it detects a...
authorSatoshi Nakamoto <satoshin@gmx.com>
Wed, 4 Aug 2010 01:51:34 +0000 (01:51 +0000)
committerGavin Andresen <gavinandresen@gmail.com>
Wed, 4 Aug 2010 01:51:34 +0000 (01:51 +0000)
-- version 0.3.8

db.cpp
db.h
main.cpp
main.h
rpc.cpp
serialize.h
setup.nsi
ui.cpp

diff --git a/db.cpp b/db.cpp
index fa4ae90..d773d7a 100644 (file)
--- a/db.cpp
+++ b/db.cpp
@@ -342,6 +342,16 @@ bool CTxDB::WriteHashBestChain(uint256 hashBestChain)
     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 @@ bool CTxDB::LoadBlockIndex()
     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;
 }
 
diff --git a/db.h b/db.h
index 96d0973..83eff35 100644 (file)
--- a/db.h
+++ b/db.h
@@ -280,6 +280,8 @@ public:
     bool EraseBlockIndex(uint256 hash);
     bool ReadHashBestChain(uint256& hashBestChain);
     bool WriteHashBestChain(uint256 hashBestChain);
+    bool ReadBestInvalidWork(CBigNum& bnBestInvalidWork);
+    bool WriteBestInvalidWork(CBigNum bnBestInvalidWork);
     bool LoadBlockIndex();
 };
 
index c8d9151..018c587 100644 (file)
--- a/main.cpp
+++ b/main.cpp
@@ -25,6 +25,7 @@ const uint256 hashGenesisBlock("0x000000000019d6689c085ae165831e934ff763ae46a2a6
 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 @@ uint256 GetOrphanRoot(const CBlock* pblock)
     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 @@ bool IsInitialBlockDownload()
             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 @@ bool CBlock::ConnectBlock(CTxDB& txdb, CBlockIndex* pindex)
             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 @@ bool Reorganize(CTxDB& txdb, CBlockIndex* pindexNew)
     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 @@ bool Reorganize(CTxDB& txdb, CBlockIndex* pindexNew)
             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 @@ bool CBlock::AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos)
     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 @@ bool CBlock::AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos)
             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 @@ bool CBlock::AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos)
             if (!Reorganize(txdb, pindexNew))
             {
                 txdb.TxnAbort();
+                Lockdown(pindexNew);
                 return error("AddToBlockIndex() : Reorganize failed");
             }
         }
+        txdb.TxnCommit();
 
         // New best block
         hashBestChain = hash;
@@ -1273,10 +1290,9 @@ bool CBlock::AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos)
         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 @@ bool CBlock::AcceptBlock()
 
     // 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 @@ void BitcoinMiner()
             }
         }
         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());
 
 
diff --git a/main.h b/main.h
index 47e2351..1d49c86 100644 (file)
--- a/main.h
+++ b/main.h
@@ -33,6 +33,7 @@ extern const uint256 hashGenesisBlock;
 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 GenerateBitcoins(bool fGenerate);
 void ThreadBitcoinMiner(void* parg);
 void BitcoinMiner();
 bool IsInitialBlockDownload();
+bool IsLockdown();
 
 
 
@@ -410,15 +412,16 @@ public:
         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 @@ public:
     }
 
 
-    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);
diff --git a/rpc.cpp b/rpc.cpp
index cd1bfce..4c5a62f 100644 (file)
--- a/rpc.cpp
+++ b/rpc.cpp
@@ -946,6 +946,10 @@ void ThreadRPCServer2(void* parg)
 
                 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())
index ba6e8df..2fb69c2 100644 (file)
@@ -19,7 +19,7 @@ class CScript;
 class CDataStream;
 class CAutoFile;
 
-static const int VERSION = 307;
+static const int VERSION = 308;
 static const char* pszSubVer = "";
 
 
index 72c961b..9f78c02 100644 (file)
--- a/setup.nsi
+++ b/setup.nsi
@@ -7,7 +7,7 @@ RequestExecutionLevel highest
 
 # 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 @@ Var StartMenuGroup
 !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}"
diff --git a/ui.cpp b/ui.cpp
index a5a6dd7..add5bce 100644 (file)
--- a/ui.cpp
+++ b/ui.cpp
@@ -196,6 +196,8 @@ bool ThreadSafeAskFee(int64 nFeeRequired, const string& strCaption, wxWindow* pa
 
 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 @@ void CMainFrame::OnIconize(wxIconizeEvent& event)
     // 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 @@ void CMainFrame::OnPaintListCtrl(wxPaintEvent& event)
     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 @@ COptionsDialog::COptionsDialog(wxWindow* parent) : COptionsDialogBase(parent)
     //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 @@ void CreateMainWindow()
     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