Compare commits

...

3 Commits

Author SHA1 Message Date
Satoshi Nakamoto
b34e8c3c36 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
2010-08-04 01:51:34 +00:00
Satoshi Nakamoto
73aa262647 fixed segfault in bignum.h, additional security limits, refactoring
-- version 0.3.7
2010-07-31 20:12:05 +00:00
--author=Satoshi Nakamoto
e1cb7ce017 simplified makefile.unix, updated build-unix.txt instructions to include boost 1.37 2010-07-31 14:14:41 +00:00
13 changed files with 128 additions and 83 deletions

View File

@@ -401,8 +401,16 @@ public:
CBigNum& operator>>=(unsigned int shift)
{
// Note: BN_rshift segfaults on 64-bit ubuntu 9.10 if 2^shift is greater than the number,
// tested OK on 64-bit ubuntu 10.4
// Note: BN_rshift segfaults on 64-bit if 2^shift is greater than the number
// if built on ubuntu 9.04 or 9.10, probably depends on version of openssl
CBigNum a = 1;
a <<= shift;
if (BN_cmp(&a, this) > 0)
{
*this = 0;
return *this;
}
if (!BN_rshift(this, this, shift))
throw bignum_error("CBigNum:operator>>= : BN_rshift failed");
return *this;
@@ -511,10 +519,8 @@ inline const CBigNum operator<<(const CBigNum& a, unsigned int shift)
inline const CBigNum operator>>(const CBigNum& a, unsigned int shift)
{
CBigNum r;
// Note: BN_rshift segfaults on 64-bit ubuntu 9.10 if 2^shift is greater than the number
if (!BN_rshift(&r, &a, shift))
throw bignum_error("CBigNum:operator>> : BN_rshift failed");
CBigNum r = a;
r >>= shift;
return r;
}

View File

@@ -16,13 +16,12 @@ sudo apt-get install libgtk2.0-dev
sudo apt-get install libssl-dev
sudo apt-get install libdb4.7-dev
sudo apt-get install libdb4.7++-dev
sudo apt-get install libboost-all-dev
Boost 1.40+: sudo apt-get install libboost-all-dev
or Boost 1.37: sudo apt-get install libboost1.37-dev
We're now using wxWidgets 2.9, which uses UTF-8.
If using Boost 1.37, append -mt to the boost libraries in the makefile.
There isn't currently a debian package of wxWidgets we can use. The 2.8
packages for Karmic are UTF-16 unicode and won't work for us, and we've had
trouble building 2.8 on 64-bit.
We're now using wxWidgets 2.9, which uses UTF-8. Don't try 2.8, it won't work.
You need to download wxWidgets from http://www.wxwidgets.org/downloads/
and build it yourself. See the build instructions and configure parameters
@@ -34,11 +33,11 @@ Berkeley DB New BSD license with additional requirement that linked software
Boost MIT-like license
Versions used in this release:
GCC 4.4.3
OpenSSL 0.9.8k
GCC 4.3.3
OpenSSL 0.9.8g
wxWidgets 2.9.0
Berkeley DB 4.7.25.NC
Boost 1.40.0
Boost 1.37
Notes
@@ -55,7 +54,7 @@ wxWidgets
---------
cd /usr/local
tar -xzvf wxWidgets-2.9.0.tar.gz
cd /usr/local/wxWidgets-2.9.0
cd wxWidgets-2.9.0
mkdir buildgtk
cd buildgtk
../configure --with-gtk --enable-debug --disable-shared --enable-monolithic
@@ -63,15 +62,6 @@ make
sudo su
make install
ldconfig
su <username>
cd ..
mkdir buildbase
cd buildbase
../configure --disable-gui --enable-debug --disable-shared --enable-monolithic
make
sudo su
make install
ldconfig
Boost

13
db.cpp
View File

@@ -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;
}

2
db.h
View File

@@ -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();
};

View File

@@ -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());
@@ -3036,7 +3052,8 @@ bool CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, CK
foreach(CWalletTx* pcoin, setCoins)
for (int nOut = 0; nOut < pcoin->vout.size(); nOut++)
if (pcoin->vout[nOut].IsMine())
SignSignature(*pcoin, wtxNew, nIn++);
if (!SignSignature(*pcoin, wtxNew, nIn++))
return false;
// Check that enough fee is included
if (nFee < wtxNew.GetMinFee())

13
main.h
View File

@@ -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);

View File

@@ -4,20 +4,16 @@
INCLUDEPATHS= \
-I"/usr/include" \
-I"/usr/local/include/wx-2.9" \
-I"/usr/local/lib/wx/include/gtk2-unicode-debug-static-2.9"
LIBPATHS= \
-L"/usr/lib" \
-L"/usr/local/lib"
WXLIBS= \
-Wl,-Bstatic \
-l wx_gtk2ud-2.9 \
-Wl,-Bdynamic \
-l gtk-x11-2.0 -l SM
# for boost 1.37, add -mt to the boost libraries
LIBS= \
-Wl,-Bstatic \
-l boost_system \
@@ -51,24 +47,21 @@ OBJS= \
all: bitcoin
headers.h.gch: headers.h $(HEADERS)
g++ -c $(CFLAGS) -DGUI -o $@ $<
obj/%.o: %.cpp $(HEADERS) headers.h.gch
obj/%.o: %.cpp $(HEADERS)
g++ -c $(CFLAGS) -DGUI -o $@ $<
cryptopp/obj/%.o: cryptopp/%.cpp
g++ -c $(CFLAGS) -O3 -DCRYPTOPP_DISABLE_SSE2 -o $@ $<
bitcoin: $(OBJS) obj/ui.o obj/uibase.o
g++ $(CFLAGS) -o $@ $(LIBPATHS) $^ $(WXLIBS) $(LIBS)
g++ $(CFLAGS) -o $@ $^ $(WXLIBS) $(LIBS)
obj/nogui/%.o: %.cpp $(HEADERS)
g++ -c $(CFLAGS) -o $@ $<
bitcoind: $(OBJS:obj/%=obj/nogui/%)
g++ $(CFLAGS) -o $@ $(LIBPATHS) $^ $(LIBS)
g++ $(CFLAGS) -o $@ $^ $(LIBS)
clean:

View File

@@ -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())

View File

@@ -42,20 +42,17 @@ void MakeSameSize(valtype& vch1, valtype& vch2)
#define stacktop(i) (stack.at(stack.size()+(i)))
#define altstacktop(i) (altstack.at(altstack.size()+(i)))
bool EvalScript(const CScript& script, const CTransaction& txTo, unsigned int nIn, int nHashType,
vector<vector<unsigned char> >* pvStackRet)
bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, const CTransaction& txTo, unsigned int nIn, int nHashType)
{
CAutoBN_CTX pctx;
CScript::const_iterator pc = script.begin();
CScript::const_iterator pend = script.end();
CScript::const_iterator pbegincodehash = script.begin();
vector<bool> vfExec;
vector<valtype> stack;
vector<valtype> altstack;
if (pvStackRet)
pvStackRet->clear();
if (script.size() > 20000)
if (script.size() > 10000)
return false;
int nOpCount = 0;
try
@@ -73,6 +70,8 @@ bool EvalScript(const CScript& script, const CTransaction& txTo, unsigned int nI
return false;
if (vchPushValue.size() > 5000)
return false;
if (opcode > OP_16 && nOpCount++ > 200)
return false;
if (fExec && opcode <= OP_PUSHDATA4)
stack.push_back(vchPushValue);
@@ -828,9 +827,7 @@ bool EvalScript(const CScript& script, const CTransaction& txTo, unsigned int nI
if (!vfExec.empty())
return false;
if (pvStackRet)
*pvStackRet = stack;
return (stack.empty() ? false : CastToBool(stack.back()));
return true;
}
#undef top
@@ -1114,6 +1111,19 @@ bool ExtractHash160(const CScript& scriptPubKey, uint160& hash160Ret)
}
bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, int nHashType)
{
vector<vector<unsigned char> > stack;
if (!EvalScript(stack, scriptSig, txTo, nIn, nHashType))
return false;
if (!EvalScript(stack, scriptPubKey, txTo, nIn, nHashType))
return false;
if (stack.empty())
return false;
return CastToBool(stack.back());
}
bool SignSignature(const CTransaction& txFrom, CTransaction& txTo, unsigned int nIn, int nHashType, CScript scriptPrereq)
{
assert(nIn < txTo.vin.size());
@@ -1132,7 +1142,7 @@ bool SignSignature(const CTransaction& txFrom, CTransaction& txTo, unsigned int
// Test solution
if (scriptPrereq.empty())
if (!EvalScript(txin.scriptSig + CScript(OP_CODESEPARATOR) + txout.scriptPubKey, txTo, nIn))
if (!VerifyScript(txin.scriptSig, txout.scriptPubKey, txTo, nIn, 0))
return false;
return true;
@@ -1150,7 +1160,7 @@ bool VerifySignature(const CTransaction& txFrom, const CTransaction& txTo, unsig
if (txin.prevout.hash != txFrom.GetHash())
return false;
if (!EvalScript(txin.scriptSig + CScript(OP_CODESEPARATOR) + txout.scriptPubKey, txTo, nIn, nHashType))
if (!VerifyScript(txin.scriptSig, txout.scriptPubKey, txTo, nIn, nHashType))
return false;
// Anytime a signature is successfully verified, it's proof the outpoint is spent,

View File

@@ -657,8 +657,6 @@ public:
bool EvalScript(const CScript& script, const CTransaction& txTo, unsigned int nIn, int nHashType=0,
vector<vector<unsigned char> >* pvStackRet=NULL);
uint256 SignatureHash(CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType);
bool IsMine(const CScript& scriptPubKey);
bool ExtractPubKey(const CScript& scriptPubKey, bool fMineOnly, vector<unsigned char>& vchPubKeyRet);

View File

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

View File

@@ -7,7 +7,7 @@ RequestExecutionLevel highest
# General Symbol Definitions
!define REGKEY "SOFTWARE\$(^Name)"
!define VERSION 0.3.6
!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.6-win32-setup.exe
OutFile bitcoin-0.3.8-win32-setup.exe
InstallDir $PROGRAMFILES\Bitcoin
CRCCheck on
XPStyle on
ShowInstDetails show
VIProductVersion 0.3.6.0
VIProductVersion 0.3.8.0
VIAddVersionKey ProductName Bitcoin
VIAddVersionKey ProductVersion "${VERSION}"
VIAddVersionKey CompanyName "${COMPANY}"

15
ui.cpp
View File

@@ -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