Browse Source

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
0.8 v0.3.8
Satoshi Nakamoto 15 years ago committed by Gavin Andresen
parent
commit
b34e8c3c36
  1. 13
      db.cpp
  2. 2
      db.h
  3. 60
      main.cpp
  4. 13
      main.h
  5. 4
      rpc.cpp
  6. 2
      serialize.h
  7. 6
      setup.nsi
  8. 15
      ui.cpp

13
db.cpp

@ -342,6 +342,16 @@ bool CTxDB::WriteHashBestChain(uint256 hashBestChain)
return Write(string("hashBestChain"), 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) CBlockIndex* InsertBlockIndex(uint256 hash)
{ {
if (hash == 0) if (hash == 0)
@ -446,6 +456,9 @@ bool CTxDB::LoadBlockIndex()
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,16).c_str(), nBestHeight);
// Load bnBestInvalidWork, OK if it doesn't exist
ReadBestInvalidWork(bnBestInvalidWork);
return true; return true;
} }

2
db.h

@ -280,6 +280,8 @@ public:
bool EraseBlockIndex(uint256 hash); bool EraseBlockIndex(uint256 hash);
bool ReadHashBestChain(uint256& hashBestChain); bool ReadHashBestChain(uint256& hashBestChain);
bool WriteHashBestChain(uint256 hashBestChain); bool WriteHashBestChain(uint256 hashBestChain);
bool ReadBestInvalidWork(CBigNum& bnBestInvalidWork);
bool WriteBestInvalidWork(CBigNum bnBestInvalidWork);
bool LoadBlockIndex(); bool LoadBlockIndex();
}; };

60
main.cpp

@ -25,6 +25,7 @@ const uint256 hashGenesisBlock("0x000000000019d6689c085ae165831e934ff763ae46a2a6
CBlockIndex* pindexGenesisBlock = NULL; CBlockIndex* pindexGenesisBlock = NULL;
int nBestHeight = -1; int nBestHeight = -1;
CBigNum bnBestChainWork = 0; CBigNum bnBestChainWork = 0;
CBigNum bnBestInvalidWork = 0;
uint256 hashBestChain = 0; uint256 hashBestChain = 0;
CBlockIndex* pindexBest = NULL; CBlockIndex* pindexBest = NULL;
int64 nTimeBestReceived = 0; int64 nTimeBestReceived = 0;
@ -794,12 +795,12 @@ uint256 GetOrphanRoot(const CBlock* pblock)
return pblock->GetHash(); return pblock->GetHash();
} }
int64 CBlock::GetBlockValue(int64 nFees) const int64 CBlock::GetBlockValue(int nHeight, int64 nFees) const
{ {
int64 nSubsidy = 50 * COIN; int64 nSubsidy = 50 * COIN;
// Subsidy is cut in half every 4 years // Subsidy is cut in half every 4 years
nSubsidy >>= (nBestHeight / 210000); nSubsidy >>= (nHeight / 210000);
return nSubsidy + nFees; return nSubsidy + nFees;
} }
@ -865,6 +866,28 @@ bool IsInitialBlockDownload()
pindexBest->nTime < GetTime() - 24 * 60 * 60); 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; return false;
} }
if (vtx[0].GetValueOut() > GetBlockValue(nFees)) if (vtx[0].GetValueOut() > GetBlockValue(pindex->nHeight, nFees))
return false; return false;
// Update block index on disk without changing it in memory. // Update block index on disk without changing it in memory.
@ -1116,11 +1139,13 @@ bool Reorganize(CTxDB& txdb, CBlockIndex* pindexNew)
CBlockIndex* plonger = pindexNew; CBlockIndex* plonger = pindexNew;
while (pfork != plonger) while (pfork != plonger)
{ {
if (!(pfork = pfork->pprev))
return error("Reorganize() : pfork->pprev is null");
while (plonger->nHeight > pfork->nHeight) while (plonger->nHeight > pfork->nHeight)
if (!(plonger = plonger->pprev)) if (!(plonger = plonger->pprev))
return error("Reorganize() : plonger->pprev is null"); 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 // List of what to disconnect
@ -1160,16 +1185,8 @@ bool Reorganize(CTxDB& txdb, CBlockIndex* pindexNew)
return error("Reorganize() : ReadFromDisk for connect failed"); return error("Reorganize() : ReadFromDisk for connect failed");
if (!block.ConnectBlock(txdb, pindex)) if (!block.ConnectBlock(txdb, pindex))
{ {
// Invalid block, delete the rest of this branch // Invalid block
txdb.TxnAbort(); 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"); 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(); pindexNew->bnChainWork = (pindexNew->pprev ? pindexNew->pprev->bnChainWork : 0) + pindexNew->GetBlockWork();
CTxDB txdb; CTxDB txdb;
txdb.TxnBegin();
txdb.WriteBlockIndex(CDiskBlockIndex(pindexNew)); txdb.WriteBlockIndex(CDiskBlockIndex(pindexNew));
// New best // New best
if (pindexNew->bnChainWork > bnBestChainWork) if (pindexNew->bnChainWork > bnBestChainWork)
{ {
txdb.TxnBegin();
if (pindexGenesisBlock == NULL && hash == hashGenesisBlock) if (pindexGenesisBlock == NULL && hash == hashGenesisBlock)
{ {
pindexGenesisBlock = pindexNew; pindexGenesisBlock = pindexNew;
@ -1244,9 +1261,7 @@ bool CBlock::AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos)
if (!ConnectBlock(txdb, pindexNew) || !txdb.WriteHashBestChain(hash)) if (!ConnectBlock(txdb, pindexNew) || !txdb.WriteHashBestChain(hash))
{ {
txdb.TxnAbort(); txdb.TxnAbort();
pindexNew->EraseBlockFromDisk(); Lockdown(pindexNew);
mapBlockIndex.erase(pindexNew->GetBlockHash());
delete pindexNew;
return error("AddToBlockIndex() : ConnectBlock failed"); return error("AddToBlockIndex() : ConnectBlock failed");
} }
txdb.TxnCommit(); txdb.TxnCommit();
@ -1262,9 +1277,11 @@ bool CBlock::AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos)
if (!Reorganize(txdb, pindexNew)) if (!Reorganize(txdb, pindexNew))
{ {
txdb.TxnAbort(); txdb.TxnAbort();
Lockdown(pindexNew);
return error("AddToBlockIndex() : Reorganize failed"); return error("AddToBlockIndex() : Reorganize failed");
} }
} }
txdb.TxnCommit();
// New best block // New best block
hashBestChain = hash; hashBestChain = hash;
@ -1273,10 +1290,9 @@ bool CBlock::AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos)
bnBestChainWork = pindexNew->bnChainWork; bnBestChainWork = pindexNew->bnChainWork;
nTimeBestReceived = GetTime(); nTimeBestReceived = GetTime();
nTransactionsUpdated++; 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(); txdb.Close();
if (pindexNew == pindexBest) if (pindexNew == pindexBest)
@ -1352,7 +1368,7 @@ bool CBlock::AcceptBlock()
// 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(nTime)) if (!tx.IsFinal(pindexPrev->nHeight+1, nTime))
return error("AcceptBlock() : contains a non-final transaction"); return error("AcceptBlock() : contains a non-final transaction");
// Check proof of work // Check proof of work
@ -2648,7 +2664,7 @@ void BitcoinMiner()
} }
} }
pblock->nBits = nBits; 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()); printf("Running BitcoinMiner with %d transactions in block\n", pblock->vtx.size());

13
main.h

@ -33,6 +33,7 @@ extern const uint256 hashGenesisBlock;
extern CBlockIndex* pindexGenesisBlock; extern CBlockIndex* pindexGenesisBlock;
extern int nBestHeight; extern int nBestHeight;
extern CBigNum bnBestChainWork; extern CBigNum bnBestChainWork;
extern CBigNum bnBestInvalidWork;
extern uint256 hashBestChain; extern uint256 hashBestChain;
extern CBlockIndex* pindexBest; extern CBlockIndex* pindexBest;
extern unsigned int nTransactionsUpdated; extern unsigned int nTransactionsUpdated;
@ -80,6 +81,7 @@ void GenerateBitcoins(bool fGenerate);
void ThreadBitcoinMiner(void* parg); void ThreadBitcoinMiner(void* parg);
void BitcoinMiner(); void BitcoinMiner();
bool IsInitialBlockDownload(); bool IsInitialBlockDownload();
bool IsLockdown();
@ -410,15 +412,16 @@ public:
return SerializeHash(*this); 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, // Time based nLockTime implemented in 0.1.6
// do not use time based until most 0.1.5 nodes have upgraded.
if (nLockTime == 0) if (nLockTime == 0)
return true; return true;
if (nBlockHeight == 0)
nBlockHeight = nBestHeight;
if (nBlockTime == 0) if (nBlockTime == 0)
nBlockTime = GetAdjustedTime(); nBlockTime = GetAdjustedTime();
if (nLockTime < (nLockTime < 500000000 ? nBestHeight : nBlockTime)) if (nLockTime < (nLockTime < 500000000 ? nBlockHeight : nBlockTime))
return true; return true;
foreach(const CTxIn& txin, vin) foreach(const CTxIn& txin, vin)
if (!txin.IsFinal()) 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 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* blockindex, bool fReadTransactions=true);

4
rpc.cpp

@ -946,6 +946,10 @@ void ThreadRPCServer2(void* parg)
printf("ThreadRPCServer method=%s\n", strMethod.c_str()); 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 // Execute
map<string, rpcfn_type>::iterator mi = mapCallTable.find(strMethod); map<string, rpcfn_type>::iterator mi = mapCallTable.find(strMethod);
if (mi == mapCallTable.end()) if (mi == mapCallTable.end())

2
serialize.h

@ -19,7 +19,7 @@ class CScript;
class CDataStream; class CDataStream;
class CAutoFile; class CAutoFile;
static const int VERSION = 307; static const int VERSION = 308;
static const char* pszSubVer = ""; static const char* pszSubVer = "";

6
setup.nsi

@ -7,7 +7,7 @@ RequestExecutionLevel highest
# General Symbol Definitions # General Symbol Definitions
!define REGKEY "SOFTWARE\$(^Name)" !define REGKEY "SOFTWARE\$(^Name)"
!define VERSION 0.3.7 !define VERSION 0.3.8
!define COMPANY "Bitcoin project" !define COMPANY "Bitcoin project"
!define URL http://www.bitcoin.org/ !define URL http://www.bitcoin.org/
@ -42,12 +42,12 @@ Var StartMenuGroup
!insertmacro MUI_LANGUAGE English !insertmacro MUI_LANGUAGE English
# Installer attributes # Installer attributes
OutFile bitcoin-0.3.7-win32-setup.exe OutFile bitcoin-0.3.8-win32-setup.exe
InstallDir $PROGRAMFILES\Bitcoin InstallDir $PROGRAMFILES\Bitcoin
CRCCheck on CRCCheck on
XPStyle on XPStyle on
ShowInstDetails show ShowInstDetails show
VIProductVersion 0.3.7.0 VIProductVersion 0.3.8.0
VIAddVersionKey ProductName Bitcoin VIAddVersionKey ProductName Bitcoin
VIAddVersionKey ProductVersion "${VERSION}" VIAddVersionKey ProductVersion "${VERSION}"
VIAddVersionKey CompanyName "${COMPANY}" VIAddVersionKey CompanyName "${COMPANY}"

15
ui.cpp

@ -196,6 +196,8 @@ bool ThreadSafeAskFee(int64 nFeeRequired, const string& strCaption, wxWindow* pa
void CalledSetStatusBar(const string& strText, int nField) void CalledSetStatusBar(const string& strText, int nField)
{ {
if (nField == 0 && IsLockdown())
return;
if (pframeMain && pframeMain->m_statusBar) if (pframeMain && pframeMain->m_statusBar)
pframeMain->m_statusBar->SetStatusText(strText, nField); 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. // to get rid of the deprecated warning. Just ignore it.
if (!event.Iconized()) if (!event.Iconized())
fClosedToTray = false; fClosedToTray = false;
#ifdef __WXGTK__ #if defined(__WXGTK__) || defined(__WXMAC_OSX__)
if (mapArgs.count("-minimizetotray")) { if (mapArgs.count("-minimizetotray")) {
#endif #endif
// The tray icon sometimes disappears on ubuntu karmic // The tray icon sometimes disappears on ubuntu karmic
@ -1011,6 +1013,13 @@ void CMainFrame::OnPaintListCtrl(wxPaintEvent& event)
RefreshStatusColumn(); RefreshStatusColumn();
// Update status bar // 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 = ""; string strGen = "";
if (fGenerateBitcoins) if (fGenerateBitcoins)
strGen = _(" Generating"); strGen = _(" Generating");
@ -1598,7 +1607,7 @@ COptionsDialog::COptionsDialog(wxWindow* parent) : COptionsDialogBase(parent)
//m_listBox->Append(_("Test 2")); //m_listBox->Append(_("Test 2"));
m_listBox->SetSelection(0); m_listBox->SetSelection(0);
SelectPage(0); SelectPage(0);
#ifdef __WXGTK__ #if defined(__WXGTK__) || defined(__WXMAC_OSX__)
m_checkBoxStartOnSystemStartup->SetLabel(_("&Start Bitcoin on window system startup")); m_checkBoxStartOnSystemStartup->SetLabel(_("&Start Bitcoin on window system startup"));
if (!mapArgs.count("-minimizetotray")) if (!mapArgs.count("-minimizetotray"))
{ {
@ -2697,7 +2706,7 @@ void CreateMainWindow()
pframeMain = new CMainFrame(NULL); pframeMain = new CMainFrame(NULL);
if (mapArgs.count("-min")) if (mapArgs.count("-min"))
pframeMain->Iconize(true); pframeMain->Iconize(true);
#ifdef __WXGTK__ #if defined(__WXGTK__) || defined(__WXMAC_OSX__)
if (!mapArgs.count("-minimizetotray")) if (!mapArgs.count("-minimizetotray"))
fMinimizeToTray = false; fMinimizeToTray = false;
#endif #endif

Loading…
Cancel
Save