Merge branch 'postfeb20' of https://github.com/sipa/bitcoin
authorGavin Andresen <gavinandresen@gmail.com>
Wed, 22 Feb 2012 16:06:44 +0000 (11:06 -0500)
committerGavin Andresen <gavinandresen@gmail.com>
Wed, 22 Feb 2012 16:06:44 +0000 (11:06 -0500)
27 files changed:
src/db.cpp
src/db.h
src/init.cpp
src/irc.cpp
src/irc.h
src/key.h
src/keystore.cpp
src/keystore.h
src/main.cpp
src/net.cpp
src/net.h
src/qt/addressbookpage.cpp
src/qt/bitcoin.cpp
src/qt/forms/messagepage.ui
src/qt/guiutil.cpp
src/qt/guiutil.h
src/qt/qrcodedialog.cpp
src/qt/sendcoinsentry.cpp
src/qt/transactionview.cpp
src/test/multisig_tests.cpp
src/test/script_P2SH_tests.cpp
src/test/script_tests.cpp
src/test/sigopcount_tests.cpp
src/test/transaction_tests.cpp
src/uint256.h
src/wallet.cpp
src/wallet.h

index 9a904ec..ea6d46a 100644 (file)
@@ -940,6 +940,7 @@ int CWalletDB::LoadWallet(CWallet* pwallet)
                 ssValue >> nMinVersion;
                 if (nMinVersion > CLIENT_VERSION)
                     return DB_TOO_NEW;
+                pwallet->LoadMinVersion(nMinVersion);
             }
             else if (strType == "cscript")
             {
index 27479fe..2611faa 100644 (file)
--- a/src/db.h
+++ b/src/db.h
@@ -486,6 +486,11 @@ public:
         return Write(std::make_pair(std::string("setting"), strKey), value);
     }
 
+    bool WriteMinVersion(int nVersion)
+    {
+        return Write(std::string("minversion"), nVersion);
+    }
+
     bool ReadAccount(const std::string& strAccount, CAccount& account);
     bool WriteAccount(const std::string& strAccount, const CAccount& account);
     bool WriteAccountingEntry(const CAccountingEntry& acentry);
index 2adfed2..f09f044 100644 (file)
@@ -249,7 +249,12 @@ bool AppInit2(int argc, char* argv[])
 
         // Remove tabs
         strUsage.erase(std::remove(strUsage.begin(), strUsage.end(), '\t'), strUsage.end());
+#if defined(QT_GUI) && defined(WIN32)
+        // On windows, show a message box, as there is no stderr
+        wxMessageBox(strUsage, "Usage");
+#else
         fprintf(stderr, "%s", strUsage.c_str());
+#endif
         return false;
     }
 
index e795772..7a6f40c 100644 (file)
@@ -76,57 +76,6 @@ static bool Send(SOCKET hSocket, const char* pszSend)
     return true;
 }
 
-bool RecvLine(SOCKET hSocket, string& strLine)
-{
-    strLine = "";
-    loop
-    {
-        char c;
-        int nBytes = recv(hSocket, &c, 1, 0);
-        if (nBytes > 0)
-        {
-            if (c == '\n')
-                continue;
-            if (c == '\r')
-                return true;
-            strLine += c;
-            if (strLine.size() >= 9000)
-                return true;
-        }
-        else if (nBytes <= 0)
-        {
-            if (fShutdown)
-                return false;
-            if (nBytes < 0)
-            {
-                int nErr = WSAGetLastError();
-                if (nErr == WSAEMSGSIZE)
-                    continue;
-                if (nErr == WSAEWOULDBLOCK || nErr == WSAEINTR || nErr == WSAEINPROGRESS)
-                {
-                    Sleep(10);
-                    continue;
-                }
-            }
-            if (!strLine.empty())
-                return true;
-            if (nBytes == 0)
-            {
-                // socket closed
-                printf("IRC socket closed\n");
-                return false;
-            }
-            else
-            {
-                // socket error
-                int nErr = WSAGetLastError();
-                printf("IRC recv failed: %d\n", nErr);
-                return false;
-            }
-        }
-    }
-}
-
 bool RecvLineIRC(SOCKET hSocket, string& strLine)
 {
     loop
index f5adaa1..08d62b8 100644 (file)
--- a/src/irc.h
+++ b/src/irc.h
@@ -5,7 +5,6 @@
 #ifndef BITCOIN_IRC_H
 #define BITCOIN_IRC_H
 
-bool RecvLine(SOCKET hSocket, std::string& strLine);
 void ThreadIRCSeed(void* parg);
 
 extern int nGotIRCAddresses;
index 9e92897..4058f11 100644 (file)
--- a/src/key.h
+++ b/src/key.h
@@ -114,7 +114,7 @@ public:
         return fCompressedPubKey;
     }
 
-    void MakeNewKey(bool fCompressed = true)
+    void MakeNewKey(bool fCompressed)
     {
         if (!EC_KEY_generate_key(pkey))
             throw key_error("CKey::MakeNewKey() : EC_KEY_generate_key failed");
@@ -141,10 +141,13 @@ public:
         if (vchSecret.size() != 32)
             throw key_error("CKey::SetSecret() : secret must be 32 bytes");
         BIGNUM *bn = BN_bin2bn(&vchSecret[0],32,BN_new());
-        if (bn == NULL) 
+        if (bn == NULL)
             throw key_error("CKey::SetSecret() : BN_bin2bn failed");
         if (!EC_KEY_regenerate_key(pkey,bn))
+        {
+            BN_clear_free(bn);
             throw key_error("CKey::SetSecret() : EC_KEY_regenerate_key failed");
+        }
         BN_clear_free(bn);
         fSet = true;
         if (fCompressed || fCompressedPubKey)
index 18e5c37..e76f779 100644 (file)
@@ -8,16 +8,6 @@
 #include "db.h"
 #include "script.h"
 
-std::vector<unsigned char> CKeyStore::GenerateNewKey()
-{
-    RandAddSeedPerfmon();
-    CKey key;
-    key.MakeNewKey();
-    if (!AddKey(key))
-        throw std::runtime_error("CKeyStore::GenerateNewKey() : AddKey failed");
-    return key.GetPubKey();
-}
-
 bool CKeyStore::GetPubKey(const CBitcoinAddress &address, std::vector<unsigned char> &vchPubKeyOut) const
 {
     CKey key;
index 7eea02d..6757834 100644 (file)
@@ -29,8 +29,6 @@ public:
     virtual bool HaveCScript(const uint160 &hash) const =0;
     virtual bool GetCScript(const uint160 &hash, CScript& redeemScriptOut) const =0;
 
-    // Generate a new key, and add it to the store
-    virtual std::vector<unsigned char> GenerateNewKey();
     virtual bool GetSecret(const CBitcoinAddress &address, CSecret& vchSecret, bool &fCompressed) const
     {
         CKey key;
index fe15a7f..8103c8a 100644 (file)
@@ -21,7 +21,7 @@ using namespace boost;
 // Name of client reported in the 'version' message. Report the same name
 // for both bitcoind and bitcoin-qt, to make it harder for attackers to
 // target servers or GUI users specifically.
-const std::string CLIENT_NAME("bitcoin-qt");
+const std::string CLIENT_NAME("Satoshi");
 
 CCriticalSection cs_setpwalletRegistered;
 set<CWallet*> setpwalletRegistered;
@@ -1405,6 +1405,9 @@ bool static Reorganize(CTxDB& txdb, CBlockIndex* pindexNew)
     BOOST_FOREACH(CTransaction& tx, vDelete)
         tx.RemoveFromMemoryPool();
 
+    printf("REORGANIZE: Disconnected %i blocks; %s..%s\n", vDisconnect.size(), pfork->GetBlockHash().ToString().substr(0,20).c_str(), pindexBest->GetBlockHash().ToString().substr(0,20).c_str());
+    printf("REORGANIZE: Connected %i blocks; %s..%s\n", vConnect.size(), pfork->GetBlockHash().ToString().substr(0,20).c_str(), pindexNew->GetBlockHash().ToString().substr(0,20).c_str());
+
     return true;
 }
 
index fd488ce..546bc6a 100644 (file)
@@ -83,6 +83,57 @@ void CNode::PushGetBlocks(CBlockIndex* pindexBegin, uint256 hashEnd)
 
 
 
+bool RecvLine(SOCKET hSocket, string& strLine)
+{
+    strLine = "";
+    loop
+    {
+        char c;
+        int nBytes = recv(hSocket, &c, 1, 0);
+        if (nBytes > 0)
+        {
+            if (c == '\n')
+                continue;
+            if (c == '\r')
+                return true;
+            strLine += c;
+            if (strLine.size() >= 9000)
+                return true;
+        }
+        else if (nBytes <= 0)
+        {
+            if (fShutdown)
+                return false;
+            if (nBytes < 0)
+            {
+                int nErr = WSAGetLastError();
+                if (nErr == WSAEMSGSIZE)
+                    continue;
+                if (nErr == WSAEWOULDBLOCK || nErr == WSAEINTR || nErr == WSAEINPROGRESS)
+                {
+                    Sleep(10);
+                    continue;
+                }
+            }
+            if (!strLine.empty())
+                return true;
+            if (nBytes == 0)
+            {
+                // socket closed
+                printf("socket closed\n");
+                return false;
+            }
+            else
+            {
+                // socket error
+                int nErr = WSAGetLastError();
+                printf("recv failed: %d\n", nErr);
+                return false;
+            }
+        }
+    }
+}
+
 
 
 bool GetMyExternalIP2(const CService& addrConnect, const char* pszGet, const char* pszKeyword, CNetAddr& ipRet)
index e3e92da..51a816d 100644 (file)
--- a/src/net.h
+++ b/src/net.h
@@ -29,6 +29,7 @@ inline unsigned int ReceiveBufferSize() { return 1000*GetArg("-maxreceivebuffer"
 inline unsigned int SendBufferSize() { return 1000*GetArg("-maxsendbuffer", 10*1000); }
 static const unsigned int PUBLISH_HOPS = 5;
 
+bool RecvLine(SOCKET hSocket, std::string& strLine);
 bool GetMyExternalIP(CNetAddr& ipRet);
 bool AddAddress(CAddress addr, int64 nTimePenalty=0, CAddrDB *pAddrDB=NULL);
 void AddressCurrentlyConnected(const CService& addr);
index b5a798c..76aa87b 100644 (file)
@@ -9,7 +9,6 @@
 
 #include <QSortFilterProxyModel>
 #include <QClipboard>
-#include <QFileDialog>
 #include <QMessageBox>
 #include <QMenu>
 
@@ -277,10 +276,9 @@ void AddressBookPage::done(int retval)
 void AddressBookPage::exportClicked()
 {
     // CSV is currently the only supported format
-    QString filename = QFileDialog::getSaveFileName(
+    QString filename = GUIUtil::getSaveFileName(
             this,
-            tr("Export Address Book Data"),
-            QDir::currentPath(),
+            tr("Export Address Book Data"), QString(),
             tr("Comma separated file (*.csv)"));
 
     if (filename.isNull()) return;
index 20c185e..354e87c 100644 (file)
@@ -27,18 +27,10 @@ QSplashScreen *splashref;
 
 int MyMessageBox(const std::string& message, const std::string& caption, int style, wxWindow* parent, int x, int y)
 {
-    // Message from main thread
-    if(guiref)
-    {
-        guiref->error(QString::fromStdString(caption),
-                      QString::fromStdString(message));
-    }
-    else
-    {
-        QMessageBox::critical(0, QString::fromStdString(caption),
-            QString::fromStdString(message),
-            QMessageBox::Ok, QMessageBox::Ok);
-    }
+    // Message from AppInit2(), always in main thread before main window is constructed
+    QMessageBox::critical(0, QString::fromStdString(caption),
+        QString::fromStdString(message),
+        QMessageBox::Ok, QMessageBox::Ok);
     return 4;
 }
 
index 8afa4b5..131e15b 100644 (file)
@@ -17,7 +17,7 @@
    <item>
     <widget class="QLabel" name="labelExplanation">
      <property name="text">
-      <string>You can sign messages with your addresses to prove you own them. Be careful to only sign statement you agree to with full details, as phishing attacks may try to trick you into signing access to them.</string>
+      <string>You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to.</string>
      </property>
      <property name="textFormat">
       <enum>Qt::AutoText</enum>
index 02fc3b6..ac69bd0 100644 (file)
@@ -15,6 +15,8 @@
 #include <QAbstractItemView>
 #include <QApplication>
 #include <QClipboard>
+#include <QFileDialog>
+#include <QDesktopServices>
 
 QString GUIUtil::dateTimeStr(qint64 nTime)
 {
@@ -135,3 +137,50 @@ void GUIUtil::copyEntryData(QAbstractItemView *view, int column, int role)
         QApplication::clipboard()->setText(selection.at(0).data(role).toString());
     }
 }
+
+QString GUIUtil::getSaveFileName(QWidget *parent, const QString &caption,
+                                 const QString &dir,
+                                 const QString &filter,
+                                 QString *selectedSuffixOut)
+{
+    QString selectedFilter;
+    QString myDir;
+    if(dir.isEmpty()) // Default to user documents location
+    {
+        myDir = QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation);
+    }
+    else
+    {
+        myDir = dir;
+    }
+    QString result = QFileDialog::getSaveFileName(parent, caption, myDir, filter, &selectedFilter);
+
+    /* Extract first suffix from filter pattern "Description (*.foo)" or "Description (*.foo *.bar ...) */
+    QRegExp filter_re(".* \\(\\*\\.(.*)[ \\)]");
+    QString selectedSuffix;
+    if(filter_re.exactMatch(selectedFilter))
+    {
+        selectedSuffix = filter_re.cap(1);
+    }
+
+    /* Add suffix if needed */
+    QFileInfo info(result);
+    if(!result.isEmpty())
+    {
+        if(info.suffix().isEmpty() && !selectedSuffix.isEmpty())
+        {
+            /* No suffix specified, add selected suffix */
+            if(!result.endsWith("."))
+                result.append(".");
+            result.append(selectedSuffix);
+        }
+    }
+
+    /* Return selected suffix if asked to */
+    if(selectedSuffixOut)
+    {
+        *selectedSuffixOut = selectedSuffix;
+    }
+    return result;
+}
+
index 0c8b171..75ba53f 100644 (file)
@@ -46,6 +46,20 @@ public:
      */
     static void copyEntryData(QAbstractItemView *view, int column, int role=Qt::EditRole);
 
+    /** Get save file name, mimics QFileDialog::getSaveFileName, except that it appends a default suffix
+        when no suffix is provided by the user.
+
+      @param[in] parent  Parent window (or 0)
+      @param[in] caption Window caption (or empty, for default)
+      @param[in] dir     Starting directory (or empty, to default to documents directory)
+      @param[in] filter  Filter specification such as "Comma Separated Files (*.csv)"
+      @param[out] selectedSuffixOut  Pointer to return the suffix (file type) that was selected (or 0).
+                  Can be useful when choosing the save file format based on suffix.
+     */
+    static QString getSaveFileName(QWidget *parent=0, const QString &caption=QString(),
+                                   const QString &dir=QString(), const QString &filter=QString(),
+                                   QString *selectedSuffixOut=0);
+
 };
 
 #endif // GUIUTIL_H
index ed4c758..8295983 100644 (file)
@@ -1,9 +1,9 @@
 #include "qrcodedialog.h"
 #include "ui_qrcodedialog.h"
+#include "guiutil.h"
+
 #include <QPixmap>
 #include <QUrl>
-#include <QFileDialog>
-#include <QDesktopServices>
 #include <QDebug>
 
 #include <qrencode.h>
@@ -34,8 +34,8 @@ QRCodeDialog::~QRCodeDialog()
     delete ui;
 }
 
-void QRCodeDialog::genCode() {
-
+void QRCodeDialog::genCode()
+{
     QString uri = getURI();
     //qDebug() << "Encoding:" << uri.toUtf8().constData();
     QRcode *code = QRcode_encodeString(uri.toUtf8().constData(), 0, QR_ECLEVEL_L, QR_MODE_8, 1);
@@ -52,7 +52,8 @@ void QRCodeDialog::genCode() {
     ui->lblQRCode->setPixmap(QPixmap::fromImage(myImage).scaled(300, 300));
 }
 
-QString QRCodeDialog::getURI() {
+QString QRCodeDialog::getURI()
+{
     QString ret = QString("bitcoin:%1").arg(address);
 
     int paramCount = 0;
@@ -80,21 +81,24 @@ QString QRCodeDialog::getURI() {
     return ret;
 }
 
-void QRCodeDialog::on_lnReqAmount_textChanged(const QString &) {
+void QRCodeDialog::on_lnReqAmount_textChanged(const QString &)
+{
     genCode();
 }
 
-void QRCodeDialog::on_lnLabel_textChanged(const QString &) {
+void QRCodeDialog::on_lnLabel_textChanged(const QString &)
+{
     genCode();
 }
 
-void QRCodeDialog::on_lnMessage_textChanged(const QString &) {
+void QRCodeDialog::on_lnMessage_textChanged(const QString &)
+{
     genCode();
 }
 
 void QRCodeDialog::on_btnSaveAs_clicked()
 {
-    QString fn = QFileDialog::getSaveFileName(this, "Save Image...", QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation), "Images (*.png)");
+    QString fn = GUIUtil::getSaveFileName(this, tr("Save Image..."), QString(), tr("PNG Images (*.png)"));
     if(!fn.isEmpty()) {
         myImage.scaled(EXPORT_IMAGE_SIZE, EXPORT_IMAGE_SIZE).save(fn);
     }
index ab5460f..d98400c 100644 (file)
@@ -59,8 +59,9 @@ void SendCoinsEntry::on_payTo_textChanged(const QString &address)
 {
     if(!model)
         return;
-    ui->addAsLabel->setText(model->getAddressTableModel()->labelForAddress(address));
-}
+    // Fill in label from address book, if no label is filled in yet
+    if(ui->addAsLabel->text().isEmpty())
+        ui->addAsLabel->setText(model->getAddressTableModel()->labelForAddress(address));}
 
 void SendCoinsEntry::setModel(WalletModel *model)
 {
index 4c357d1..eaed48b 100644 (file)
@@ -21,7 +21,6 @@
 #include <QTableView>
 #include <QHeaderView>
 #include <QPushButton>
-#include <QFileDialog>
 #include <QMessageBox>
 #include <QPoint>
 #include <QMenu>
@@ -264,10 +263,9 @@ void TransactionView::changedAmount(const QString &amount)
 void TransactionView::exportClicked()
 {
     // CSV is currently the only supported format
-    QString filename = QFileDialog::getSaveFileName(
+    QString filename = GUIUtil::getSaveFileName(
             this,
-            tr("Export Transaction Data"),
-            QDir::currentPath(),
+            tr("Export Transaction Data"), QString(),
             tr("Comma separated file (*.csv)"));
 
     if (filename.isNull()) return;
index 56b1804..8ae9290 100644 (file)
@@ -46,7 +46,7 @@ BOOST_AUTO_TEST_CASE(multisig_verify)
 {
     CKey key[4];
     for (int i = 0; i < 4; i++)
-        key[i].MakeNewKey();
+        key[i].MakeNewKey(true);
 
     CScript a_and_b;
     a_and_b << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG;
@@ -131,7 +131,7 @@ BOOST_AUTO_TEST_CASE(multisig_IsStandard)
 {
     CKey key[4];
     for (int i = 0; i < 4; i++)
-        key[i].MakeNewKey();
+        key[i].MakeNewKey(true);
 
     CScript a_and_b;
     a_and_b << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG;
@@ -178,7 +178,7 @@ BOOST_AUTO_TEST_CASE(multisig_Solver1)
     CBitcoinAddress keyaddr[3];
     for (int i = 0; i < 3; i++)
     {
-        key[i].MakeNewKey();
+        key[i].MakeNewKey(true);
         keystore.AddKey(key[i]);
         keyaddr[i].SetPubKey(key[i].GetPubKey());
     }
@@ -257,7 +257,7 @@ BOOST_AUTO_TEST_CASE(multisig_Sign)
     CKey key[4];
     for (int i = 0; i < 4; i++)
     {
-        key[i].MakeNewKey();
+        key[i].MakeNewKey(true);
         keystore.AddKey(key[i]);
     }
 
index e389911..aa72c00 100644 (file)
@@ -57,7 +57,7 @@ BOOST_AUTO_TEST_CASE(sign)
     CKey key[4];
     for (int i = 0; i < 4; i++)
     {
-        key[i].MakeNewKey();
+        key[i].MakeNewKey(true);
         keystore.AddKey(key[i]);
     }
 
@@ -148,7 +148,7 @@ BOOST_AUTO_TEST_CASE(set)
     std::vector<CKey> keys;
     for (int i = 0; i < 4; i++)
     {
-        key[i].MakeNewKey();
+        key[i].MakeNewKey(true);
         keystore.AddKey(key[i]);
         keys.push_back(key[i]);
     }
@@ -249,7 +249,7 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard)
     vector<CKey> keys;
     for (int i = 0; i < 3; i++)
     {
-        key[i].MakeNewKey();
+        key[i].MakeNewKey(true);
         keystore.AddKey(key[i]);
         keys.push_back(key[i]);
     }
index 79dd7f1..493ea69 100644 (file)
@@ -72,9 +72,9 @@ sign_multisig(CScript scriptPubKey, CKey key, CTransaction transaction)
 BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG12)
 {
     CKey key1, key2, key3;
-    key1.MakeNewKey();
-    key2.MakeNewKey();
-    key3.MakeNewKey();
+    key1.MakeNewKey(true);
+    key2.MakeNewKey(false);
+    key3.MakeNewKey(true);
 
     CScript scriptPubKey12;
     scriptPubKey12 << OP_1 << key1.GetPubKey() << key2.GetPubKey() << OP_2 << OP_CHECKMULTISIG;
@@ -105,10 +105,10 @@ BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG12)
 BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG23)
 {
     CKey key1, key2, key3, key4;
-    key1.MakeNewKey();
-    key2.MakeNewKey();
-    key3.MakeNewKey();
-    key4.MakeNewKey();
+    key1.MakeNewKey(true);
+    key2.MakeNewKey(false);
+    key3.MakeNewKey(true);
+    key4.MakeNewKey(false);
 
     CScript scriptPubKey23;
     scriptPubKey23 << OP_2 << key1.GetPubKey() << key2.GetPubKey() << key3.GetPubKey() << OP_3 << OP_CHECKMULTISIG;
index 0b0a4a6..d301313 100644 (file)
@@ -41,7 +41,7 @@ BOOST_AUTO_TEST_CASE(GetSigOpCount)
     for (int i = 0; i < 3; i++)
     {
         CKey k;
-        k.MakeNewKey();
+        k.MakeNewKey(true);
         keys.push_back(k);
     }
     CScript s2;
index cd4d7ee..99163e5 100644 (file)
@@ -38,7 +38,7 @@ SetupDummyInputs(CBasicKeyStore& keystoreRet, MapPrevTx& inputsRet)
     CKey key[4];
     for (int i = 0; i < 4; i++)
     {
-        key[i].MakeNewKey();
+        key[i].MakeNewKey(i % 2);
         keystoreRet.AddKey(key[i]);
     }
 
index 5b1ba9f..caf6fa1 100644 (file)
@@ -92,13 +92,6 @@ public:
         return *this;
     }
 
-    base_uint& operator&=(uint64 b)
-    {
-        pn[0] &= (unsigned int)b;
-        pn[1] &= (unsigned int)(b >> 32);
-        return *this;
-    }
-
     base_uint& operator|=(uint64 b)
     {
         pn[0] |= (unsigned int)b;
index 9d80f8a..30590c8 100644 (file)
@@ -15,6 +15,23 @@ using namespace std;
 // mapWallet
 //
 
+std::vector<unsigned char> CWallet::GenerateNewKey()
+{
+    bool fCompressed = true; // default to compressed public keys
+
+    RandAddSeedPerfmon();
+    CKey key;
+    key.MakeNewKey(fCompressed);
+
+    // Compressed public keys were introduced in version 0.6.0
+    if (fCompressed)
+        SetMinVersion(59900);
+
+    if (!AddKey(key))
+        throw std::runtime_error("CWallet::GenerateNewKey() : AddKey failed");
+    return key.GetPubKey();
+}
+
 bool CWallet::AddKey(const CKey& key)
 {
     if (!CCryptoKeyStore::AddKey(key))
@@ -131,6 +148,32 @@ public:
     )
 };
 
+bool CWallet::SetMinVersion(int nVersion, CWalletDB* pwalletdbIn)
+{
+    if (nWalletVersion >= nVersion)
+        return true;
+
+    nWalletVersion = nVersion;
+
+    if (fFileBacked)
+    {
+        CWalletDB* pwalletdb = pwalletdbIn ? pwalletdbIn : new CWalletDB(strWalletFile);
+        if (nWalletVersion >= 40000)
+        {
+            // Versions prior to 0.4.0 did not support the "minversion" record.
+            // Use a CCorruptAddress to make them crash instead.
+            CCorruptAddress corruptAddress;
+            pwalletdb->WriteSetting("addrIncoming", corruptAddress);
+        }
+        if (nWalletVersion > 40000)
+            pwalletdb->WriteMinVersion(nWalletVersion);
+        if (!pwalletdbIn)
+            delete pwalletdb;
+    }
+
+    return true;
+}
+
 bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
 {
     if (IsCrypted())
@@ -184,10 +227,11 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
             exit(1); //We now probably have half of our keys encrypted in memory, and half not...die and let the user reload their unencrypted wallet.
         }
 
+        // Encryption was introduced in version 0.4.0
+        SetMinVersion(40000, pwalletdbEncryption);
+
         if (fFileBacked)
         {
-            CCorruptAddress corruptAddress;
-            pwalletdbEncryption->WriteSetting("addrIncoming", corruptAddress);
             if (!pwalletdbEncryption->TxnCommit())
                 exit(1); //We now have keys encrypted in memory, but no on disk...die to avoid confusion and let the user reload their unencrypted wallet.
 
index 3fdef50..fea3297 100644 (file)
@@ -25,6 +25,8 @@ private:
 
     CWalletDB *pwalletdbEncryption;
 
+    int nWalletVersion;
+
 public:
     mutable CCriticalSection cs_wallet;
 
@@ -33,18 +35,21 @@ public:
 
     std::set<int64> setKeyPool;
 
+
     typedef std::map<unsigned int, CMasterKey> MasterKeyMap;
     MasterKeyMap mapMasterKeys;
     unsigned int nMasterKeyMaxID;
 
     CWallet()
     {
+        nWalletVersion = 0;
         fFileBacked = false;
         nMasterKeyMaxID = 0;
         pwalletdbEncryption = NULL;
     }
     CWallet(std::string strWalletFileIn)
     {
+        nWalletVersion = 0;
         strWalletFile = strWalletFileIn;
         fFileBacked = true;
         nMasterKeyMaxID = 0;
@@ -61,11 +66,15 @@ public:
     std::vector<unsigned char> vchDefaultKey;
 
     // keystore implementation
+    // Generate a new key
+    std::vector<unsigned char> GenerateNewKey();
     // Adds a key to the store, and saves it to disk.
     bool AddKey(const CKey& key);
     // Adds a key to the store, without saving it to disk (used by LoadWallet)
     bool LoadKey(const CKey& key) { return CCryptoKeyStore::AddKey(key); }
 
+    bool LoadMinVersion(int nVersion) { nWalletVersion = nVersion; return true; }
+
     // Adds an encrypted key to the store, and saves it to disk.
     bool AddCryptedKey(const std::vector<unsigned char> &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret);
     // Adds an encrypted key to the store, without saving it to disk (used by LoadWallet)
@@ -206,6 +215,8 @@ public:
     bool GetTransaction(const uint256 &hashTx, CWalletTx& wtx);
 
     bool SetDefaultKey(const std::vector<unsigned char> &vchPubKey);
+
+    bool SetMinVersion(int nVersion, CWalletDB* pwalletdbIn = NULL);
 };