Merge branch '0.6.0.x' into 0.6.x
authorLuke Dashjr <luke-jr+git@utopios.org>
Tue, 22 May 2012 23:07:46 +0000 (23:07 +0000)
committerLuke Dashjr <luke-jr+git@utopios.org>
Tue, 22 May 2012 23:07:46 +0000 (23:07 +0000)
Conflicts:
bitcoin-qt.pro
doc/README
doc/README_windows.txt
share/setup.nsi
src/bitcoinrpc.h
src/db.h
src/headers.h
src/init.cpp
src/main.cpp
src/main.h
src/noui.h
src/qt/bitcoin.cpp
src/qt/locale/bitcoin_en.ts
src/qt/walletmodel.cpp
src/script.cpp
src/ui_interface.h
src/util.cpp

13 files changed:
.gitignore
doc/build-unix.txt
src/bitcoinrpc.cpp
src/db.cpp
src/db.h
src/main.cpp
src/main.h
src/qt/bitcoinaddressvalidator.cpp
src/qt/bitcoingui.cpp
src/qt/csvmodelwriter.cpp
src/qt/forms/askpassphrasedialog.ui
src/qt/optionsdialog.cpp
src/wallet.cpp

index dafbc2b..fe93caa 100644 (file)
@@ -20,3 +20,4 @@ qrc_*.cpp
 *.pro.user
 #mac specific
 .DS_Store
+build
index c5b4205..a9bc551 100644 (file)
@@ -40,7 +40,7 @@ turned off by default.  Set USE_UPNP to a different value to control this:
 libqrencode may be used for QRCode image generation. It can be downloaded
 from http://fukuchi.org/works/qrencode/index.html.en, or installed via
 your package manager. Set USE_QRCODE to control this:
- USE_QRCODE=0   (the default) No QRCode support - libarcode not required
+ USE_QRCODE=0   (the default) No QRCode support - libqrcode not required
  USE_QRCODE=1   QRCode support enabled
 
 Licenses of statically linked libraries:
index cf6e4fb..a954050 100644 (file)
@@ -839,7 +839,8 @@ Value movecmd(const Array& params, bool fHelp)
         strComment = params[4].get_str();
 
     CWalletDB walletdb(pwalletMain->strWalletFile);
-    walletdb.TxnBegin();
+    if (!walletdb.TxnBegin())
+        throw JSONRPCError(-20, "database error");
 
     int64 nNow = GetAdjustedTime();
 
@@ -861,7 +862,8 @@ Value movecmd(const Array& params, bool fHelp)
     credit.strComment = strComment;
     walletdb.WriteAccountingEntry(credit);
 
-    walletdb.TxnCommit();
+    if (!walletdb.TxnCommit())
+        throw JSONRPCError(-20, "database error");
 
     return true;
 }
index 4d2965f..2d9d552 100644 (file)
@@ -410,9 +410,15 @@ bool CTxDB::ReadOwnerTxes(uint160 hash160, int nMinHeight, vector<CTransaction>&
         string strType;
         uint160 hashItem;
         CDiskTxPos pos;
-        ssKey >> strType >> hashItem >> pos;
         int nItemHeight;
-        ssValue >> nItemHeight;
+
+        try {
+            ssKey >> strType >> hashItem >> pos;
+            ssValue >> nItemHeight;
+        }
+        catch (std::exception &e) {
+            return error("%s() : deserialize error", __PRETTY_FUNCTION__);
+        }
 
         // Read transaction
         if (strType != "owner" || hashItem != hash160)
@@ -532,6 +538,8 @@ bool CTxDB::LoadBlockIndex()
             return false;
 
         // Unserialize
+
+        try {
         string strType;
         ssKey >> strType;
         if (strType == "blockindex" && !fRequestShutdown)
@@ -563,6 +571,10 @@ bool CTxDB::LoadBlockIndex()
         {
             break; // if shutdown requested or finished loading block index
         }
+        }    // try
+        catch (std::exception &e) {
+            return error("%s() : deserialize error", __PRETTY_FUNCTION__);
+        }
     }
     pcursor->close();
 
index ae0ffd2..faba824 100644 (file)
--- a/src/db.h
+++ b/src/db.h
@@ -72,8 +72,13 @@ protected:
             return false;
 
         // Unserialize value
-        CDataStream ssValue((char*)datValue.get_data(), (char*)datValue.get_data() + datValue.get_size(), SER_DISK, CLIENT_VERSION);
-        ssValue >> value;
+        try {
+            CDataStream ssValue((char*)datValue.get_data(), (char*)datValue.get_data() + datValue.get_size(), SER_DISK, CLIENT_VERSION);
+            ssValue >> value;
+        }
+        catch (std::exception &e) {
+            return false;
+        }
 
         // Clear and free memory
         memset(datValue.get_data(), 0, datValue.get_size());
index ad5ab6e..6e5f9fb 100644 (file)
@@ -1490,7 +1490,9 @@ bool CBlock::SetBestChain(CTxDB& txdb, CBlockIndex* pindexNew)
 {
     uint256 hash = GetHash();
 
-    txdb.TxnBegin();
+    if (!txdb.TxnBegin())
+        return error("SetBestChain() : TxnBegin failed");
+
     if (pindexGenesisBlock == NULL && hash == hashGenesisBlock)
     {
         txdb.WriteHashBestChain(hash);
@@ -1539,7 +1541,10 @@ bool CBlock::SetBestChain(CTxDB& txdb, CBlockIndex* pindexNew)
                 printf("SetBestChain() : ReadFromDisk failed\n");
                 break;
             }
-            txdb.TxnBegin();
+            if (!txdb.TxnBegin()) {
+                printf("SetBestChain() : TxnBegin 2 failed\n");
+                break;
+            }
             // errors now are not fatal, we still did a reorganisation to a new chain in a valid way
             if (!block.SetBestChainInner(txdb, pindex))
                 break;
@@ -1597,7 +1602,8 @@ bool CBlock::AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos)
     pindexNew->bnChainWork = (pindexNew->pprev ? pindexNew->pprev->bnChainWork : 0) + pindexNew->GetBlockWork();
 
     CTxDB txdb;
-    txdb.TxnBegin();
+    if (!txdb.TxnBegin())
+        return false;
     txdb.WriteBlockIndex(CDiskBlockIndex(pindexNew));
     if (!txdb.TxnCommit())
         return false;
@@ -1825,7 +1831,7 @@ bool CheckDiskSpace(uint64 nAdditionalBytes)
     if (nFreeBytesAvailable < (uint64)15000000 + nAdditionalBytes)
     {
         fShutdown = true;
-        string strMessage = _("Warning: Disk space is low  ");
+        string strMessage = _("Warning: Disk space is low");
         strMiscWarning = strMessage;
         printf("*** %s\n", strMessage.c_str());
         ThreadSafeMessageBox(strMessage, "Bitcoin", wxOK | wxICON_EXCLAMATION | wxMODAL);
@@ -2392,6 +2398,14 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
             return error("message inv size() = %d", vInv.size());
         }
 
+        // find last block in inv vector
+        unsigned int nLastBlock = (unsigned int)(-1);
+        for (unsigned int nInv = 0; nInv < vInv.size(); nInv++) {
+            if (vInv[vInv.size() - 1 - nInv].type == MSG_BLOCK) {
+                nLastBlock = vInv.size() - 1 - nInv;
+                break;
+            }
+        }
         CTxDB txdb("r");
         for (unsigned int nInv = 0; nInv < vInv.size(); nInv++)
         {
@@ -2405,13 +2419,19 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
             if (fDebug)
                 printf("  got inventory: %s  %s\n", inv.ToString().c_str(), fAlreadyHave ? "have" : "new");
 
-            // Always request the last block in an inv bundle (even if we already have it), as it is the
-            // trigger for the other side to send further invs. If we are stuck on a (very long) side chain,
-            // this is necessary to connect earlier received orphan blocks to the chain again.
-            if (!fAlreadyHave || (inv.type == MSG_BLOCK && nInv==vInv.size()-1))
+            if (!fAlreadyHave)
                 pfrom->AskFor(inv);
-            if (inv.type == MSG_BLOCK && mapOrphanBlocks.count(inv.hash))
+            else if (inv.type == MSG_BLOCK && mapOrphanBlocks.count(inv.hash)) {
                 pfrom->PushGetBlocks(pindexBest, GetOrphanRoot(mapOrphanBlocks[inv.hash]));
+            } else if (nInv == nLastBlock) {
+                // In case we are on a very long side-chain, it is possible that we already have
+                // the last block in an inv bundle sent in response to getblocks. Try to detect
+                // this situation and push another getblocks to continue.
+                std::vector<CInv> vGetData(1,inv);
+                pfrom->PushGetBlocks(mapBlockIndex[inv.hash], uint256(0));
+                if (fDebug)
+                    printf("force request: %s\n", inv.ToString().c_str());
+            }
 
             // Track requests for our stuff
             Inventory(inv.hash);
@@ -2787,7 +2807,7 @@ bool ProcessMessages(CNode* pfrom)
         unsigned int nMessageSize = hdr.nMessageSize;
         if (nMessageSize > MAX_SIZE)
         {
-            printf("ProcessMessage(%s, %u bytes) : nMessageSize > MAX_SIZE\n", strCommand.c_str(), nMessageSize);
+            printf("ProcessMessages(%s, %u bytes) : nMessageSize > MAX_SIZE\n", strCommand.c_str(), nMessageSize);
             continue;
         }
         if (nMessageSize > vRecv.size())
@@ -2803,7 +2823,7 @@ bool ProcessMessages(CNode* pfrom)
         memcpy(&nChecksum, &hash, sizeof(nChecksum));
         if (nChecksum != hdr.nChecksum)
         {
-            printf("ProcessMessage(%s, %u bytes) : CHECKSUM ERROR nChecksum=%08x hdr.nChecksum=%08x\n",
+            printf("ProcessMessages(%s, %u bytes) : CHECKSUM ERROR nChecksum=%08x hdr.nChecksum=%08x\n",
                strCommand.c_str(), nMessageSize, nChecksum, hdr.nChecksum);
             continue;
         }
@@ -2828,22 +2848,22 @@ bool ProcessMessages(CNode* pfrom)
             if (strstr(e.what(), "end of data"))
             {
                 // Allow exceptions from underlength message on vRecv
-                printf("ProcessMessage(%s, %u bytes) : Exception '%s' caught, normally caused by a message being shorter than its stated length\n", strCommand.c_str(), nMessageSize, e.what());
+                printf("ProcessMessages(%s, %u bytes) : Exception '%s' caught, normally caused by a message being shorter than its stated length\n", strCommand.c_str(), nMessageSize, e.what());
             }
             else if (strstr(e.what(), "size too large"))
             {
                 // Allow exceptions from overlong size
-                printf("ProcessMessage(%s, %u bytes) : Exception '%s' caught\n", strCommand.c_str(), nMessageSize, e.what());
+                printf("ProcessMessages(%s, %u bytes) : Exception '%s' caught\n", strCommand.c_str(), nMessageSize, e.what());
             }
             else
             {
-                PrintExceptionContinue(&e, "ProcessMessage()");
+                PrintExceptionContinue(&e, "ProcessMessages()");
             }
         }
         catch (std::exception& e) {
-            PrintExceptionContinue(&e, "ProcessMessage()");
+            PrintExceptionContinue(&e, "ProcessMessages()");
         } catch (...) {
-            PrintExceptionContinue(NULL, "ProcessMessage()");
+            PrintExceptionContinue(NULL, "ProcessMessages()");
         }
 
         if (!fRet)
index 2439572..241ef46 100644 (file)
@@ -594,7 +594,13 @@ public:
         // Read transaction
         if (fseek(filein, pos.nTxPos, SEEK_SET) != 0)
             return error("CTransaction::ReadFromDisk() : fseek failed");
-        filein >> *this;
+
+        try {
+            filein >> *this;
+        }
+        catch (std::exception &e) {
+            return error("%s() : deserialize or I/O error", __PRETTY_FUNCTION__);
+        }
 
         // Return file pointer
         if (pfileRet)
@@ -976,7 +982,12 @@ public:
             filein.nType |= SER_BLOCKHEADERONLY;
 
         // Read block
-        filein >> *this;
+        try {
+            filein >> *this;
+        }
+        catch (std::exception &e) {
+            return error("%s() : deserialize or I/O error", __PRETTY_FUNCTION__);
+        }
 
         // Check the header
         if (!CheckProofOfWork(GetHash(), nBits))
index 3738778..c804ad0 100644 (file)
@@ -21,9 +21,12 @@ BitcoinAddressValidator::BitcoinAddressValidator(QObject *parent) :
 QValidator::State BitcoinAddressValidator::validate(QString &input, int &pos) const
 {
     // Correction
-    for(int idx=0; idx<input.size(); ++idx)
+    for(int idx=0; idx<input.size();)
     {
-        switch(input.at(idx).unicode())
+        bool removeChar = false;
+        QChar ch = input.at(idx);
+        // Transform characters that are visually close
+        switch(ch.unicode())
         {
         case 'l':
         case 'I':
@@ -33,9 +36,22 @@ QValidator::State BitcoinAddressValidator::validate(QString &input, int &pos) co
         case 'O':
             input[idx] = QChar('o');
             break;
+        // Qt categorizes these as "Other_Format" not "Separator_Space"
+        case 0x200B: // ZERO WIDTH SPACE
+        case 0xFEFF: // ZERO WIDTH NO-BREAK SPACE
+            removeChar = true;
+            break;
         default:
             break;
         }
+        // Remove whitespace
+        if(ch.isSpace())
+            removeChar = true;
+        // To next character
+        if(removeChar)
+            input.remove(idx, 1);
+        else
+            ++idx;
     }
 
     // Validation
index e776f35..3cae99e 100644 (file)
@@ -1,8 +1,8 @@
 /*
  * Qt4 bitcoin GUI.
  *
- * W.J. van der Laan 20011-2012
- * The Bitcoin Developers 20011-2012
+ * W.J. van der Laan 2011-2012
+ * The Bitcoin Developers 2011-2012
  */
 #include "bitcoingui.h"
 #include "transactiontablemodel.h"
index 84578b3..8a50bba 100644 (file)
@@ -27,8 +27,9 @@ void CSVModelWriter::addColumn(const QString &title, int column, int role)
 
 static void writeValue(QTextStream &f, const QString &value)
 {
-    // TODO: quoting if " or \n in string
-    f << "\"" << value << "\"";
+    QString escaped = value;
+    escaped.replace('"', "\"\"");
+    f << "\"" << escaped << "\"";
 }
 
 static void writeSep(QTextStream &f)
index 3f6b668..ff3a771 100644 (file)
@@ -28,9 +28,6 @@
   <layout class="QVBoxLayout" name="verticalLayout">
    <item>
     <widget class="QLabel" name="warningLabel">
-     <property name="text">
-      <string>TextLabel</string>
-     </property>
      <property name="textFormat">
       <enum>Qt::RichText</enum>
      </property>
index 59c44ac..0c43647 100644 (file)
@@ -213,7 +213,7 @@ MainOptionsPage::MainOptionsPage(QWidget *parent):
     proxy_hbox->addStretch(1);
 
     layout->addLayout(proxy_hbox);
-    QLabel *fee_help = new QLabel(tr("Optional transaction fee per kB that helps make sure your transactions are processed quickly.  Most transactions are 1 kB.  Fee 0.01 recommended."));
+    QLabel *fee_help = new QLabel(tr("Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended."));
     fee_help->setWordWrap(true);
     layout->addWidget(fee_help);
 
@@ -222,7 +222,6 @@ MainOptionsPage::MainOptionsPage(QWidget *parent):
     QLabel *fee_label = new QLabel(tr("Pay transaction &fee"));
     fee_hbox->addWidget(fee_label);
     fee_edit = new BitcoinAmountField();
-    fee_edit->setToolTip(tr("Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended."));
 
     fee_label->setBuddy(fee_edit);
     fee_hbox->addWidget(fee_edit);
index d068413..d7a70fe 100644 (file)
@@ -242,7 +242,8 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
         if (fFileBacked)
         {
             pwalletdbEncryption = new CWalletDB(strWalletFile);
-            pwalletdbEncryption->TxnBegin();
+            if (!pwalletdbEncryption->TxnBegin())
+                return false;
             pwalletdbEncryption->WriteMasterKey(nMasterKeyMaxID, kMasterKey);
         }