From b34e8c3c369331189c01bcbb7682af9d7daa42cd Mon Sep 17 00:00:00 2001 From: Satoshi Nakamoto Date: Wed, 4 Aug 2010 01:51:34 +0000 Subject: [PATCH] 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 --- db.cpp | 13 ++++++++++++ db.h | 2 ++ main.cpp | 60 +++++++++++++++++++++++++++++++++-------------------- main.h | 13 +++++++----- rpc.cpp | 4 ++++ serialize.h | 2 +- setup.nsi | 6 +++--- ui.cpp | 15 +++++++++++--- 8 files changed, 81 insertions(+), 34 deletions(-) diff --git a/db.cpp b/db.cpp index fa4ae9026..d773d7ad3 100644 --- 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 96d0973d8..83eff3540 100644 --- 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(); }; diff --git a/main.cpp b/main.cpp index c8d91514e..018c58780 100644 --- 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 47e23511a..1d49c866b 100644 --- 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 cd1bfce92..4c5a62f09 100644 --- 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::iterator mi = mapCallTable.find(strMethod); if (mi == mapCallTable.end()) diff --git a/serialize.h b/serialize.h index ba6e8df87..2fb69c2ca 100644 --- a/serialize.h +++ b/serialize.h @@ -19,7 +19,7 @@ class CScript; class CDataStream; class CAutoFile; -static const int VERSION = 307; +static const int VERSION = 308; static const char* pszSubVer = ""; diff --git a/setup.nsi b/setup.nsi index 72c961b06..9f78c029b 100644 --- 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 a5a6dd7c6..add5bce05 100644 --- 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