aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bitcoin-qt.pro2
-rw-r--r--src/addrman.cpp2
-rw-r--r--src/addrman.h2
-rw-r--r--src/allocators.h2
-rw-r--r--src/base58.h2
-rw-r--r--src/bignum.h2
-rw-r--r--src/bitcoinrpc.cpp18
-rw-r--r--src/bitcoinrpc.h3
-rw-r--r--src/checkpoints.cpp2
-rw-r--r--src/checkpoints.h2
-rw-r--r--src/compat.h2
-rw-r--r--src/db.cpp25
-rw-r--r--src/db.h11
-rw-r--r--src/init.cpp453
-rw-r--r--src/init.h3
-rw-r--r--src/irc.cpp2
-rw-r--r--src/irc.h2
-rw-r--r--src/key.cpp334
-rw-r--r--src/key.h270
-rw-r--r--src/keystore.cpp17
-rw-r--r--src/keystore.h21
-rw-r--r--src/main.cpp139
-rw-r--r--src/main.h22
-rw-r--r--src/makefile.linux-mingw2
-rw-r--r--src/makefile.mingw2
-rw-r--r--src/makefile.osx2
-rw-r--r--src/makefile.unix2
-rw-r--r--src/mruset.h2
-rw-r--r--src/net.cpp6
-rw-r--r--src/net.h2
-rw-r--r--src/netbase.cpp2
-rw-r--r--src/netbase.h2
-rw-r--r--src/noui.cpp35
-rw-r--r--src/protocol.cpp2
-rw-r--r--src/protocol.h2
-rw-r--r--src/qt/addressbookpage.cpp29
-rw-r--r--src/qt/addressbookpage.h5
-rw-r--r--src/qt/addresstablemodel.cpp85
-rw-r--r--src/qt/addresstablemodel.h9
-rw-r--r--src/qt/bitcoin.cpp66
-rw-r--r--src/qt/bitcoinaddressvalidator.cpp28
-rw-r--r--src/qt/bitcoingui.cpp10
-rw-r--r--src/qt/bitcoingui.h2
-rw-r--r--src/qt/clientmodel.cpp102
-rw-r--r--src/qt/clientmodel.h17
-rw-r--r--src/qt/forms/askpassphrasedialog.ui14
-rw-r--r--src/qt/forms/messagepage.ui2
-rw-r--r--src/qt/optionsdialog.cpp8
-rw-r--r--src/qt/qtipcserver.cpp4
-rw-r--r--src/qt/rpcconsole.cpp17
-rw-r--r--src/qt/rpcconsole.h3
-rw-r--r--src/qt/transactionrecord.cpp181
-rw-r--r--src/qt/transactiontablemodel.cpp146
-rw-r--r--src/qt/transactiontablemodel.h6
-rw-r--r--src/qt/verifymessagedialog.cpp2
-rw-r--r--src/qt/walletmodel.cpp74
-rw-r--r--src/qt/walletmodel.h11
-rw-r--r--src/rpcdump.cpp4
-rw-r--r--src/script.cpp2
-rw-r--r--src/script.h2
-rw-r--r--src/serialize.h2
-rw-r--r--src/sync.cpp2
-rw-r--r--src/sync.h2
-rw-r--r--src/test/DoS_tests.cpp135
-rw-r--r--src/test/test_bitcoin.cpp4
-rw-r--r--src/ui_interface.h134
-rw-r--r--src/uint256.h2
-rw-r--r--src/util.cpp134
-rw-r--r--src/util.h10
-rw-r--r--src/version.cpp2
-rw-r--r--src/version.h2
-rw-r--r--src/wallet.cpp37
-rw-r--r--src/wallet.h23
-rw-r--r--src/walletdb.cpp2
-rw-r--r--src/walletdb.h2
75 files changed, 1655 insertions, 1066 deletions
diff --git a/bitcoin-qt.pro b/bitcoin-qt.pro
index ae4ef79cb8..a47d661678 100644
--- a/bitcoin-qt.pro
+++ b/bitcoin-qt.pro
@@ -2,7 +2,7 @@ TEMPLATE = app
TARGET =
VERSION = 0.6.99
INCLUDEPATH += src src/json src/qt
-DEFINES += QT_GUI BOOST_THREAD_USE_LIB USE_IPV6
+DEFINES += QT_GUI BOOST_THREAD_USE_LIB BOOST_SPIRIT_THREADSAFE USE_IPV6
CONFIG += no_include_pwd
# for boost 1.37, add -mt to the boost libraries
diff --git a/src/addrman.cpp b/src/addrman.cpp
index 56ac9ca12c..acd0d46790 100644
--- a/src/addrman.cpp
+++ b/src/addrman.cpp
@@ -1,6 +1,6 @@
// Copyright (c) 2012 Pieter Wuille
// Distributed under the MIT/X11 software license, see the accompanying
-// file license.txt or http://www.opensource.org/licenses/mit-license.php.
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "addrman.h"
diff --git a/src/addrman.h b/src/addrman.h
index a1275da2d5..b996839e3c 100644
--- a/src/addrman.h
+++ b/src/addrman.h
@@ -1,6 +1,6 @@
// Copyright (c) 2012 Pieter Wuille
// Distributed under the MIT/X11 software license, see the accompanying
-// file license.txt or http://www.opensource.org/licenses/mit-license.php.
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef _BITCOIN_ADDRMAN
#define _BITCOIN_ADDRMAN 1
diff --git a/src/allocators.h b/src/allocators.h
index fa9534bc52..4b3356e874 100644
--- a/src/allocators.h
+++ b/src/allocators.h
@@ -1,7 +1,7 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
-// file license.txt or http://www.opensource.org/licenses/mit-license.php.
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_ALLOCATORS_H
#define BITCOIN_ALLOCATORS_H
diff --git a/src/base58.h b/src/base58.h
index 1391a13e0e..a4ff35c4a8 100644
--- a/src/base58.h
+++ b/src/base58.h
@@ -1,7 +1,7 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2012 The Bitcoin Developers
// Distributed under the MIT/X11 software license, see the accompanying
-// file license.txt or http://www.opensource.org/licenses/mit-license.php.
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
//
diff --git a/src/bignum.h b/src/bignum.h
index f0971e8850..307017b0ab 100644
--- a/src/bignum.h
+++ b/src/bignum.h
@@ -1,7 +1,7 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
-// file license.txt or http://www.opensource.org/licenses/mit-license.php.
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_BIGNUM_H
#define BITCOIN_BIGNUM_H
diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp
index 334425a9a9..24fa97588c 100644
--- a/src/bitcoinrpc.cpp
+++ b/src/bitcoinrpc.cpp
@@ -1,7 +1,7 @@
// Copyright (c) 2010 Satoshi Nakamoto
// Copyright (c) 2009-2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
-// file license.txt or http://www.opensource.org/licenses/mit-license.php.
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "main.h"
#include "wallet.h"
@@ -435,7 +435,7 @@ Value stop(const Array& params, bool fHelp)
"stop\n"
"Stop Bitcoin server.");
// Shutdown will take long enough that the response should get back
- QueueShutdown();
+ uiInterface.QueueShutdown();
return "Bitcoin server stopping";
}
@@ -1928,7 +1928,7 @@ Value encryptwallet(const Array& params, bool fHelp)
// BDB seems to have a bad habit of writing old data into
// slack space in .dat files; that is bad if the old data is
// unencrypted private keys. So:
- QueueShutdown();
+ uiInterface.QueueShutdown();
return "wallet encrypted; Bitcoin server stopping, restart to run with encrypted wallet";
}
@@ -2620,7 +2620,7 @@ void ThreadRPCServer2(void* parg)
strWhatAmI = strprintf(_("To use the %s option"), "\"-server\"");
else if (mapArgs.count("-daemon"))
strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\"");
- ThreadSafeMessageBox(strprintf(
+ uiInterface.ThreadSafeMessageBox(strprintf(
_("%s, you must set a rpcpassword in the configuration file:\n %s\n"
"It is recommended you use the following random password:\n"
"rpcuser=bitcoinrpc\n"
@@ -2630,8 +2630,8 @@ void ThreadRPCServer2(void* parg)
strWhatAmI.c_str(),
GetConfigFile().string().c_str(),
EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32).c_str()),
- _("Error"), wxOK | wxMODAL);
- QueueShutdown();
+ _("Error"), CClientUIInterface::OK | CClientUIInterface::MODAL);
+ uiInterface.QueueShutdown();
return;
}
@@ -2650,9 +2650,9 @@ void ThreadRPCServer2(void* parg)
}
catch(boost::system::system_error &e)
{
- ThreadSafeMessageBox(strprintf(_("An error occured while setting up the RPC port %i for listening: %s"), endpoint.port(), e.what()),
- _("Error"), wxOK | wxMODAL);
- QueueShutdown();
+ uiInterface.ThreadSafeMessageBox(strprintf(_("An error occured while setting up the RPC port %i for listening: %s"), endpoint.port(), e.what()),
+ _("Error"), CClientUIInterface::OK | CClientUIInterface::MODAL);
+ uiInterface.QueueShutdown();
return;
}
diff --git a/src/bitcoinrpc.h b/src/bitcoinrpc.h
index ed5974578c..8b2d905179 100644
--- a/src/bitcoinrpc.h
+++ b/src/bitcoinrpc.h
@@ -1,7 +1,7 @@
// Copyright (c) 2010 Satoshi Nakamoto
// Copyright (c) 2009-2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
-// file license.txt or http://www.opensource.org/licenses/mit-license.php.
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef _BITCOINRPC_H_
#define _BITCOINRPC_H_ 1
@@ -9,7 +9,6 @@
#include <string>
#include <map>
-#define BOOST_SPIRIT_THREADSAFE
#include "json/json_spirit_reader_template.h"
#include "json/json_spirit_writer_template.h"
#include "json/json_spirit_utils.h"
diff --git a/src/checkpoints.cpp b/src/checkpoints.cpp
index cf56fa0695..6679bc93d4 100644
--- a/src/checkpoints.cpp
+++ b/src/checkpoints.cpp
@@ -1,6 +1,6 @@
// Copyright (c) 2009-2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
-// file license.txt or http://www.opensource.org/licenses/mit-license.php.
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <boost/assign/list_of.hpp> // for 'map_list_of()'
#include <boost/foreach.hpp>
diff --git a/src/checkpoints.h b/src/checkpoints.h
index 5d3228f3fc..70e936564c 100644
--- a/src/checkpoints.h
+++ b/src/checkpoints.h
@@ -1,6 +1,6 @@
// Copyright (c) 2009-2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
-// file license.txt or http://www.opensource.org/licenses/mit-license.php.
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_CHECKPOINT_H
#define BITCOIN_CHECKPOINT_H
diff --git a/src/compat.h b/src/compat.h
index 804a8141b5..79ebb9323a 100644
--- a/src/compat.h
+++ b/src/compat.h
@@ -1,7 +1,7 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
-// file license.txt or http://www.opensource.org/licenses/mit-license.php.
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef _BITCOIN_COMPAT_H
#define _BITCOIN_COMPAT_H 1
diff --git a/src/db.cpp b/src/db.cpp
index f0addda918..95220059d0 100644
--- a/src/db.cpp
+++ b/src/db.cpp
@@ -1,7 +1,7 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
-// file license.txt or http://www.opensource.org/licenses/mit-license.php.
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "db.h"
#include "util.h"
@@ -74,6 +74,10 @@ bool CDBEnv::Open(boost::filesystem::path pathEnv_)
filesystem::path pathErrorFile = pathDataDir / "db.log";
printf("dbenv.open LogDir=%s ErrorFile=%s\n", pathLogDir.string().c_str(), pathErrorFile.string().c_str());
+ unsigned int nEnvFlags = 0;
+ if (GetBoolArg("-privdb", true))
+ nEnvFlags |= DB_PRIVATE;
+
int nDbCache = GetArg("-dbcache", 25);
dbenv.set_lg_dir(pathLogDir.string().c_str());
dbenv.set_cachesize(nDbCache / 1024, (nDbCache % 1024)*1048576, 1);
@@ -92,7 +96,8 @@ bool CDBEnv::Open(boost::filesystem::path pathEnv_)
DB_INIT_MPOOL |
DB_INIT_TXN |
DB_THREAD |
- DB_RECOVER,
+ DB_RECOVER |
+ nEnvFlags,
S_IRUSR | S_IWUSR);
if (ret > 0)
return error("CDB() : error %d opening database environment", ret);
@@ -423,9 +428,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)
@@ -540,6 +551,8 @@ bool CTxDB::LoadBlockIndex()
return false;
// Unserialize
+
+ try {
string strType;
ssKey >> strType;
if (strType == "blockindex" && !fRequestShutdown)
@@ -571,6 +584,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();
diff --git a/src/db.h b/src/db.h
index abc58c4b1e..4919284a3d 100644
--- a/src/db.h
+++ b/src/db.h
@@ -1,7 +1,7 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
-// file license.txt or http://www.opensource.org/licenses/mit-license.php.
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_DB_H
#define BITCOIN_DB_H
@@ -107,8 +107,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());
diff --git a/src/init.cpp b/src/init.cpp
index 809c07f375..c01dc27086 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -1,7 +1,7 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
-// file license.txt or http://www.opensource.org/licenses/mit-license.php.
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "db.h"
#include "walletdb.h"
#include "bitcoinrpc.h"
@@ -13,6 +13,7 @@
#include <boost/filesystem/fstream.hpp>
#include <boost/filesystem/convenience.hpp>
#include <boost/interprocess/sync/file_lock.hpp>
+#include <boost/algorithm/string/predicate.hpp>
#ifndef WIN32
#include <signal.h>
@@ -22,6 +23,7 @@ using namespace std;
using namespace boost;
CWallet* pwalletMain;
+CClientUIInterface uiInterface;
//////////////////////////////////////////////////////////////////////////////
//
@@ -80,6 +82,10 @@ void HandleSIGTERM(int)
fRequestShutdown = true;
}
+void HandleSIGHUP(int)
+{
+ fReopenDebugLog = true;
+}
@@ -90,17 +96,6 @@ void HandleSIGTERM(int)
// Start
//
#if !defined(QT_GUI)
-int main(int argc, char* argv[])
-{
- bool fRet = false;
- fRet = AppInit(argc, argv);
-
- if (fRet && fDaemon)
- return 0;
-
- return 1;
-}
-
bool AppInit(int argc, char* argv[])
{
bool fRet = false;
@@ -136,7 +131,7 @@ bool AppInit(int argc, char* argv[])
// Command-line RPC
for (int i = 1; i < argc; i++)
- if (!IsSwitchChar(argv[i][0]) && !(strlen(argv[i]) > 7 && strncasecmp(argv[i], "bitcoin:", 8) == 0))
+ if (!IsSwitchChar(argv[i][0]) && !boost::algorithm::istarts_with(argv[i], "bitcoin:"))
fCommandLine = true;
if (fCommandLine)
@@ -156,17 +151,33 @@ bool AppInit(int argc, char* argv[])
Shutdown(NULL);
return fRet;
}
+
+extern void noui_connect();
+int main(int argc, char* argv[])
+{
+ bool fRet = false;
+
+ // Connect bitcoind signal handlers
+ noui_connect();
+
+ fRet = AppInit(argc, argv);
+
+ if (fRet && fDaemon)
+ return 0;
+
+ return 1;
+}
#endif
bool static InitError(const std::string &str)
{
- ThreadSafeMessageBox(str, _("Bitcoin"), wxOK | wxMODAL);
+ uiInterface.ThreadSafeMessageBox(str, _("Bitcoin"), CClientUIInterface::OK | CClientUIInterface::MODAL);
return false;
}
bool static InitWarning(const std::string &str)
{
- ThreadSafeMessageBox(str, _("Bitcoin"), wxOK | wxICON_EXCLAMATION | wxMODAL);
+ uiInterface.ThreadSafeMessageBox(str, _("Bitcoin"), CClientUIInterface::OK | CClientUIInterface::ICON_EXCLAMATION | CClientUIInterface::MODAL);
return true;
}
@@ -264,6 +275,7 @@ std::string HelpMessage()
*/
bool AppInit2()
{
+ // ********************************************************* Step 1: setup
#ifdef _MSC_VER
// Turn off microsoft heap dump noise
_CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
@@ -284,15 +296,44 @@ bool AppInit2()
sa.sa_flags = 0;
sigaction(SIGTERM, &sa, NULL);
sigaction(SIGINT, &sa, NULL);
- sigaction(SIGHUP, &sa, NULL);
+
+ // Reopen debug.log on SIGHUP
+ struct sigaction sa_hup;
+ sa_hup.sa_handler = HandleSIGHUP;
+ sigemptyset(&sa_hup.sa_mask);
+ sa_hup.sa_flags = 0;
+ sigaction(SIGHUP, &sa_hup, NULL);
#endif
+ // ********************************************************* Step 2: parameter interactions
+
fTestNet = GetBoolArg("-testnet");
if (fTestNet)
{
SoftSetBoolArg("-irc", true);
}
+ if (mapArgs.count("-connect"))
+ SoftSetBoolArg("-dnsseed", false);
+
+ // even in Tor mode, if -bind is specified, you really want -listen
+ if (mapArgs.count("-bind"))
+ SoftSetBoolArg("-listen", true);
+
+ bool fTor = (fUseProxy && addrProxy.GetPort() == 9050);
+ if (fTor)
+ {
+ // Use SoftSetBoolArg here so user can override any of these if they wish.
+ // Note: the GetBoolArg() calls for all of these must happen later.
+ SoftSetBoolArg("-listen", false);
+ SoftSetBoolArg("-irc", false);
+ SoftSetBoolArg("-proxydns", true);
+ SoftSetBoolArg("-upnp", false);
+ SoftSetBoolArg("-discover", false);
+ }
+
+ // ********************************************************* Step 3: parameter-to-internal-flags
+
fDebug = GetBoolArg("-debug");
bitdb.SetDetach(GetBoolArg("-detachdb", false));
@@ -315,6 +356,38 @@ bool AppInit2()
fPrintToDebugger = GetBoolArg("-printtodebugger");
fLogTimestamps = GetBoolArg("-logtimestamps");
+ if (mapArgs.count("-timeout"))
+ {
+ int nNewTimeout = GetArg("-timeout", 5000);
+ if (nNewTimeout > 0 && nNewTimeout < 600000)
+ nConnectTimeout = nNewTimeout;
+ }
+
+ // Continue to put "/P2SH/" in the coinbase to monitor
+ // BIP16 support.
+ // This can be removed eventually...
+ const char* pszP2SH = "/P2SH/";
+ COINBASE_FLAGS << std::vector<unsigned char>(pszP2SH, pszP2SH+strlen(pszP2SH));
+
+
+ if (mapArgs.count("-paytxfee"))
+ {
+ if (!ParseMoney(mapArgs["-paytxfee"], nTransactionFee))
+ return InitError(strprintf(_("Invalid amount for -paytxfee=<amount>: '%s'"), mapArgs["-paytxfee"].c_str()));
+ if (nTransactionFee > 0.25 * COIN)
+ InitWarning(_("Warning: -paytxfee is set very high. This is the transaction fee you will pay if you send a transaction."));
+ }
+
+ // ********************************************************* Step 4: application initialization: dir lock, daemonize, pidfile, debug log
+
+ // Make sure only a single Bitcoin process is using the data directory.
+ boost::filesystem::path pathLockFile = GetDataDir() / ".lock";
+ FILE* file = fopen(pathLockFile.string().c_str(), "a"); // empty lock file; created if it doesn't exist.
+ if (file) fclose(file);
+ static boost::interprocess::file_lock lock(pathLockFile.string().c_str());
+ if (!lock.try_lock())
+ return InitError(strprintf(_("Cannot obtain a lock on data directory %s. Bitcoin is probably already running."), GetDataDir().string().c_str()));
+
#if !defined(WIN32) && !defined(QT_GUI)
if (fDaemon)
{
@@ -342,45 +415,106 @@ bool AppInit2()
printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
printf("Bitcoin version %s (%s)\n", FormatFullVersion().c_str(), CLIENT_DATE.c_str());
printf("Default data directory %s\n", GetDefaultDataDir().string().c_str());
+ std::ostringstream strErrors;
- if (GetBoolArg("-loadblockindextest"))
+ if (fDaemon)
+ fprintf(stdout, "Bitcoin server starting\n");
+
+ int64 nStart;
+
+ // ********************************************************* Step 5: network initialization
+
+ if (mapArgs.count("-proxy"))
{
- CTxDB txdb("r");
- txdb.LoadBlockIndex();
- PrintBlockTree();
- return false;
+ fUseProxy = true;
+ addrProxy = CService(mapArgs["-proxy"], 9050);
+ if (!addrProxy.IsValid())
+ return InitError(strprintf(_("Invalid -proxy address: '%s'"), mapArgs["-proxy"].c_str()));
}
- // Make sure only a single Bitcoin process is using the data directory.
- boost::filesystem::path pathLockFile = GetDataDir() / ".lock";
- FILE* file = fopen(pathLockFile.string().c_str(), "a"); // empty lock file; created if it doesn't exist.
- if (file) fclose(file);
- static boost::interprocess::file_lock lock(pathLockFile.string().c_str());
- if (!lock.try_lock())
- return InitError(strprintf(_("Cannot obtain a lock on data directory %s. Bitcoin is probably already running."), GetDataDir().string().c_str()));
+ if (mapArgs.count("-noproxy"))
+ {
+ BOOST_FOREACH(std::string snet, mapMultiArgs["-noproxy"]) {
+ enum Network net = ParseNetwork(snet);
+ if (net == NET_UNROUTABLE)
+ return InitError(strprintf(_("Unknown network specified in -noproxy: '%s'"), snet.c_str()));
+ SetNoProxy(net);
+ }
+ }
- std::ostringstream strErrors;
- //
- // Load data files
- //
- if (fDaemon)
- fprintf(stdout, "Bitcoin server starting\n");
- int64 nStart;
+ fNameLookup = GetBoolArg("-dns");
+ fProxyNameLookup = GetBoolArg("-proxydns");
+ if (fProxyNameLookup)
+ fNameLookup = true;
+ fNoListen = !GetBoolArg("-listen", true);
+ nSocksVersion = GetArg("-socks", 5);
+ if (nSocksVersion != 4 && nSocksVersion != 5)
+ return InitError(strprintf(_("Unknown -socks proxy version requested: %i"), nSocksVersion));
- InitMessage(_("Loading addresses..."));
- printf("Loading addresses...\n");
- nStart = GetTimeMillis();
+ if (mapArgs.count("-onlynet")) {
+ std::set<enum Network> nets;
+ BOOST_FOREACH(std::string snet, mapMultiArgs["-onlynet"]) {
+ enum Network net = ParseNetwork(snet);
+ if (net == NET_UNROUTABLE)
+ return InitError(strprintf(_("Unknown network specified in -onlynet: '%s'"), snet.c_str()));
+ nets.insert(net);
+ }
+ for (int n = 0; n < NET_MAX; n++) {
+ enum Network net = (enum Network)n;
+ if (!nets.count(net))
+ SetLimited(net);
+ }
+ }
+
+ BOOST_FOREACH(string strDest, mapMultiArgs["-seednode"])
+ AddOneShot(strDest);
+ bool fBound = false;
+ if (!fNoListen)
{
- CAddrDB adb;
- if (!adb.Read(addrman))
- printf("Invalid or missing peers.dat; recreating\n");
+ std::string strError;
+ if (mapArgs.count("-bind")) {
+ BOOST_FOREACH(std::string strBind, mapMultiArgs["-bind"]) {
+ CService addrBind;
+ if (!Lookup(strBind.c_str(), addrBind, GetListenPort(), false))
+ return InitError(strprintf(_("Cannot resolve -bind address: '%s'"), strBind.c_str()));
+ fBound |= Bind(addrBind);
+ }
+ } else {
+ struct in_addr inaddr_any;
+ inaddr_any.s_addr = INADDR_ANY;
+ if (!IsLimited(NET_IPV4))
+ fBound |= Bind(CService(inaddr_any, GetListenPort()));
+#ifdef USE_IPV6
+ if (!IsLimited(NET_IPV6))
+ fBound |= Bind(CService(in6addr_any, GetListenPort()));
+#endif
+ }
+ if (!fBound)
+ return InitError(_("Not listening on any port"));
}
- printf("Loaded %i addresses from peers.dat %"PRI64d"ms\n",
- addrman.size(), GetTimeMillis() - nStart);
+ if (mapArgs.count("-externalip"))
+ {
+ BOOST_FOREACH(string strAddr, mapMultiArgs["-externalip"]) {
+ CService addrLocal(strAddr, GetListenPort(), fNameLookup);
+ if (!addrLocal.IsValid())
+ return InitError(strprintf(_("Cannot resolve -externalip address: '%s'"), strAddr.c_str()));
+ AddLocal(CService(strAddr, GetListenPort(), fNameLookup), LOCAL_MANUAL);
+ }
+ }
+
+ // ********************************************************* Step 6: load blockchain
+
+ if (GetBoolArg("-loadblockindextest"))
+ {
+ CTxDB txdb("r");
+ txdb.LoadBlockIndex();
+ PrintBlockTree();
+ return false;
+ }
- InitMessage(_("Loading block index..."));
+ uiInterface.InitMessage(_("Loading block index..."));
printf("Loading block index...\n");
nStart = GetTimeMillis();
if (!LoadBlockIndex())
@@ -396,17 +530,38 @@ bool AppInit2()
}
printf(" block index %15"PRI64d"ms\n", GetTimeMillis() - nStart);
- if (mapArgs.count("-loadblock"))
+ if (GetBoolArg("-printblockindex") || GetBoolArg("-printblocktree"))
{
- BOOST_FOREACH(string strFile, mapMultiArgs["-loadblock"])
+ PrintBlockTree();
+ return false;
+ }
+
+ if (mapArgs.count("-printblock"))
+ {
+ string strMatch = mapArgs["-printblock"];
+ int nFound = 0;
+ for (map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.begin(); mi != mapBlockIndex.end(); ++mi)
{
- FILE *file = fopen(strFile.c_str(), "rb");
- if (file)
- LoadExternalBlockFile(file);
+ uint256 hash = (*mi).first;
+ if (strncmp(hash.ToString().c_str(), strMatch.c_str(), strMatch.size()) == 0)
+ {
+ CBlockIndex* pindex = (*mi).second;
+ CBlock block;
+ block.ReadFromDisk(pindex);
+ block.BuildMerkleTree();
+ block.print();
+ printf("\n");
+ nFound++;
+ }
}
+ if (nFound == 0)
+ printf("No blocks matching %s were found\n", strMatch.c_str());
+ return false;
}
- InitMessage(_("Loading wallet..."));
+ // ********************************************************* Step 7: load wallet
+
+ uiInterface.InitMessage(_("Loading wallet..."));
printf("Loading wallet...\n");
nStart = GetTimeMillis();
bool fFirstRun;
@@ -474,199 +629,71 @@ bool AppInit2()
}
if (pindexBest != pindexRescan)
{
- InitMessage(_("Rescanning..."));
+ uiInterface.InitMessage(_("Rescanning..."));
printf("Rescanning last %i blocks (from block %i)...\n", pindexBest->nHeight - pindexRescan->nHeight, pindexRescan->nHeight);
nStart = GetTimeMillis();
pwalletMain->ScanForWalletTransactions(pindexRescan, true);
printf(" rescan %15"PRI64d"ms\n", GetTimeMillis() - nStart);
}
- InitMessage(_("Done loading"));
- printf("Done loading\n");
-
- //// debug print
- printf("mapBlockIndex.size() = %d\n", mapBlockIndex.size());
- printf("nBestHeight = %d\n", nBestHeight);
- printf("setKeyPool.size() = %d\n", pwalletMain->setKeyPool.size());
- printf("mapWallet.size() = %d\n", pwalletMain->mapWallet.size());
- printf("mapAddressBook.size() = %d\n", pwalletMain->mapAddressBook.size());
-
- if (!strErrors.str().empty())
- return InitError(strErrors.str());
-
- // Add wallet transactions that aren't already in a block to mapTransactions
- pwalletMain->ReacceptWalletTransactions();
-
- // Note: Bitcoin-Qt stores several settings in the wallet, so we want
- // to load the wallet BEFORE parsing command-line arguments, so
- // the command-line/bitcoin.conf settings override GUI setting.
-
- //
- // Parameters
- //
- if (GetBoolArg("-printblockindex") || GetBoolArg("-printblocktree"))
- {
- PrintBlockTree();
- return false;
- }
-
- if (mapArgs.count("-timeout"))
- {
- int nNewTimeout = GetArg("-timeout", 5000);
- if (nNewTimeout > 0 && nNewTimeout < 600000)
- nConnectTimeout = nNewTimeout;
- }
+ // ********************************************************* Step 8: import blocks
- if (mapArgs.count("-printblock"))
+ if (mapArgs.count("-loadblock"))
{
- string strMatch = mapArgs["-printblock"];
- int nFound = 0;
- for (map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.begin(); mi != mapBlockIndex.end(); ++mi)
+ BOOST_FOREACH(string strFile, mapMultiArgs["-loadblock"])
{
- uint256 hash = (*mi).first;
- if (strncmp(hash.ToString().c_str(), strMatch.c_str(), strMatch.size()) == 0)
- {
- CBlockIndex* pindex = (*mi).second;
- CBlock block;
- block.ReadFromDisk(pindex);
- block.BuildMerkleTree();
- block.print();
- printf("\n");
- nFound++;
- }
- }
- if (nFound == 0)
- printf("No blocks matching %s were found\n", strMatch.c_str());
- return false;
- }
-
- if (mapArgs.count("-proxy"))
- {
- fUseProxy = true;
- addrProxy = CService(mapArgs["-proxy"], 9050);
- if (!addrProxy.IsValid())
- return InitError(strprintf(_("Invalid -proxy address: '%s'"), mapArgs["-proxy"].c_str()));
- }
-
- if (mapArgs.count("-noproxy"))
- {
- BOOST_FOREACH(std::string snet, mapMultiArgs["-noproxy"]) {
- enum Network net = ParseNetwork(snet);
- if (net == NET_UNROUTABLE)
- return InitError(strprintf(_("Unknown network specified in -noproxy: '%s'"), snet.c_str()));
- SetNoProxy(net);
- }
- }
-
- if (mapArgs.count("-connect"))
- SoftSetBoolArg("-dnsseed", false);
-
- // even in Tor mode, if -bind is specified, you really want -listen
- if (mapArgs.count("-bind"))
- SoftSetBoolArg("-listen", true);
-
- bool fTor = (fUseProxy && addrProxy.GetPort() == 9050);
- if (fTor)
- {
- // Use SoftSetBoolArg here so user can override any of these if they wish.
- // Note: the GetBoolArg() calls for all of these must happen later.
- SoftSetBoolArg("-listen", false);
- SoftSetBoolArg("-irc", false);
- SoftSetBoolArg("-proxydns", true);
- SoftSetBoolArg("-upnp", false);
- SoftSetBoolArg("-discover", false);
- }
-
- if (mapArgs.count("-onlynet")) {
- std::set<enum Network> nets;
- BOOST_FOREACH(std::string snet, mapMultiArgs["-onlynet"]) {
- enum Network net = ParseNetwork(snet);
- if (net == NET_UNROUTABLE)
- return InitError(strprintf(_("Unknown network specified in -onlynet: '%s'"), snet.c_str()));
- nets.insert(net);
- }
- for (int n = 0; n < NET_MAX; n++) {
- enum Network net = (enum Network)n;
- if (!nets.count(net))
- SetLimited(net);
+ FILE *file = fopen(strFile.c_str(), "rb");
+ if (file)
+ LoadExternalBlockFile(file);
}
}
- fNameLookup = GetBoolArg("-dns");
- fProxyNameLookup = GetBoolArg("-proxydns");
- if (fProxyNameLookup)
- fNameLookup = true;
- fNoListen = !GetBoolArg("-listen", true);
- nSocksVersion = GetArg("-socks", 5);
- if (nSocksVersion != 4 && nSocksVersion != 5)
- return InitError(strprintf(_("Unknown -socks proxy version requested: %i"), nSocksVersion));
+ // ********************************************************* Step 9: load peers
- BOOST_FOREACH(string strDest, mapMultiArgs["-seednode"])
- AddOneShot(strDest);
-
- // Continue to put "/P2SH/" in the coinbase to monitor
- // BIP16 support.
- // This can be removed eventually...
- const char* pszP2SH = "/P2SH/";
- COINBASE_FLAGS << std::vector<unsigned char>(pszP2SH, pszP2SH+strlen(pszP2SH));
+ uiInterface.InitMessage(_("Loading addresses..."));
+ printf("Loading addresses...\n");
+ nStart = GetTimeMillis();
- bool fBound = false;
- if (!fNoListen)
{
- std::string strError;
- if (mapArgs.count("-bind")) {
- BOOST_FOREACH(std::string strBind, mapMultiArgs["-bind"]) {
- CService addrBind;
- if (!Lookup(strBind.c_str(), addrBind, GetListenPort(), false))
- return InitError(strprintf(_("Cannot resolve -bind address: '%s'"), strBind.c_str()));
- fBound |= Bind(addrBind);
- }
- } else {
- struct in_addr inaddr_any;
- inaddr_any.s_addr = INADDR_ANY;
- if (!IsLimited(NET_IPV4))
- fBound |= Bind(CService(inaddr_any, GetListenPort()));
-#ifdef USE_IPV6
- if (!IsLimited(NET_IPV6))
- fBound |= Bind(CService(in6addr_any, GetListenPort()));
-#endif
- }
- if (!fBound)
- return InitError(_("Not listening on any port"));
+ CAddrDB adb;
+ if (!adb.Read(addrman))
+ printf("Invalid or missing peers.dat; recreating\n");
}
- if (mapArgs.count("-externalip"))
- {
- BOOST_FOREACH(string strAddr, mapMultiArgs["-externalip"]) {
- CService addrLocal(strAddr, GetListenPort(), fNameLookup);
- if (!addrLocal.IsValid())
- return InitError(strprintf(_("Cannot resolve -externalip address: '%s'"), strAddr.c_str()));
- AddLocal(CService(strAddr, GetListenPort(), fNameLookup), LOCAL_MANUAL);
- }
- }
+ printf("Loaded %i addresses from peers.dat %"PRI64d"ms\n",
+ addrman.size(), GetTimeMillis() - nStart);
- if (mapArgs.count("-paytxfee"))
- {
- if (!ParseMoney(mapArgs["-paytxfee"], nTransactionFee))
- return InitError(strprintf(_("Invalid amount for -paytxfee=<amount>: '%s'"), mapArgs["-paytxfee"].c_str()));
- if (nTransactionFee > 0.25 * COIN)
- InitWarning(_("Warning: -paytxfee is set very high. This is the transaction fee you will pay if you send a transaction."));
- }
+ // ********************************************************* Step 10: start node
- //
- // Start the node
- //
if (!CheckDiskSpace())
return false;
RandAddSeedPerfmon();
+ //// debug print
+ printf("mapBlockIndex.size() = %d\n", mapBlockIndex.size());
+ printf("nBestHeight = %d\n", nBestHeight);
+ printf("setKeyPool.size() = %d\n", pwalletMain->setKeyPool.size());
+ printf("mapWallet.size() = %d\n", pwalletMain->mapWallet.size());
+ printf("mapAddressBook.size() = %d\n", pwalletMain->mapAddressBook.size());
+
if (!CreateThread(StartNode, NULL))
InitError(_("Error: could not start node"));
if (fServer)
CreateThread(ThreadRPCServer, NULL);
+ // ********************************************************* Step 11: finished
+
+ uiInterface.InitMessage(_("Done loading"));
+ printf("Done loading\n");
+
+ if (!strErrors.str().empty())
+ return InitError(strErrors.str());
+
+ // Add wallet transactions that aren't already in a block to mapTransactions
+ pwalletMain->ReacceptWalletTransactions();
+
#if !defined(QT_GUI)
// Loop until process is exit()ed from shutdown() function,
// called from ThreadRPCServer thread when a "stop" command is received.
diff --git a/src/init.h b/src/init.h
index 9a8f98cce9..6159ededa5 100644
--- a/src/init.h
+++ b/src/init.h
@@ -1,7 +1,7 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
-// file license.txt or http://www.opensource.org/licenses/mit-license.php.
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_INIT_H
#define BITCOIN_INIT_H
@@ -10,7 +10,6 @@
extern CWallet* pwalletMain;
void Shutdown(void* parg);
-bool AppInit(int argc, char* argv[]);
bool AppInit2();
std::string HelpMessage();
diff --git a/src/irc.cpp b/src/irc.cpp
index f21772ac1f..1049188411 100644
--- a/src/irc.cpp
+++ b/src/irc.cpp
@@ -1,7 +1,7 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
-// file license.txt or http://www.opensource.org/licenses/mit-license.php.
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "irc.h"
#include "net.h"
diff --git a/src/irc.h b/src/irc.h
index a6073199ec..119aeb3fda 100644
--- a/src/irc.h
+++ b/src/irc.h
@@ -1,7 +1,7 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
-// file license.txt or http://www.opensource.org/licenses/mit-license.php.
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_IRC_H
#define BITCOIN_IRC_H
diff --git a/src/key.cpp b/src/key.cpp
index e0844412d9..4172d6be5e 100644
--- a/src/key.cpp
+++ b/src/key.cpp
@@ -1,9 +1,16 @@
// Copyright (c) 2009-2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
-// file license.txt or http://www.opensource.org/licenses/mit-license.php.
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <openssl/ec.h>
+#include <map>
+
+#include <boost/tuple/tuple.hpp>
#include <openssl/ecdsa.h>
+#include <openssl/obj_mac.h>
+
+#include "key.h"
+#include "sync.h"
+#include "util.h"
// Generate a private key from just the secret parameter
int EC_KEY_regenerate_key(EC_KEY *eckey, BIGNUM *priv_key)
@@ -115,3 +122,326 @@ err:
if (Q != NULL) EC_POINT_free(Q);
return ret;
}
+
+void CKey::SetCompressedPubKey()
+{
+ EC_KEY_set_conv_form(pkey, POINT_CONVERSION_COMPRESSED);
+ fCompressedPubKey = true;
+}
+
+void CKey::Reset()
+{
+ fCompressedPubKey = false;
+ pkey = EC_KEY_new_by_curve_name(NID_secp256k1);
+ if (pkey == NULL)
+ throw key_error("CKey::CKey() : EC_KEY_new_by_curve_name failed");
+ fSet = false;
+}
+
+CKey::CKey()
+{
+ Reset();
+}
+
+CKey::CKey(const CKey& b)
+{
+ pkey = EC_KEY_dup(b.pkey);
+ if (pkey == NULL)
+ throw key_error("CKey::CKey(const CKey&) : EC_KEY_dup failed");
+ fSet = b.fSet;
+}
+
+CKey& CKey::operator=(const CKey& b)
+{
+ if (!EC_KEY_copy(pkey, b.pkey))
+ throw key_error("CKey::operator=(const CKey&) : EC_KEY_copy failed");
+ fSet = b.fSet;
+ return (*this);
+}
+
+CKey::~CKey()
+{
+ EC_KEY_free(pkey);
+}
+
+bool CKey::IsNull() const
+{
+ return !fSet;
+}
+
+bool CKey::IsCompressed() const
+{
+ return fCompressedPubKey;
+}
+
+void CKey::MakeNewKey(bool fCompressed)
+{
+ if (!EC_KEY_generate_key(pkey))
+ throw key_error("CKey::MakeNewKey() : EC_KEY_generate_key failed");
+ if (fCompressed)
+ SetCompressedPubKey();
+ fSet = true;
+}
+
+bool CKey::SetPrivKey(const CPrivKey& vchPrivKey)
+{
+ const unsigned char* pbegin = &vchPrivKey[0];
+ if (!d2i_ECPrivateKey(&pkey, &pbegin, vchPrivKey.size()))
+ return false;
+ fSet = true;
+ return true;
+}
+
+bool CKey::SetSecret(const CSecret& vchSecret, bool fCompressed)
+{
+ EC_KEY_free(pkey);
+ pkey = EC_KEY_new_by_curve_name(NID_secp256k1);
+ if (pkey == NULL)
+ throw key_error("CKey::SetSecret() : EC_KEY_new_by_curve_name failed");
+ 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)
+ 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)
+ SetCompressedPubKey();
+ return true;
+}
+
+CSecret CKey::GetSecret(bool &fCompressed) const
+{
+ CSecret vchRet;
+ vchRet.resize(32);
+ const BIGNUM *bn = EC_KEY_get0_private_key(pkey);
+ int nBytes = BN_num_bytes(bn);
+ if (bn == NULL)
+ throw key_error("CKey::GetSecret() : EC_KEY_get0_private_key failed");
+ int n=BN_bn2bin(bn,&vchRet[32 - nBytes]);
+ if (n != nBytes)
+ throw key_error("CKey::GetSecret(): BN_bn2bin failed");
+ fCompressed = fCompressedPubKey;
+ return vchRet;
+}
+
+CPrivKey CKey::GetPrivKey() const
+{
+ int nSize = i2d_ECPrivateKey(pkey, NULL);
+ if (!nSize)
+ throw key_error("CKey::GetPrivKey() : i2d_ECPrivateKey failed");
+ CPrivKey vchPrivKey(nSize, 0);
+ unsigned char* pbegin = &vchPrivKey[0];
+ if (i2d_ECPrivateKey(pkey, &pbegin) != nSize)
+ throw key_error("CKey::GetPrivKey() : i2d_ECPrivateKey returned unexpected size");
+ return vchPrivKey;
+}
+
+bool CKey::SetPubKey(const std::vector<unsigned char>& vchPubKey)
+{
+ const unsigned char* pbegin = &vchPubKey[0];
+ if (!o2i_ECPublicKey(&pkey, &pbegin, vchPubKey.size()))
+ return false;
+ fSet = true;
+ if (vchPubKey.size() == 33)
+ SetCompressedPubKey();
+ return true;
+}
+
+std::vector<unsigned char> CKey::GetPubKey() const
+{
+ int nSize = i2o_ECPublicKey(pkey, NULL);
+ if (!nSize)
+ throw key_error("CKey::GetPubKey() : i2o_ECPublicKey failed");
+ std::vector<unsigned char> vchPubKey(nSize, 0);
+ unsigned char* pbegin = &vchPubKey[0];
+ if (i2o_ECPublicKey(pkey, &pbegin) != nSize)
+ throw key_error("CKey::GetPubKey() : i2o_ECPublicKey returned unexpected size");
+ return vchPubKey;
+}
+
+bool CKey::Sign(uint256 hash, std::vector<unsigned char>& vchSig)
+{
+ unsigned int nSize = ECDSA_size(pkey);
+ vchSig.resize(nSize); // Make sure it is big enough
+ if (!ECDSA_sign(0, (unsigned char*)&hash, sizeof(hash), &vchSig[0], &nSize, pkey))
+ {
+ vchSig.clear();
+ return false;
+ }
+ vchSig.resize(nSize); // Shrink to fit actual size
+ return true;
+}
+
+// create a compact signature (65 bytes), which allows reconstructing the used public key
+// The format is one header byte, followed by two times 32 bytes for the serialized r and s values.
+// The header byte: 0x1B = first key with even y, 0x1C = first key with odd y,
+// 0x1D = second key with even y, 0x1E = second key with odd y
+bool CKey::SignCompact(uint256 hash, std::vector<unsigned char>& vchSig)
+{
+ bool fOk = false;
+ ECDSA_SIG *sig = ECDSA_do_sign((unsigned char*)&hash, sizeof(hash), pkey);
+ if (sig==NULL)
+ return false;
+ vchSig.clear();
+ vchSig.resize(65,0);
+ int nBitsR = BN_num_bits(sig->r);
+ int nBitsS = BN_num_bits(sig->s);
+ if (nBitsR <= 256 && nBitsS <= 256)
+ {
+ int nRecId = -1;
+ for (int i=0; i<4; i++)
+ {
+ CKey keyRec;
+ keyRec.fSet = true;
+ if (fCompressedPubKey)
+ keyRec.SetCompressedPubKey();
+ if (ECDSA_SIG_recover_key_GFp(keyRec.pkey, sig, (unsigned char*)&hash, sizeof(hash), i, 1) == 1)
+ if (keyRec.GetPubKey() == this->GetPubKey())
+ {
+ nRecId = i;
+ break;
+ }
+ }
+
+ if (nRecId == -1)
+ throw key_error("CKey::SignCompact() : unable to construct recoverable key");
+
+ vchSig[0] = nRecId+27+(fCompressedPubKey ? 4 : 0);
+ BN_bn2bin(sig->r,&vchSig[33-(nBitsR+7)/8]);
+ BN_bn2bin(sig->s,&vchSig[65-(nBitsS+7)/8]);
+ fOk = true;
+ }
+ ECDSA_SIG_free(sig);
+ return fOk;
+}
+
+// reconstruct public key from a compact signature
+// This is only slightly more CPU intensive than just verifying it.
+// If this function succeeds, the recovered public key is guaranteed to be valid
+// (the signature is a valid signature of the given data for that key)
+bool CKey::SetCompactSignature(uint256 hash, const std::vector<unsigned char>& vchSig)
+{
+ if (vchSig.size() != 65)
+ return false;
+ int nV = vchSig[0];
+ if (nV<27 || nV>=35)
+ return false;
+ ECDSA_SIG *sig = ECDSA_SIG_new();
+ BN_bin2bn(&vchSig[1],32,sig->r);
+ BN_bin2bn(&vchSig[33],32,sig->s);
+
+ EC_KEY_free(pkey);
+ pkey = EC_KEY_new_by_curve_name(NID_secp256k1);
+ if (nV >= 31)
+ {
+ SetCompressedPubKey();
+ nV -= 4;
+ }
+ if (ECDSA_SIG_recover_key_GFp(pkey, sig, (unsigned char*)&hash, sizeof(hash), nV - 27, 0) == 1)
+ {
+ fSet = true;
+ ECDSA_SIG_free(sig);
+ return true;
+ }
+ return false;
+}
+
+// Valid signature cache, to avoid doing expensive ECDSA signature checking
+// twice for every transaction (once when accepted into memory pool, and
+// again when accepted into the block chain)
+
+// sigdata_type is (signature hash, signature, public key):
+typedef boost::tuple<uint256, std::vector<unsigned char>, std::vector<unsigned char> > sigdata_type;
+static std::set< sigdata_type> setValidSigCache;
+static CCriticalSection cs_sigcache;
+
+static bool
+GetValidSigCache(uint256 hash, const std::vector<unsigned char>& vchSig, const std::vector<unsigned char>& pubKey)
+{
+ LOCK(cs_sigcache);
+
+ sigdata_type k(hash, vchSig, pubKey);
+ std::set<sigdata_type>::iterator mi = setValidSigCache.find(k);
+ if (mi != setValidSigCache.end())
+ return true;
+ return false;
+}
+
+static void
+SetValidSigCache(uint256 hash, const std::vector<unsigned char>& vchSig, const std::vector<unsigned char>& pubKey)
+{
+ // DoS prevention: limit cache size to less than 10MB
+ // (~200 bytes per cache entry times 50,000 entries)
+ // Since there are a maximum of 20,000 signature operations per block
+ // 50,000 is a reasonable default.
+ int64 nMaxCacheSize = GetArg("-maxsigcachesize", 50000);
+ if (nMaxCacheSize <= 0) return;
+
+ LOCK(cs_sigcache);
+
+ while (setValidSigCache.size() > nMaxCacheSize)
+ {
+ // Evict a random entry. Random because that helps
+ // foil would-be DoS attackers who might try to pre-generate
+ // and re-use a set of valid signatures just-slightly-greater
+ // than our cache size.
+ uint256 randomHash = GetRandHash();
+ std::vector<unsigned char> unused;
+ std::set<sigdata_type>::iterator it =
+ setValidSigCache.lower_bound(sigdata_type(randomHash, unused, unused));
+ if (it == setValidSigCache.end())
+ it = setValidSigCache.begin();
+ setValidSigCache.erase(*it);
+ }
+
+ sigdata_type k(hash, vchSig, pubKey);
+ setValidSigCache.insert(k);
+}
+
+
+bool CKey::Verify(uint256 hash, const std::vector<unsigned char>& vchSig)
+{
+ if (GetValidSigCache(hash, vchSig, GetPubKey()))
+ return true;
+
+ // -1 = error, 0 = bad sig, 1 = good
+ if (ECDSA_verify(0, (unsigned char*)&hash, sizeof(hash), &vchSig[0], vchSig.size(), pkey) != 1)
+ return false;
+
+ // good sig
+ SetValidSigCache(hash, vchSig, GetPubKey());
+ return true;
+}
+
+bool CKey::VerifyCompact(uint256 hash, const std::vector<unsigned char>& vchSig)
+{
+ if (GetValidSigCache(hash, vchSig, GetPubKey()))
+ return true;
+
+ CKey key;
+ if (!key.SetCompactSignature(hash, vchSig))
+ return false;
+ if (GetPubKey() != key.GetPubKey())
+ return false;
+
+ SetValidSigCache(hash, vchSig, GetPubKey());
+ return true;
+}
+
+bool CKey::IsValid()
+{
+ if (!fSet)
+ return false;
+
+ bool fCompr;
+ CSecret secret = GetSecret(fCompr);
+ CKey key2;
+ key2.SetSecret(secret, fCompr);
+ return GetPubKey() == key2.GetPubKey();
+}
diff --git a/src/key.h b/src/key.h
index 1579cdc40a..bd58c84375 100644
--- a/src/key.h
+++ b/src/key.h
@@ -1,20 +1,18 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
-// file license.txt or http://www.opensource.org/licenses/mit-license.php.
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_KEY_H
#define BITCOIN_KEY_H
#include <stdexcept>
#include <vector>
-#include <openssl/ec.h>
-#include <openssl/ecdsa.h>
-#include <openssl/obj_mac.h>
-
#include "allocators.h"
#include "uint256.h"
+#include <openssl/ec.h> // for EC_KEY definition
+
// secp160k1
// const unsigned int PRIVATE_KEY_SIZE = 192;
// const unsigned int PUBLIC_KEY_SIZE = 41;
@@ -38,9 +36,6 @@
// see www.keylength.com
// script supports up to 75 for single byte push
-int extern EC_KEY_regenerate_key(EC_KEY *eckey, BIGNUM *priv_key);
-int extern ECDSA_SIG_recover_key_GFp(EC_KEY *eckey, ECDSA_SIG *ecsig, const unsigned char *msg, int msglen, int recid, int check);
-
class key_error : public std::runtime_error
{
public:
@@ -62,267 +57,50 @@ protected:
bool fSet;
bool fCompressedPubKey;
- void SetCompressedPubKey()
- {
- EC_KEY_set_conv_form(pkey, POINT_CONVERSION_COMPRESSED);
- fCompressedPubKey = true;
- }
+ void SetCompressedPubKey();
public:
- void Reset()
- {
- fCompressedPubKey = false;
- pkey = EC_KEY_new_by_curve_name(NID_secp256k1);
- if (pkey == NULL)
- throw key_error("CKey::CKey() : EC_KEY_new_by_curve_name failed");
- fSet = false;
- }
-
- CKey()
- {
- Reset();
- }
-
- CKey(const CKey& b)
- {
- pkey = EC_KEY_dup(b.pkey);
- if (pkey == NULL)
- throw key_error("CKey::CKey(const CKey&) : EC_KEY_dup failed");
- fSet = b.fSet;
- }
-
- CKey& operator=(const CKey& b)
- {
- if (!EC_KEY_copy(pkey, b.pkey))
- throw key_error("CKey::operator=(const CKey&) : EC_KEY_copy failed");
- fSet = b.fSet;
- return (*this);
- }
-
- ~CKey()
- {
- EC_KEY_free(pkey);
- }
-
- bool IsNull() const
- {
- return !fSet;
- }
+ void Reset();
- bool IsCompressed() const
- {
- return fCompressedPubKey;
- }
+ CKey();
+ CKey(const CKey& b);
- void MakeNewKey(bool fCompressed)
- {
- if (!EC_KEY_generate_key(pkey))
- throw key_error("CKey::MakeNewKey() : EC_KEY_generate_key failed");
- if (fCompressed)
- SetCompressedPubKey();
- fSet = true;
- }
+ CKey& operator=(const CKey& b);
- bool SetPrivKey(const CPrivKey& vchPrivKey)
- {
- const unsigned char* pbegin = &vchPrivKey[0];
- if (!d2i_ECPrivateKey(&pkey, &pbegin, vchPrivKey.size()))
- return false;
- fSet = true;
- return true;
- }
+ ~CKey();
- bool SetSecret(const CSecret& vchSecret, bool fCompressed = false)
- {
- EC_KEY_free(pkey);
- pkey = EC_KEY_new_by_curve_name(NID_secp256k1);
- if (pkey == NULL)
- throw key_error("CKey::SetSecret() : EC_KEY_new_by_curve_name failed");
- 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)
- 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)
- SetCompressedPubKey();
- return true;
- }
+ bool IsNull() const;
+ bool IsCompressed() const;
- CSecret GetSecret(bool &fCompressed) const
- {
- CSecret vchRet;
- vchRet.resize(32);
- const BIGNUM *bn = EC_KEY_get0_private_key(pkey);
- int nBytes = BN_num_bytes(bn);
- if (bn == NULL)
- throw key_error("CKey::GetSecret() : EC_KEY_get0_private_key failed");
- int n=BN_bn2bin(bn,&vchRet[32 - nBytes]);
- if (n != nBytes)
- throw key_error("CKey::GetSecret(): BN_bn2bin failed");
- fCompressed = fCompressedPubKey;
- return vchRet;
- }
+ void MakeNewKey(bool fCompressed);
+ bool SetPrivKey(const CPrivKey& vchPrivKey);
+ bool SetSecret(const CSecret& vchSecret, bool fCompressed = false);
+ CSecret GetSecret(bool &fCompressed) const;
+ CPrivKey GetPrivKey() const;
+ bool SetPubKey(const std::vector<unsigned char>& vchPubKey);
+ std::vector<unsigned char> GetPubKey() const;
- CPrivKey GetPrivKey() const
- {
- int nSize = i2d_ECPrivateKey(pkey, NULL);
- if (!nSize)
- throw key_error("CKey::GetPrivKey() : i2d_ECPrivateKey failed");
- CPrivKey vchPrivKey(nSize, 0);
- unsigned char* pbegin = &vchPrivKey[0];
- if (i2d_ECPrivateKey(pkey, &pbegin) != nSize)
- throw key_error("CKey::GetPrivKey() : i2d_ECPrivateKey returned unexpected size");
- return vchPrivKey;
- }
-
- bool SetPubKey(const std::vector<unsigned char>& vchPubKey)
- {
- const unsigned char* pbegin = &vchPubKey[0];
- if (!o2i_ECPublicKey(&pkey, &pbegin, vchPubKey.size()))
- return false;
- fSet = true;
- if (vchPubKey.size() == 33)
- SetCompressedPubKey();
- return true;
- }
-
- std::vector<unsigned char> GetPubKey() const
- {
- int nSize = i2o_ECPublicKey(pkey, NULL);
- if (!nSize)
- throw key_error("CKey::GetPubKey() : i2o_ECPublicKey failed");
- std::vector<unsigned char> vchPubKey(nSize, 0);
- unsigned char* pbegin = &vchPubKey[0];
- if (i2o_ECPublicKey(pkey, &pbegin) != nSize)
- throw key_error("CKey::GetPubKey() : i2o_ECPublicKey returned unexpected size");
- return vchPubKey;
- }
-
- bool Sign(uint256 hash, std::vector<unsigned char>& vchSig)
- {
- unsigned int nSize = ECDSA_size(pkey);
- vchSig.resize(nSize); // Make sure it is big enough
- if (!ECDSA_sign(0, (unsigned char*)&hash, sizeof(hash), &vchSig[0], &nSize, pkey))
- {
- vchSig.clear();
- return false;
- }
- vchSig.resize(nSize); // Shrink to fit actual size
- return true;
- }
+ bool Sign(uint256 hash, std::vector<unsigned char>& vchSig);
// create a compact signature (65 bytes), which allows reconstructing the used public key
// The format is one header byte, followed by two times 32 bytes for the serialized r and s values.
// The header byte: 0x1B = first key with even y, 0x1C = first key with odd y,
// 0x1D = second key with even y, 0x1E = second key with odd y
- bool SignCompact(uint256 hash, std::vector<unsigned char>& vchSig)
- {
- bool fOk = false;
- ECDSA_SIG *sig = ECDSA_do_sign((unsigned char*)&hash, sizeof(hash), pkey);
- if (sig==NULL)
- return false;
- vchSig.clear();
- vchSig.resize(65,0);
- int nBitsR = BN_num_bits(sig->r);
- int nBitsS = BN_num_bits(sig->s);
- if (nBitsR <= 256 && nBitsS <= 256)
- {
- int nRecId = -1;
- for (int i=0; i<4; i++)
- {
- CKey keyRec;
- keyRec.fSet = true;
- if (fCompressedPubKey)
- keyRec.SetCompressedPubKey();
- if (ECDSA_SIG_recover_key_GFp(keyRec.pkey, sig, (unsigned char*)&hash, sizeof(hash), i, 1) == 1)
- if (keyRec.GetPubKey() == this->GetPubKey())
- {
- nRecId = i;
- break;
- }
- }
-
- if (nRecId == -1)
- throw key_error("CKey::SignCompact() : unable to construct recoverable key");
-
- vchSig[0] = nRecId+27+(fCompressedPubKey ? 4 : 0);
- BN_bn2bin(sig->r,&vchSig[33-(nBitsR+7)/8]);
- BN_bn2bin(sig->s,&vchSig[65-(nBitsS+7)/8]);
- fOk = true;
- }
- ECDSA_SIG_free(sig);
- return fOk;
- }
+ bool SignCompact(uint256 hash, std::vector<unsigned char>& vchSig);
// reconstruct public key from a compact signature
// This is only slightly more CPU intensive than just verifying it.
// If this function succeeds, the recovered public key is guaranteed to be valid
// (the signature is a valid signature of the given data for that key)
- bool SetCompactSignature(uint256 hash, const std::vector<unsigned char>& vchSig)
- {
- if (vchSig.size() != 65)
- return false;
- int nV = vchSig[0];
- if (nV<27 || nV>=35)
- return false;
- ECDSA_SIG *sig = ECDSA_SIG_new();
- BN_bin2bn(&vchSig[1],32,sig->r);
- BN_bin2bn(&vchSig[33],32,sig->s);
-
- EC_KEY_free(pkey);
- pkey = EC_KEY_new_by_curve_name(NID_secp256k1);
- if (nV >= 31)
- {
- SetCompressedPubKey();
- nV -= 4;
- }
- if (ECDSA_SIG_recover_key_GFp(pkey, sig, (unsigned char*)&hash, sizeof(hash), nV - 27, 0) == 1)
- {
- fSet = true;
- ECDSA_SIG_free(sig);
- return true;
- }
- return false;
- }
+ bool SetCompactSignature(uint256 hash, const std::vector<unsigned char>& vchSig);
- bool Verify(uint256 hash, const std::vector<unsigned char>& vchSig)
- {
- // -1 = error, 0 = bad sig, 1 = good
- if (ECDSA_verify(0, (unsigned char*)&hash, sizeof(hash), &vchSig[0], vchSig.size(), pkey) != 1)
- return false;
- return true;
- }
+ bool Verify(uint256 hash, const std::vector<unsigned char>& vchSig);
// Verify a compact signature
- bool VerifyCompact(uint256 hash, const std::vector<unsigned char>& vchSig)
- {
- CKey key;
- if (!key.SetCompactSignature(hash, vchSig))
- return false;
- if (GetPubKey() != key.GetPubKey())
- return false;
- return true;
- }
-
- bool IsValid()
- {
- if (!fSet)
- return false;
+ bool VerifyCompact(uint256 hash, const std::vector<unsigned char>& vchSig);
- bool fCompr;
- CSecret secret = GetSecret(fCompr);
- CKey key2;
- key2.SetSecret(secret, fCompr);
- return GetPubKey() == key2.GetPubKey();
- }
+ bool IsValid();
};
#endif
diff --git a/src/keystore.cpp b/src/keystore.cpp
index 313518711b..c56e820e0f 100644
--- a/src/keystore.cpp
+++ b/src/keystore.cpp
@@ -1,7 +1,7 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
-// file license.txt or http://www.opensource.org/licenses/mit-license.php.
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "keystore.h"
#include "script.h"
@@ -73,6 +73,20 @@ bool CCryptoKeyStore::SetCrypted()
return true;
}
+bool CCryptoKeyStore::Lock()
+{
+ if (!SetCrypted())
+ return false;
+
+ {
+ LOCK(cs_KeyStore);
+ vMasterKey.clear();
+ }
+
+ NotifyStatusChanged(this);
+ return true;
+}
+
bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn)
{
{
@@ -99,6 +113,7 @@ bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn)
}
vMasterKey = vMasterKeyIn;
}
+ NotifyStatusChanged(this);
return true;
}
diff --git a/src/keystore.h b/src/keystore.h
index 52889b184e..479d6c5a2e 100644
--- a/src/keystore.h
+++ b/src/keystore.h
@@ -1,13 +1,14 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
-// file license.txt or http://www.opensource.org/licenses/mit-license.php.
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_KEYSTORE_H
#define BITCOIN_KEYSTORE_H
#include "crypter.h"
#include "sync.h"
#include "base58.h"
+#include <boost/signals2/signal.hpp>
class CScript;
@@ -143,18 +144,7 @@ public:
return result;
}
- bool Lock()
- {
- if (!SetCrypted())
- return false;
-
- {
- LOCK(cs_KeyStore);
- vMasterKey.clear();
- }
-
- return true;
- }
+ bool Lock();
virtual bool AddCryptedKey(const std::vector<unsigned char> &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret);
bool AddKey(const CKey& key);
@@ -185,6 +175,11 @@ public:
mi++;
}
}
+
+ /* Wallet status (encrypted, locked) changed.
+ * Note: Called without locks held.
+ */
+ boost::signals2::signal<void (CCryptoKeyStore* wallet)> NotifyStatusChanged;
};
#endif
diff --git a/src/main.cpp b/src/main.cpp
index f516ad65b5..9a4d7abc8c 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1,7 +1,8 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
-// file license.txt or http://www.opensource.org/licenses/mit-license.php.
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
#include "checkpoints.h"
#include "db.h"
#include "net.h"
@@ -43,7 +44,7 @@ map<uint256, CBlock*> mapOrphanBlocks;
multimap<uint256, CBlock*> mapOrphanBlocksByPrev;
map<uint256, CDataStream*> mapOrphanTransactions;
-multimap<uint256, CDataStream*> mapOrphanTransactionsByPrev;
+map<uint256, map<uint256, CDataStream*> > mapOrphanTransactionsByPrev;
// Constant stuff for coinbase transactions we create:
CScript COINBASE_FLAGS;
@@ -160,17 +161,37 @@ void static ResendWalletTransactions()
// mapOrphanTransactions
//
-void AddOrphanTx(const CDataStream& vMsg)
+bool AddOrphanTx(const CDataStream& vMsg)
{
CTransaction tx;
CDataStream(vMsg) >> tx;
uint256 hash = tx.GetHash();
if (mapOrphanTransactions.count(hash))
- return;
+ return false;
- CDataStream* pvMsg = mapOrphanTransactions[hash] = new CDataStream(vMsg);
+ CDataStream* pvMsg = new CDataStream(vMsg);
+
+ // Ignore big transactions, to avoid a
+ // send-big-orphans memory exhaustion attack. If a peer has a legitimate
+ // large transaction with a missing parent then we assume
+ // it will rebroadcast it later, after the parent transaction(s)
+ // have been mined or received.
+ // 10,000 orphans, each of which is at most 5,000 bytes big is
+ // at most 500 megabytes of orphans:
+ if (pvMsg->size() > 5000)
+ {
+ delete pvMsg;
+ printf("ignoring large orphan tx (size: %u, hash: %s)\n", pvMsg->size(), hash.ToString().substr(0,10).c_str());
+ return false;
+ }
+
+ mapOrphanTransactions[hash] = pvMsg;
BOOST_FOREACH(const CTxIn& txin, tx.vin)
- mapOrphanTransactionsByPrev.insert(make_pair(txin.prevout.hash, pvMsg));
+ mapOrphanTransactionsByPrev[txin.prevout.hash].insert(make_pair(hash, pvMsg));
+
+ printf("stored orphan tx %s (mapsz %u)\n", hash.ToString().substr(0,10).c_str(),
+ mapOrphanTransactions.size());
+ return true;
}
void static EraseOrphanTx(uint256 hash)
@@ -182,14 +203,9 @@ void static EraseOrphanTx(uint256 hash)
CDataStream(*pvMsg) >> tx;
BOOST_FOREACH(const CTxIn& txin, tx.vin)
{
- for (multimap<uint256, CDataStream*>::iterator mi = mapOrphanTransactionsByPrev.lower_bound(txin.prevout.hash);
- mi != mapOrphanTransactionsByPrev.upper_bound(txin.prevout.hash);)
- {
- if ((*mi).second == pvMsg)
- mapOrphanTransactionsByPrev.erase(mi++);
- else
- mi++;
- }
+ mapOrphanTransactionsByPrev[txin.prevout.hash].erase(hash);
+ if (mapOrphanTransactionsByPrev[txin.prevout.hash].empty())
+ mapOrphanTransactionsByPrev.erase(txin.prevout.hash);
}
delete pvMsg;
mapOrphanTransactions.erase(hash);
@@ -201,9 +217,7 @@ unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans)
while (mapOrphanTransactions.size() > nMaxOrphans)
{
// Evict a random orphan:
- std::vector<unsigned char> randbytes(32);
- RAND_bytes(&randbytes[0], 32);
- uint256 randomhash(randbytes);
+ uint256 randomhash = GetRandHash();
map<uint256, CDataStream*>::iterator it = mapOrphanTransactions.lower_bound(randomhash);
if (it == mapOrphanTransactions.end())
it = mapOrphanTransactions.begin();
@@ -946,7 +960,7 @@ void static InvalidChainFound(CBlockIndex* pindexNew)
{
bnBestInvalidWork = pindexNew->bnChainWork;
CTxDB().WriteBestInvalidWork(bnBestInvalidWork);
- MainFrameRepaint();
+ uiInterface.NotifyBlocksChanged();
}
printf("InvalidChainFound: invalid block=%s height=%d work=%s\n", pindexNew->GetBlockHash().ToString().substr(0,20).c_str(), pindexNew->nHeight, pindexNew->bnChainWork.ToString().c_str());
printf("InvalidChainFound: current best=%s height=%d work=%s\n", hashBestChain.ToString().substr(0,20).c_str(), nBestHeight, bnBestChainWork.ToString().c_str());
@@ -1154,17 +1168,28 @@ bool CTransaction::ConnectInputs(MapPrevTx inputs,
if (pindex->nBlockPos == txindex.pos.nBlockPos && pindex->nFile == txindex.pos.nFile)
return error("ConnectInputs() : tried to spend coinbase at depth %d", pindexBlock->nHeight - pindex->nHeight);
+ // Check for negative or overflow input values
+ nValueIn += txPrev.vout[prevout.n].nValue;
+ if (!MoneyRange(txPrev.vout[prevout.n].nValue) || !MoneyRange(nValueIn))
+ return DoS(100, error("ConnectInputs() : txin values out of range"));
+
+ }
+ // The first loop above does all the inexpensive checks.
+ // Only if ALL inputs pass do we perform expensive ECDSA signature checks.
+ // Helps prevent CPU exhaustion attacks.
+ for (unsigned int i = 0; i < vin.size(); i++)
+ {
+ COutPoint prevout = vin[i].prevout;
+ assert(inputs.count(prevout.hash) > 0);
+ CTxIndex& txindex = inputs[prevout.hash].first;
+ CTransaction& txPrev = inputs[prevout.hash].second;
+
// Check for conflicts (double-spend)
// This doesn't trigger the DoS code on purpose; if it did, it would make it easier
// for an attacker to attempt to split the network.
if (!txindex.vSpent[prevout.n].IsNull())
return fMiner ? false : error("ConnectInputs() : %s prev tx already used at %s", GetHash().ToString().substr(0,10).c_str(), txindex.vSpent[prevout.n].ToString().c_str());
- // Check for negative or overflow input values
- nValueIn += txPrev.vout[prevout.n].nValue;
- if (!MoneyRange(txPrev.vout[prevout.n].nValue) || !MoneyRange(nValueIn))
- return DoS(100, error("ConnectInputs() : txin values out of range"));
-
// Skip ECDSA signature verification when connecting blocks (fBlock=true)
// before the last blockchain checkpoint. This is safe because block merkle hashes are
// still computed and checked, and any change will be caught at the next checkpoint.
@@ -1646,7 +1671,7 @@ bool CBlock::AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos)
hashPrevBestCoinBase = vtx[0].GetHash();
}
- MainFrameRepaint();
+ uiInterface.NotifyBlocksChanged();
return true;
}
@@ -1857,8 +1882,8 @@ bool CheckDiskSpace(uint64 nAdditionalBytes)
string strMessage = _("Warning: Disk space is low");
strMiscWarning = strMessage;
printf("*** %s\n", strMessage.c_str());
- ThreadSafeMessageBox(strMessage, "Bitcoin", wxOK | wxICON_EXCLAMATION | wxMODAL);
- QueueShutdown();
+ uiInterface.ThreadSafeMessageBox(strMessage, "Bitcoin", CClientUIInterface::OK | CClientUIInterface::ICON_EXCLAMATION | CClientUIInterface::MODAL);
+ uiInterface.QueueShutdown();
return false;
}
return true;
@@ -2107,8 +2132,9 @@ bool LoadExternalBlockFile(FILE* fileIn)
}
}
}
- catch (std::exception &e)
- {
+ catch (std::exception &e) {
+ printf("%s() : Deserialize or I/O error caught during load\n",
+ __PRETTY_FUNCTION__);
}
}
printf("Loaded %i blocks from external file\n", nLoaded);
@@ -2175,6 +2201,18 @@ string GetWarnings(string strFor)
return "error";
}
+CAlert CAlert::getAlertByHash(const uint256 &hash)
+{
+ CAlert retval;
+ {
+ LOCK(cs_mapAlerts);
+ map<uint256, CAlert>::iterator mi = mapAlerts.find(hash);
+ if(mi != mapAlerts.end())
+ retval = mi->second;
+ }
+ return retval;
+}
+
bool CAlert::ProcessAlert()
{
if (!CheckSignature())
@@ -2191,11 +2229,13 @@ bool CAlert::ProcessAlert()
if (Cancels(alert))
{
printf("cancelling alert %d\n", alert.nID);
+ uiInterface.NotifyAlertChanged((*mi).first, CT_DELETED);
mapAlerts.erase(mi++);
}
else if (!alert.IsInEffect())
{
printf("expiring alert %d\n", alert.nID);
+ uiInterface.NotifyAlertChanged((*mi).first, CT_DELETED);
mapAlerts.erase(mi++);
}
else
@@ -2215,10 +2255,12 @@ bool CAlert::ProcessAlert()
// Add to mapAlerts
mapAlerts.insert(make_pair(GetHash(), *this));
+ // Notify UI if it applies to me
+ if(AppliesToMe())
+ uiInterface.NotifyAlertChanged(GetHash(), CT_NEW);
}
printf("accepted alert %d, AppliesToMe()=%d\n", nID, AppliesToMe());
- MainFrameRepaint();
return true;
}
@@ -2442,7 +2484,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
// at a time so the setAddrKnowns of the chosen nodes prevent repeats
static uint256 hashSalt;
if (hashSalt == 0)
- RAND_bytes((unsigned char*)&hashSalt, sizeof(hashSalt));
+ hashSalt = GetRandHash();
int64 hashAddr = addr.GetHash();
uint256 hashRand = hashSalt ^ (hashAddr<<32) ^ ((GetTime()+hashAddr)/(24*60*60));
hashRand = Hash(BEGIN(hashRand), END(hashRand));
@@ -2658,6 +2700,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
else if (strCommand == "tx")
{
vector<uint256> vWorkQueue;
+ vector<uint256> vEraseQueue;
CDataStream vMsg(vRecv);
CTxDB txdb("r");
CTransaction tx;
@@ -2673,39 +2716,45 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
RelayMessage(inv, vMsg);
mapAlreadyAskedFor.erase(inv);
vWorkQueue.push_back(inv.hash);
+ vEraseQueue.push_back(inv.hash);
// Recursively process any orphan transactions that depended on this one
for (unsigned int i = 0; i < vWorkQueue.size(); i++)
{
uint256 hashPrev = vWorkQueue[i];
- for (multimap<uint256, CDataStream*>::iterator mi = mapOrphanTransactionsByPrev.lower_bound(hashPrev);
- mi != mapOrphanTransactionsByPrev.upper_bound(hashPrev);
+ for (map<uint256, CDataStream*>::iterator mi = mapOrphanTransactionsByPrev[hashPrev].begin();
+ mi != mapOrphanTransactionsByPrev[hashPrev].end();
++mi)
{
const CDataStream& vMsg = *((*mi).second);
CTransaction tx;
CDataStream(vMsg) >> tx;
CInv inv(MSG_TX, tx.GetHash());
+ bool fMissingInputs2 = false;
- if (tx.AcceptToMemoryPool(txdb, true))
+ if (tx.AcceptToMemoryPool(txdb, true, &fMissingInputs2))
{
printf(" accepted orphan tx %s\n", inv.hash.ToString().substr(0,10).c_str());
SyncWithWallets(tx, NULL, true);
RelayMessage(inv, vMsg);
mapAlreadyAskedFor.erase(inv);
vWorkQueue.push_back(inv.hash);
+ vEraseQueue.push_back(inv.hash);
+ }
+ else if (!fMissingInputs2)
+ {
+ // invalid orphan
+ vEraseQueue.push_back(inv.hash);
+ printf(" removed invalid orphan tx %s\n", inv.hash.ToString().substr(0,10).c_str());
}
}
}
- BOOST_FOREACH(uint256 hash, vWorkQueue)
+ BOOST_FOREACH(uint256 hash, vEraseQueue)
EraseOrphanTx(hash);
}
else if (fMissingInputs)
{
- printf("storing orphan tx %s (mapsz %d)\n",
- inv.hash.ToString().substr(0,10).c_str(),
- mapOrphanTransactions.size() + 1);
AddOrphanTx(vMsg);
// DoS prevention: do not allow mapOrphanTransactions to grow unbounded
@@ -2895,7 +2944,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())
@@ -2911,7 +2960,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;
}
@@ -2936,22 +2985,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)
@@ -3054,7 +3103,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
// 1/4 of tx invs blast to all immediately
static uint256 hashSalt;
if (hashSalt == 0)
- RAND_bytes((unsigned char*)&hashSalt, sizeof(hashSalt));
+ hashSalt = GetRandHash();
uint256 hashRand = inv.hash ^ hashSalt;
hashRand = Hash(BEGIN(hashRand), END(hashRand));
bool fTrickleWait = ((hashRand & 3) != 0);
diff --git a/src/main.h b/src/main.h
index 9700909f8b..c0fe63a32a 100644
--- a/src/main.h
+++ b/src/main.h
@@ -1,7 +1,7 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
-// file license.txt or http://www.opensource.org/licenses/mit-license.php.
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_MAIN_H
#define BITCOIN_MAIN_H
@@ -593,7 +593,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)
@@ -969,7 +975,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))
@@ -1574,6 +1585,11 @@ public:
}
bool ProcessAlert();
+
+ /*
+ * Get copy of (active) alert object by hash. Returns a null alert if it is not found.
+ */
+ static CAlert getAlertByHash(const uint256 &hash);
};
class CTxMemPool
diff --git a/src/makefile.linux-mingw b/src/makefile.linux-mingw
index 61b38a663e..51f49bb3cf 100644
--- a/src/makefile.linux-mingw
+++ b/src/makefile.linux-mingw
@@ -27,7 +27,7 @@ LIBS= \
-l ssl \
-l crypto
-DEFS=-D_MT -DWIN32 -D_WINDOWS -DBOOST_THREAD_USE_LIB -DUSE_IPV6
+DEFS=-D_MT -DWIN32 -D_WINDOWS -DBOOST_THREAD_USE_LIB -DBOOST_SPIRIT_THREADSAFE -DUSE_IPV6
DEBUGFLAGS=-g
CFLAGS=-O2 -w -Wall -Wextra -Wformat -Wformat-security -Wno-unused-parameter $(DEBUGFLAGS) $(DEFS) $(INCLUDEPATHS)
diff --git a/src/makefile.mingw b/src/makefile.mingw
index 47bf8d5304..577c77b7d4 100644
--- a/src/makefile.mingw
+++ b/src/makefile.mingw
@@ -23,7 +23,7 @@ LIBS= \
-l ssl \
-l crypto
-DEFS=-DWIN32 -D_WINDOWS -DBOOST_THREAD_USE_LIB -DUSE_IPV6
+DEFS=-DWIN32 -D_WINDOWS -DBOOST_THREAD_USE_LIB -DBOOST_SPIRIT_THREADSAFE -DUSE_IPV6
DEBUGFLAGS=-g
CFLAGS=-mthreads -O2 -w -Wall -Wextra -Wformat -Wformat-security -Wno-unused-parameter $(DEBUGFLAGS) $(DEFS) $(INCLUDEPATHS)
diff --git a/src/makefile.osx b/src/makefile.osx
index 227756f274..9728733122 100644
--- a/src/makefile.osx
+++ b/src/makefile.osx
@@ -53,7 +53,7 @@ LIBS += \
TESTDEFS += -DBOOST_TEST_DYN_LINK
endif
-DEFS=-DMAC_OSX -DMSG_NOSIGNAL=0 -DUSE_IPV6
+DEFS=-DMAC_OSX -DMSG_NOSIGNAL=0 -DBOOST_SPIRIT_THREADSAFE -DUSE_IPV6
ifdef RELEASE
# Compile for maximum compatibility and smallest size.
diff --git a/src/makefile.unix b/src/makefile.unix
index 04e17866e5..9052891b4f 100644
--- a/src/makefile.unix
+++ b/src/makefile.unix
@@ -4,7 +4,7 @@
USE_UPNP:=0
-DEFS=-DUSE_IPV6
+DEFS=-DUSE_IPV6 -DBOOST_SPIRIT_THREADSAFE
DEFS += $(addprefix -I,$(CURDIR) $(CURDIR)/obj $(BOOST_INCLUDE_PATH) $(BDB_INCLUDE_PATH) $(OPENSSL_INCLUDE_PATH))
LIBS = $(addprefix -L,$(BOOST_LIB_PATH) $(BDB_LIB_PATH) $(OPENSSL_LIB_PATH))
diff --git a/src/mruset.h b/src/mruset.h
index b21f18563c..ad2e160d3a 100644
--- a/src/mruset.h
+++ b/src/mruset.h
@@ -1,6 +1,6 @@
// Copyright (c) 2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
-// file license.txt or http://www.opensource.org/licenses/mit-license.php.
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_MRUSET_H
#define BITCOIN_MRUSET_H
diff --git a/src/net.cpp b/src/net.cpp
index 65b78bf6fa..4c795554a9 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -1,7 +1,7 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
-// file license.txt or http://www.opensource.org/licenses/mit-license.php.
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "irc.h"
#include "db.h"
@@ -705,7 +705,7 @@ void ThreadSocketHandler2(void* parg)
if (vNodes.size() != nPrevNodeCount)
{
nPrevNodeCount = vNodes.size();
- MainFrameRepaint();
+ uiInterface.NotifyNumConnectionsChanged(vNodes.size());
}
@@ -1760,7 +1760,7 @@ bool BindListenPort(const CService &addrBind, string& strError)
{
int nErr = WSAGetLastError();
if (nErr == WSAEADDRINUSE)
- strError = strprintf(_("Unable to bind to %s on this computer. Bitcoin is probably already running."), addrBind.ToString().c_str());
+ strError = strprintf(_("Unable to bind to %s on this computer. Bitcoin is probably already running."), addrBind.ToString().c_str());
else
strError = strprintf(_("Unable to bind to %s on this computer (bind returned error %d, %s)"), addrBind.ToString().c_str(), nErr, strerror(nErr));
printf("%s\n", strError.c_str());
diff --git a/src/net.h b/src/net.h
index fcb5824d8a..8075328b13 100644
--- a/src/net.h
+++ b/src/net.h
@@ -1,7 +1,7 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
-// file license.txt or http://www.opensource.org/licenses/mit-license.php.
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_NET_H
#define BITCOIN_NET_H
diff --git a/src/netbase.cpp b/src/netbase.cpp
index 3fe42a7a74..7de06eaef8 100644
--- a/src/netbase.cpp
+++ b/src/netbase.cpp
@@ -1,7 +1,7 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
-// file license.txt or http://www.opensource.org/licenses/mit-license.php.
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "netbase.h"
#include "util.h"
diff --git a/src/netbase.h b/src/netbase.h
index 514a1ae950..2cbc8bd8a2 100644
--- a/src/netbase.h
+++ b/src/netbase.h
@@ -1,6 +1,6 @@
// Copyright (c) 2009-2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
-// file license.txt or http://www.opensource.org/licenses/mit-license.php.
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_NETBASE_H
#define BITCOIN_NETBASE_H
diff --git a/src/noui.cpp b/src/noui.cpp
index 08a08b439a..3ba7e729f5 100644
--- a/src/noui.cpp
+++ b/src/noui.cpp
@@ -1,44 +1,35 @@
// Copyright (c) 2010 Satoshi Nakamoto
// Copyright (c) 2009-2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
-// file license.txt or http://www.opensource.org/licenses/mit-license.php.
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "ui_interface.h"
+#include "init.h"
+#include "bitcoinrpc.h"
#include <string>
-#include "init.h"
-int ThreadSafeMessageBox(const std::string& message, const std::string& caption, int style)
+static int noui_ThreadSafeMessageBox(const std::string& message, const std::string& caption, int style)
{
printf("%s: %s\n", caption.c_str(), message.c_str());
fprintf(stderr, "%s: %s\n", caption.c_str(), message.c_str());
return 4;
}
-bool ThreadSafeAskFee(int64 nFeeRequired, const std::string& strCaption)
+static bool noui_ThreadSafeAskFee(int64 nFeeRequired, const std::string& strCaption)
{
return true;
}
-void MainFrameRepaint()
-{
-}
-
-void AddressBookRepaint()
-{
-}
-
-void InitMessage(const std::string &message)
-{
-}
-
-std::string _(const char* psz)
-{
- return psz;
-}
-
-void QueueShutdown()
+static void noui_QueueShutdown()
{
// Without UI, Shutdown can simply be started in a new thread
CreateThread(Shutdown, NULL);
}
+void noui_connect()
+{
+ // Connect bitcoind signal handlers
+ uiInterface.ThreadSafeMessageBox.connect(noui_ThreadSafeMessageBox);
+ uiInterface.ThreadSafeAskFee.connect(noui_ThreadSafeAskFee);
+ uiInterface.QueueShutdown.connect(noui_QueueShutdown);
+}
diff --git a/src/protocol.cpp b/src/protocol.cpp
index fda31966f2..d6e340e366 100644
--- a/src/protocol.cpp
+++ b/src/protocol.cpp
@@ -1,7 +1,7 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
-// file license.txt or http://www.opensource.org/licenses/mit-license.php.
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "protocol.h"
#include "util.h"
diff --git a/src/protocol.h b/src/protocol.h
index f7331c1923..b516f1b897 100644
--- a/src/protocol.h
+++ b/src/protocol.h
@@ -1,7 +1,7 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
-// file license.txt or http://www.opensource.org/licenses/mit-license.php.
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef __cplusplus
# error This header can only be compiled as C++.
diff --git a/src/qt/addressbookpage.cpp b/src/qt/addressbookpage.cpp
index d314e62b5a..c207987561 100644
--- a/src/qt/addressbookpage.cpp
+++ b/src/qt/addressbookpage.cpp
@@ -132,6 +132,10 @@ void AddressBookPage::setModel(AddressTableModel *model)
connect(ui->tableView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
this, SLOT(selectionChanged()));
+ // Select row for newly created address
+ connect(model, SIGNAL(rowsInserted(QModelIndex,int,int)),
+ this, SLOT(selectNewAddress(QModelIndex,int,int)));
+
if(mode == ForSending)
{
// Auto-select first row when in sending mode
@@ -193,20 +197,11 @@ void AddressBookPage::on_newAddressButton_clicked()
EditAddressDialog dlg(
tab == SendingTab ?
EditAddressDialog::NewSendingAddress :
- EditAddressDialog::NewReceivingAddress);
+ EditAddressDialog::NewReceivingAddress, this);
dlg.setModel(model);
if(dlg.exec())
{
- // Select row for newly created address
- QString address = dlg.getAddress();
- QModelIndexList lst = proxyModel->match(proxyModel->index(0,
- AddressTableModel::Address, QModelIndex()),
- Qt::EditRole, address, 1, Qt::MatchExactly);
- if(!lst.isEmpty())
- {
- ui->tableView->setFocus();
- ui->tableView->selectRow(lst.at(0).row());
- }
+ newAddressToSelect = dlg.getAddress();
}
}
@@ -338,3 +333,15 @@ void AddressBookPage::contextualMenu(const QPoint &point)
contextMenu->exec(QCursor::pos());
}
}
+
+void AddressBookPage::selectNewAddress(const QModelIndex &parent, int begin, int end)
+{
+ QModelIndex idx = proxyModel->mapFromSource(model->index(begin, AddressTableModel::Address, parent));
+ if(idx.isValid() && (idx.data(Qt::EditRole).toString() == newAddressToSelect))
+ {
+ // Select row of newly created address, once
+ ui->tableView->setFocus();
+ ui->tableView->selectRow(idx.row());
+ newAddressToSelect.clear();
+ }
+}
diff --git a/src/qt/addressbookpage.h b/src/qt/addressbookpage.h
index b2cf2db979..b2e91c7cb2 100644
--- a/src/qt/addressbookpage.h
+++ b/src/qt/addressbookpage.h
@@ -13,6 +13,7 @@ class QTableView;
class QItemSelection;
class QSortFilterProxyModel;
class QMenu;
+class QModelIndex;
QT_END_NAMESPACE
/** Widget that shows a list of sending or receiving addresses.
@@ -51,6 +52,7 @@ private:
QSortFilterProxyModel *proxyModel;
QMenu *contextMenu;
QAction *deleteAction;
+ QString newAddressToSelect;
private slots:
void on_deleteButton_clicked();
@@ -67,6 +69,9 @@ private slots:
void onCopyLabelAction();
/** Edit currently selected address entry */
void onEditAction();
+
+ /** New entry/entries were added to address table */
+ void selectNewAddress(const QModelIndex &parent, int begin, int end);
};
#endif // ADDRESSBOOKDIALOG_H
diff --git a/src/qt/addresstablemodel.cpp b/src/qt/addresstablemodel.cpp
index 7b95f51c04..75ea2c12c5 100644
--- a/src/qt/addresstablemodel.cpp
+++ b/src/qt/addresstablemodel.cpp
@@ -26,20 +26,36 @@ struct AddressTableEntry
type(type), label(label), address(address) {}
};
+struct AddressTableEntryLessThan
+{
+ bool operator()(const AddressTableEntry &a, const AddressTableEntry &b) const
+ {
+ return a.address < b.address;
+ }
+ bool operator()(const AddressTableEntry &a, const QString &b) const
+ {
+ return a.address < b;
+ }
+ bool operator()(const QString &a, const AddressTableEntry &b) const
+ {
+ return a < b.address;
+ }
+};
+
// Private implementation
class AddressTablePriv
{
public:
CWallet *wallet;
QList<AddressTableEntry> cachedAddressTable;
+ AddressTableModel *parent;
- AddressTablePriv(CWallet *wallet):
- wallet(wallet) {}
+ AddressTablePriv(CWallet *wallet, AddressTableModel *parent):
+ wallet(wallet), parent(parent) {}
void refreshAddressTable()
{
cachedAddressTable.clear();
-
{
LOCK(wallet->cs_wallet);
BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, std::string)& item, wallet->mapAddressBook)
@@ -54,6 +70,53 @@ public:
}
}
+ void updateEntry(const QString &address, const QString &label, bool isMine, int status)
+ {
+ // Find address / label in model
+ QList<AddressTableEntry>::iterator lower = qLowerBound(
+ cachedAddressTable.begin(), cachedAddressTable.end(), address, AddressTableEntryLessThan());
+ QList<AddressTableEntry>::iterator upper = qUpperBound(
+ cachedAddressTable.begin(), cachedAddressTable.end(), address, AddressTableEntryLessThan());
+ int lowerIndex = (lower - cachedAddressTable.begin());
+ int upperIndex = (upper - cachedAddressTable.begin());
+ bool inModel = (lower != upper);
+ AddressTableEntry::Type newEntryType = isMine ? AddressTableEntry::Receiving : AddressTableEntry::Sending;
+
+ switch(status)
+ {
+ case CT_NEW:
+ if(inModel)
+ {
+ OutputDebugStringF("Warning: AddressTablePriv::updateEntry: Got CT_NOW, but entry is already in model\n");
+ break;
+ }
+ parent->beginInsertRows(QModelIndex(), lowerIndex, lowerIndex);
+ cachedAddressTable.insert(lowerIndex, AddressTableEntry(newEntryType, label, address));
+ parent->endInsertRows();
+ break;
+ case CT_UPDATED:
+ if(!inModel)
+ {
+ OutputDebugStringF("Warning: AddressTablePriv::updateEntry: Got CT_UPDATED, but entry is not in model\n");
+ break;
+ }
+ lower->type = newEntryType;
+ lower->label = label;
+ parent->emitDataChanged(lowerIndex);
+ break;
+ case CT_DELETED:
+ if(!inModel)
+ {
+ OutputDebugStringF("Warning: AddressTablePriv::updateEntry: Got CT_DELETED, but entry is not in model\n");
+ break;
+ }
+ parent->beginRemoveRows(QModelIndex(), lowerIndex, upperIndex-1);
+ cachedAddressTable.erase(lower, upper);
+ parent->endRemoveRows();
+ break;
+ }
+ }
+
int size()
{
return cachedAddressTable.size();
@@ -76,7 +139,7 @@ AddressTableModel::AddressTableModel(CWallet *wallet, WalletModel *parent) :
QAbstractTableModel(parent),walletModel(parent),wallet(wallet),priv(0)
{
columns << tr("Label") << tr("Address");
- priv = new AddressTablePriv(wallet);
+ priv = new AddressTablePriv(wallet, this);
priv->refreshAddressTable();
}
@@ -158,7 +221,6 @@ bool AddressTableModel::setData(const QModelIndex & index, const QVariant & valu
{
case Label:
wallet->SetAddressBookName(rec->address.toStdString(), value.toString().toStdString());
- rec->label = value.toString();
break;
case Address:
// Refuse to set invalid address, set error status and return false
@@ -177,12 +239,9 @@ bool AddressTableModel::setData(const QModelIndex & index, const QVariant & valu
// Add new entry with new address
wallet->SetAddressBookName(value.toString().toStdString(), rec->label.toStdString());
}
-
- rec->address = value.toString();
}
break;
}
- emit dataChanged(index, index);
return true;
}
@@ -232,12 +291,10 @@ QModelIndex AddressTableModel::index(int row, int column, const QModelIndex & pa
}
}
-void AddressTableModel::update()
+void AddressTableModel::updateEntry(const QString &address, const QString &label, bool isMine, int status)
{
// Update address book model from Bitcoin core
- beginResetModel();
- priv->refreshAddressTable();
- endResetModel();
+ priv->updateEntry(address, label, isMine, status);
}
QString AddressTableModel::addRow(const QString &type, const QString &label, const QString &address)
@@ -341,3 +398,7 @@ int AddressTableModel::lookupAddress(const QString &address) const
}
}
+void AddressTableModel::emitDataChanged(int idx)
+{
+ emit dataChanged(index(idx, 0, QModelIndex()), index(idx, columns.length()-1, QModelIndex()));
+}
diff --git a/src/qt/addresstablemodel.h b/src/qt/addresstablemodel.h
index 7fd07cfb81..42974e3e1f 100644
--- a/src/qt/addresstablemodel.h
+++ b/src/qt/addresstablemodel.h
@@ -74,13 +74,18 @@ private:
QStringList columns;
EditStatus editStatus;
+ /** Notify listeners that data changed. */
+ void emitDataChanged(int index);
+
signals:
void defaultAddressChanged(const QString &address);
public slots:
- /* Update address list from core. Invalidates any indices.
+ /* Update address list from core.
*/
- void update();
+ void updateEntry(const QString &address, const QString &label, bool isMine, int status);
+
+ friend class AddressTablePriv;
};
#endif // ADDRESSTABLEMODEL_H
diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp
index 9452f7e1e3..bdc6ea6ffd 100644
--- a/src/qt/bitcoin.cpp
+++ b/src/qt/bitcoin.cpp
@@ -21,6 +21,7 @@
#include <QLibraryInfo>
#include <boost/interprocess/ipc/message_queue.hpp>
+#include <boost/algorithm/string/predicate.hpp>
#if defined(BITCOIN_NEED_QT_PLUGINS) && !defined(_BITCOIN_QT_PLUGINS_INCLUDED)
#define _BITCOIN_QT_PLUGINS_INCLUDED
@@ -36,15 +37,13 @@ Q_IMPORT_PLUGIN(qtaccessiblewidgets)
// Need a global reference for the notifications to find the GUI
static BitcoinGUI *guiref;
static QSplashScreen *splashref;
-static WalletModel *walletmodel;
-static ClientModel *clientmodel;
-int ThreadSafeMessageBox(const std::string& message, const std::string& caption, int style)
+static void ThreadSafeMessageBox(const std::string& message, const std::string& caption, int style)
{
// Message from network thread
if(guiref)
{
- bool modal = (style & wxMODAL);
+ bool modal = (style & CClientUIInterface::MODAL);
// in case of modal message, use blocking connection to wait for user to click OK
QMetaObject::invokeMethod(guiref, "error",
modal ? GUIUtil::blockingGUIThreadConnection() : Qt::QueuedConnection,
@@ -57,10 +56,9 @@ int ThreadSafeMessageBox(const std::string& message, const std::string& caption,
printf("%s: %s\n", caption.c_str(), message.c_str());
fprintf(stderr, "%s: %s\n", caption.c_str(), message.c_str());
}
- return 4;
}
-bool ThreadSafeAskFee(int64 nFeeRequired, const std::string& strCaption)
+static bool ThreadSafeAskFee(int64 nFeeRequired, const std::string& strCaption)
{
if(!guiref)
return false;
@@ -75,7 +73,7 @@ bool ThreadSafeAskFee(int64 nFeeRequired, const std::string& strCaption)
return payFee;
}
-void ThreadSafeHandleURI(const std::string& strURI)
+static void ThreadSafeHandleURI(const std::string& strURI)
{
if(!guiref)
return;
@@ -84,21 +82,7 @@ void ThreadSafeHandleURI(const std::string& strURI)
Q_ARG(QString, QString::fromStdString(strURI)));
}
-void MainFrameRepaint()
-{
- if(clientmodel)
- QMetaObject::invokeMethod(clientmodel, "update", Qt::QueuedConnection);
- if(walletmodel)
- QMetaObject::invokeMethod(walletmodel, "update", Qt::QueuedConnection);
-}
-
-void AddressBookRepaint()
-{
- if(walletmodel)
- QMetaObject::invokeMethod(walletmodel, "updateAddressList", Qt::QueuedConnection);
-}
-
-void InitMessage(const std::string &message)
+static void InitMessage(const std::string &message)
{
if(splashref)
{
@@ -107,7 +91,7 @@ void InitMessage(const std::string &message)
}
}
-void QueueShutdown()
+static void QueueShutdown()
{
QMetaObject::invokeMethod(QCoreApplication::instance(), "quit", Qt::QueuedConnection);
}
@@ -115,7 +99,7 @@ void QueueShutdown()
/*
Translate string to current locale using Qt.
*/
-std::string _(const char* psz)
+static std::string Translate(const char* psz)
{
return QCoreApplication::translate("bitcoin-core", psz).toStdString();
}
@@ -147,14 +131,14 @@ HelpMessageBox::HelpMessageBox(QWidget *parent):
QMessageBox(parent)
{
header = tr("Bitcoin-Qt") + " " + tr("version") + " " +
- QString::fromStdString(FormatFullVersion()) + "\n\n" +
+ QString::fromStdString(FormatFullVersion()) + "\n\n" +
tr("Usage:") + "\n" +
- " bitcoin-qt [options] " + "\n";
+ " bitcoin-qt [" + tr("options") + "] " + "\n";
coreOptions = QString::fromStdString(HelpMessage());
uiOptions = tr("UI options") + ":\n" +
- " -lang=<lang> " + tr("Set language, for example \"de_DE\" (default: system locale)") + "\n" +
- " -min " + tr("Start minimized") + "\n" +
- " -splash " + tr("Show splash screen on startup (default: 1)") + "\n";
+ " -lang=<lang> " + tr("Set language, for example \"de_DE\" (default: system locale)") + "\n" +
+ " -min " + tr("Start minimized") + "\n" +
+ " -splash " + tr("Show splash screen on startup (default: 1)") + "\n";
setWindowTitle(tr("Bitcoin-Qt"));
setTextFormat(Qt::PlainText);
@@ -177,9 +161,6 @@ void HelpMessageBox::exec()
#endif
}
-#ifdef WIN32
-#define strncasecmp strnicmp
-#endif
#ifndef BITCOIN_QT_TEST
int main(int argc, char *argv[])
{
@@ -189,7 +170,7 @@ int main(int argc, char *argv[])
// Do this early as we don't want to bother initializing if we are just calling IPC
for (int i = 1; i < argc; i++)
{
- if (strlen(argv[i]) > 7 && strncasecmp(argv[i], "bitcoin:", 8) == 0)
+ if (boost::algorithm::istarts_with(argv[i], "bitcoin:"))
{
const char *strURI = argv[i];
try {
@@ -266,6 +247,14 @@ int main(int argc, char *argv[])
if (translator.load(lang_territory, ":/translations/"))
app.installTranslator(&translator);
+ // Subscribe to global signals from core
+ uiInterface.ThreadSafeMessageBox.connect(ThreadSafeMessageBox);
+ uiInterface.ThreadSafeAskFee.connect(ThreadSafeAskFee);
+ uiInterface.ThreadSafeHandleURI.connect(ThreadSafeHandleURI);
+ uiInterface.InitMessage.connect(InitMessage);
+ uiInterface.QueueShutdown.connect(QueueShutdown);
+ uiInterface.Translate.connect(Translate);
+
// Show help message immediately after parsing command-line options (for "-lang") and setting locale,
// but before showing splash screen.
if (mapArgs.count("-?") || mapArgs.count("--help"))
@@ -307,9 +296,7 @@ int main(int argc, char *argv[])
splash.finish(&window);
ClientModel clientModel(&optionsModel);
- clientmodel = &clientModel;
WalletModel walletModel(pwalletMain, &optionsModel);
- walletmodel = &walletModel;
window.setClientModel(&clientModel);
window.setWalletModel(&walletModel);
@@ -323,17 +310,16 @@ int main(int argc, char *argv[])
{
window.show();
}
+#if !defined(MAC_OSX) && !defined(WIN32)
+// TODO: implement qtipcserver.cpp for Mac and Windows
// Place this here as guiref has to be defined if we dont want to lose URIs
ipcInit();
-#if !defined(MAC_OSX) && !defined(WIN32)
-// TODO: implement qtipcserver.cpp for Mac and Windows
-
// Check for URI in argv
for (int i = 1; i < argc; i++)
{
- if (strlen(argv[i]) > 7 && strncasecmp(argv[i], "bitcoin:", 8) == 0)
+ if (boost::algorithm::istarts_with(argv[i], "bitcoin:"))
{
const char *strURI = argv[i];
try {
@@ -351,8 +337,6 @@ int main(int argc, char *argv[])
window.setClientModel(0);
window.setWalletModel(0);
guiref = 0;
- clientmodel = 0;
- walletmodel = 0;
}
Shutdown(NULL);
}
diff --git a/src/qt/bitcoinaddressvalidator.cpp b/src/qt/bitcoinaddressvalidator.cpp
index 373877808f..d2b93e70f5 100644
--- a/src/qt/bitcoinaddressvalidator.cpp
+++ b/src/qt/bitcoinaddressvalidator.cpp
@@ -21,21 +21,31 @@ 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);
+ // Corrections made are very conservative on purpose, to avoid
+ // users unexpectedly getting away with typos that would normally
+ // be detected, and thus sending to the wrong address.
+ switch(ch.unicode())
{
- case 'l':
- case 'I':
- input[idx] = QChar('1');
- break;
- case '0':
- case 'O':
- input[idx] = QChar('o');
+ // 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
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index 7070e59444..a4bb63886b 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -350,11 +350,11 @@ void BitcoinGUI::setClientModel(ClientModel *clientModel)
setNumConnections(clientModel->getNumConnections());
connect(clientModel, SIGNAL(numConnectionsChanged(int)), this, SLOT(setNumConnections(int)));
- setNumBlocks(clientModel->getNumBlocks());
- connect(clientModel, SIGNAL(numBlocksChanged(int)), this, SLOT(setNumBlocks(int)));
+ setNumBlocks(clientModel->getNumBlocks(), clientModel->getNumBlocksOfPeers());
+ connect(clientModel, SIGNAL(numBlocksChanged(int,int)), this, SLOT(setNumBlocks(int,int)));
// Report errors from network/worker thread
- connect(clientModel, SIGNAL(error(QString,QString, bool)), this, SLOT(error(QString,QString,bool)));
+ connect(clientModel, SIGNAL(error(QString,QString,bool)), this, SLOT(error(QString,QString,bool)));
rpcConsole->setClientModel(clientModel);
}
@@ -404,7 +404,6 @@ void BitcoinGUI::createTrayIcon()
#else
// Note: On Mac, the dock icon is used to provide the tray's functionality.
MacDockIconHandler *dockIconHandler = MacDockIconHandler::instance();
- connect(dockIconHandler, SIGNAL(dockIconClicked()), toggleHideAction, SLOT(trigger()));
trayIconMenu = dockIconHandler->dockMenu();
#endif
@@ -493,7 +492,7 @@ void BitcoinGUI::setNumConnections(int count)
labelConnectionsIcon->setToolTip(tr("%n active connection(s) to Bitcoin network", "", count));
}
-void BitcoinGUI::setNumBlocks(int count)
+void BitcoinGUI::setNumBlocks(int count, int nTotalBlocks)
{
// don't show / hide progressBar and it's label if we have no connection(s) to the network
if (!clientModel || clientModel->getNumConnections() == 0)
@@ -504,7 +503,6 @@ void BitcoinGUI::setNumBlocks(int count)
return;
}
- int nTotalBlocks = clientModel->getNumBlocksOfPeers();
QString tooltip;
if(count < nTotalBlocks)
diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h
index 88e6d064d7..8a7f6e541b 100644
--- a/src/qt/bitcoingui.h
+++ b/src/qt/bitcoingui.h
@@ -111,7 +111,7 @@ public slots:
/** Set number of connections shown in the UI */
void setNumConnections(int count);
/** Set number of blocks shown in the UI */
- void setNumBlocks(int count);
+ void setNumBlocks(int count, int countOfPeers);
/** Set the encryption status as shown in the UI.
@param[in] status current encryption status
@see WalletModel::EncryptionStatus
diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp
index 85ab03612d..64fd2a9450 100644
--- a/src/qt/clientmodel.cpp
+++ b/src/qt/clientmodel.cpp
@@ -5,15 +5,30 @@
#include "transactiontablemodel.h"
#include "main.h"
-static const int64 nClientStartupTime = GetTime();
+#include "ui_interface.h"
#include <QDateTime>
+#include <QTimer>
+
+static const int64 nClientStartupTime = GetTime();
ClientModel::ClientModel(OptionsModel *optionsModel, QObject *parent) :
QObject(parent), optionsModel(optionsModel),
- cachedNumConnections(0), cachedNumBlocks(0)
+ cachedNumBlocks(0), cachedNumBlocksOfPeers(0), pollTimer(0)
{
numBlocksAtStartup = -1;
+
+ pollTimer = new QTimer();
+ pollTimer->setInterval(MODEL_UPDATE_DELAY);
+ pollTimer->start();
+ connect(pollTimer, SIGNAL(timeout()), this, SLOT(updateTimer()));
+
+ subscribeToCoreSignals();
+}
+
+ClientModel::~ClientModel()
+{
+ unsubscribeFromCoreSignals();
}
int ClientModel::getNumConnections() const
@@ -37,27 +52,42 @@ QDateTime ClientModel::getLastBlockDate() const
return QDateTime::fromTime_t(pindexBest->GetBlockTime());
}
-void ClientModel::update()
+void ClientModel::updateTimer()
{
- int newNumConnections = getNumConnections();
+ // Some quantities (such as number of blocks) change so fast that we don't want to be notified for each change.
+ // Periodically check and update with a timer.
int newNumBlocks = getNumBlocks();
- QString newStatusBar = getStatusBarWarnings();
+ int newNumBlocksOfPeers = getNumBlocksOfPeers();
- if(cachedNumConnections != newNumConnections)
- emit numConnectionsChanged(newNumConnections);
- if(cachedNumBlocks != newNumBlocks || cachedStatusBar != newStatusBar)
+ if(cachedNumBlocks != newNumBlocks || cachedNumBlocksOfPeers != newNumBlocksOfPeers)
+ emit numBlocksChanged(newNumBlocks, newNumBlocksOfPeers);
+
+ cachedNumBlocks = newNumBlocks;
+ cachedNumBlocksOfPeers = newNumBlocksOfPeers;
+}
+
+void ClientModel::updateNumConnections(int numConnections)
+{
+ emit numConnectionsChanged(numConnections);
+}
+
+void ClientModel::updateAlert(const QString &hash, int status)
+{
+ // Show error message notification for new alert
+ if(status == CT_NEW)
{
- // Simply emit a numBlocksChanged for now in case the status message changes,
- // so that the view updates the status bar.
- // TODO: It should send a notification.
- // (However, this might generate looped notifications and needs to be thought through and tested carefully)
- // error(tr("Network Alert"), newStatusBar);
- emit numBlocksChanged(newNumBlocks);
+ uint256 hash_256;
+ hash_256.SetHex(hash.toStdString());
+ CAlert alert = CAlert::getAlertByHash(hash_256);
+ if(!alert.IsNull())
+ {
+ emit error(tr("Network Alert"), QString::fromStdString(alert.strStatusBar), false);
+ }
}
- cachedNumConnections = newNumConnections;
- cachedNumBlocks = newNumBlocks;
- cachedStatusBar = newStatusBar;
+ // Emit a numBlocksChanged when the status message changes,
+ // so that the view recomputes and updates the status bar.
+ emit numBlocksChanged(getNumBlocks(), getNumBlocksOfPeers());
}
bool ClientModel::isTestNet() const
@@ -104,3 +134,41 @@ QDateTime ClientModel::formatClientStartupTime() const
{
return QDateTime::fromTime_t(nClientStartupTime);
}
+
+// Handlers for core signals
+static void NotifyBlocksChanged(ClientModel *clientmodel)
+{
+ // This notification is too frequent. Don't trigger a signal.
+ // Don't remove it, though, as it might be useful later.
+}
+
+static void NotifyNumConnectionsChanged(ClientModel *clientmodel, int newNumConnections)
+{
+ // Too noisy: OutputDebugStringF("NotifyNumConnectionsChanged %i\n", newNumConnections);
+ QMetaObject::invokeMethod(clientmodel, "updateNumConnections", Qt::QueuedConnection,
+ Q_ARG(int, newNumConnections));
+}
+
+static void NotifyAlertChanged(ClientModel *clientmodel, const uint256 &hash, ChangeType status)
+{
+ OutputDebugStringF("NotifyAlertChanged %s status=%i\n", hash.GetHex().c_str(), status);
+ QMetaObject::invokeMethod(clientmodel, "updateAlert", Qt::QueuedConnection,
+ Q_ARG(QString, QString::fromStdString(hash.GetHex())),
+ Q_ARG(int, status));
+}
+
+void ClientModel::subscribeToCoreSignals()
+{
+ // Connect signals to client
+ uiInterface.NotifyBlocksChanged.connect(boost::bind(NotifyBlocksChanged, this));
+ uiInterface.NotifyNumConnectionsChanged.connect(boost::bind(NotifyNumConnectionsChanged, this, _1));
+ uiInterface.NotifyAlertChanged.connect(boost::bind(NotifyAlertChanged, this, _1, _2));
+}
+
+void ClientModel::unsubscribeFromCoreSignals()
+{
+ // Disconnect signals from client
+ uiInterface.NotifyBlocksChanged.disconnect(boost::bind(NotifyBlocksChanged, this));
+ uiInterface.NotifyNumConnectionsChanged.disconnect(boost::bind(NotifyNumConnectionsChanged, this, _1));
+ uiInterface.NotifyAlertChanged.disconnect(boost::bind(NotifyAlertChanged, this, _1, _2));
+}
diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h
index 67835db727..0349c389c5 100644
--- a/src/qt/clientmodel.h
+++ b/src/qt/clientmodel.h
@@ -10,6 +10,7 @@ class CWallet;
QT_BEGIN_NAMESPACE
class QDateTime;
+class QTimer;
QT_END_NAMESPACE
/** Model for Bitcoin network client. */
@@ -18,6 +19,7 @@ class ClientModel : public QObject
Q_OBJECT
public:
explicit ClientModel(OptionsModel *optionsModel, QObject *parent = 0);
+ ~ClientModel();
OptionsModel *getOptionsModel();
@@ -44,23 +46,26 @@ public:
private:
OptionsModel *optionsModel;
- int cachedNumConnections;
int cachedNumBlocks;
- QString cachedStatusBar;
+ int cachedNumBlocksOfPeers;
int numBlocksAtStartup;
+ QTimer *pollTimer;
+
+ void subscribeToCoreSignals();
+ void unsubscribeFromCoreSignals();
signals:
void numConnectionsChanged(int count);
- void numBlocksChanged(int count);
+ void numBlocksChanged(int count, int countOfPeers);
//! Asynchronous error notification
void error(const QString &title, const QString &message, bool modal);
public slots:
-
-private slots:
- void update();
+ void updateTimer();
+ void updateNumConnections(int numConnections);
+ void updateAlert(const QString &hash, int status);
};
#endif // CLIENTMODEL_H
diff --git a/src/qt/forms/askpassphrasedialog.ui b/src/qt/forms/askpassphrasedialog.ui
index e4d86f7cf9..25169042a1 100644
--- a/src/qt/forms/askpassphrasedialog.ui
+++ b/src/qt/forms/askpassphrasedialog.ui
@@ -41,49 +41,49 @@
<property name="fieldGrowthPolicy">
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
</property>
- <item row="1" column="0">
+ <item row="0" column="0">
<widget class="QLabel" name="passLabel1">
<property name="text">
<string>Enter passphrase</string>
</property>
</widget>
</item>
- <item row="1" column="1">
+ <item row="0" column="1">
<widget class="QLineEdit" name="passEdit1">
<property name="echoMode">
<enum>QLineEdit::Password</enum>
</property>
</widget>
</item>
- <item row="2" column="0">
+ <item row="1" column="0">
<widget class="QLabel" name="passLabel2">
<property name="text">
<string>New passphrase</string>
</property>
</widget>
</item>
- <item row="2" column="1">
+ <item row="1" column="1">
<widget class="QLineEdit" name="passEdit2">
<property name="echoMode">
<enum>QLineEdit::Password</enum>
</property>
</widget>
</item>
- <item row="3" column="0">
+ <item row="2" column="0">
<widget class="QLabel" name="passLabel3">
<property name="text">
<string>Repeat new passphrase</string>
</property>
</widget>
</item>
- <item row="3" column="1">
+ <item row="2" column="1">
<widget class="QLineEdit" name="passEdit3">
<property name="echoMode">
<enum>QLineEdit::Password</enum>
</property>
</widget>
</item>
- <item row="4" column="1">
+ <item row="3" column="1">
<widget class="QLabel" name="capsLabel">
<property name="font">
<font>
diff --git a/src/qt/forms/messagepage.ui b/src/qt/forms/messagepage.ui
index 7c8f3b5ad6..0b685aae1d 100644
--- a/src/qt/forms/messagepage.ui
+++ b/src/qt/forms/messagepage.ui
@@ -11,7 +11,7 @@
</rect>
</property>
<property name="windowTitle">
- <string>Sign Message Dialog</string>
+ <string>Sign Message</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp
index c3260217bb..7c6ad087cb 100644
--- a/src/qt/optionsdialog.cpp
+++ b/src/qt/optionsdialog.cpp
@@ -249,7 +249,7 @@ DisplayOptionsPage::DisplayOptionsPage(QWidget *parent):
QHBoxLayout *lang_hbox = new QHBoxLayout();
lang_hbox->addSpacing(18);
- QLabel *lang_label = new QLabel(tr("User Interface &Language: "));
+ QLabel *lang_label = new QLabel(tr("User Interface &Language:"));
lang_hbox->addWidget(lang_label);
lang = new QValueComboBox(this);
// Make list of languages
@@ -270,7 +270,7 @@ DisplayOptionsPage::DisplayOptionsPage(QWidget *parent):
QHBoxLayout *unit_hbox = new QHBoxLayout();
unit_hbox->addSpacing(18);
- QLabel *unit_label = new QLabel(tr("&Unit to show amounts in: "));
+ QLabel *unit_label = new QLabel(tr("&Unit to show amounts in:"));
unit_hbox->addWidget(unit_label);
unit = new QValueComboBox(this);
unit->setModel(new BitcoinUnits(this));
@@ -354,7 +354,7 @@ NetworkOptionsPage::NetworkOptionsPage(QWidget *parent):
QHBoxLayout *proxy_hbox = new QHBoxLayout();
proxy_hbox->addSpacing(18);
- QLabel *proxy_ip_label = new QLabel(tr("Proxy &IP: "));
+ QLabel *proxy_ip_label = new QLabel(tr("Proxy &IP:"));
proxy_hbox->addWidget(proxy_ip_label);
proxy_ip = new QLineEdit();
proxy_ip->setMaximumWidth(140);
@@ -363,7 +363,7 @@ NetworkOptionsPage::NetworkOptionsPage(QWidget *parent):
proxy_ip->setToolTip(tr("IP address of the proxy (e.g. 127.0.0.1)"));
proxy_ip_label->setBuddy(proxy_ip);
proxy_hbox->addWidget(proxy_ip);
- QLabel *proxy_port_label = new QLabel(tr("&Port: "));
+ QLabel *proxy_port_label = new QLabel(tr("&Port:"));
proxy_hbox->addWidget(proxy_port_label);
proxy_port = new QLineEdit();
proxy_port->setMaximumWidth(55);
diff --git a/src/qt/qtipcserver.cpp b/src/qt/qtipcserver.cpp
index 06ada5aaca..3d7d90e902 100644
--- a/src/qt/qtipcserver.cpp
+++ b/src/qt/qtipcserver.cpp
@@ -31,7 +31,7 @@ void ipcThread(void* parg)
ptime d = boost::posix_time::microsec_clock::universal_time() + millisec(100);
if(mq->timed_receive(&strBuf, sizeof(strBuf), nSize, nPriority, d))
{
- ThreadSafeHandleURI(std::string(strBuf, nSize));
+ uiInterface.ThreadSafeHandleURI(std::string(strBuf, nSize));
Sleep(1000);
}
if (fShutdown)
@@ -69,7 +69,7 @@ void ipcInit()
ptime d = boost::posix_time::microsec_clock::universal_time() + millisec(1);
if(mq->timed_receive(&strBuf, sizeof(strBuf), nSize, nPriority, d))
{
- ThreadSafeHandleURI(std::string(strBuf, nSize));
+ uiInterface.ThreadSafeHandleURI(std::string(strBuf, nSize));
}
else
break;
diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp
index 78dbcd7daa..7029ee33bc 100644
--- a/src/qt/rpcconsole.cpp
+++ b/src/qt/rpcconsole.cpp
@@ -109,7 +109,9 @@ RPCConsole::RPCConsole(QWidget *parent) :
{
ui->setupUi(this);
-#ifndef WIN32
+#ifdef WIN32
+ ui->openDebugLogfileButton->setIcon(QIcon(":/icons/export"));
+#else
// Show Debug logfile label and Open button only for Windows
ui->labelDebugLogfile->setVisible(false);
ui->openDebugLogfileButton->setVisible(false);
@@ -155,7 +157,7 @@ void RPCConsole::setClientModel(ClientModel *model)
{
// Subscribe to information, replies, messages, errors
connect(model, SIGNAL(numConnectionsChanged(int)), this, SLOT(setNumConnections(int)));
- connect(model, SIGNAL(numBlocksChanged(int)), this, SLOT(setNumBlocks(int)));
+ connect(model, SIGNAL(numBlocksChanged(int,int)), this, SLOT(setNumBlocks(int,int)));
// Provide initial values
ui->clientVersion->setText(model->formatFullVersion());
@@ -166,7 +168,7 @@ void RPCConsole::setClientModel(ClientModel *model)
setNumConnections(model->getNumConnections());
ui->isTestNet->setChecked(model->isTestNet());
- setNumBlocks(model->getNumBlocks());
+ setNumBlocks(model->getNumBlocks(), model->getNumBlocksOfPeers());
}
}
@@ -207,9 +209,9 @@ void RPCConsole::clear()
"b { color: #006060; } "
);
- message(CMD_REPLY, tr("Welcome to the Bitcoin RPC console.<br>"
- "Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen.<br>"
- "Type <b>help</b> for an overview of available commands."), true);
+ message(CMD_REPLY, (tr("Welcome to the Bitcoin RPC console.") + "<br>" +
+ tr("Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen.") + "<br>" +
+ tr("Type <b>help</b> for an overview of available commands.")), true);
}
void RPCConsole::message(int category, const QString &message, bool html)
@@ -233,9 +235,10 @@ void RPCConsole::setNumConnections(int count)
ui->numberOfConnections->setText(QString::number(count));
}
-void RPCConsole::setNumBlocks(int count)
+void RPCConsole::setNumBlocks(int count, int countOfPeers)
{
ui->numberOfBlocks->setText(QString::number(count));
+ ui->totalBlocks->setText(QString::number(countOfPeers));
if(clientModel)
{
// If there is no current number available display N/A instead of 0, which can't ever be true
diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h
index c64ea5710c..4b71cdb988 100644
--- a/src/qt/rpcconsole.h
+++ b/src/qt/rpcconsole.h
@@ -33,6 +33,7 @@ protected:
private slots:
void on_lineEdit_returnPressed();
void on_tabWidget_currentChanged(int index);
+ /** open the debug.log from the current datadir */
void on_openDebugLogfileButton_clicked();
public slots:
@@ -41,7 +42,7 @@ public slots:
/** Set number of connections shown in the UI */
void setNumConnections(int count);
/** Set number of blocks shown in the UI */
- void setNumBlocks(int count);
+ void setNumBlocks(int count, int countOfPeers);
/** Go forward or back in history */
void browseHistory(int offset);
/** Scroll console view to end */
diff --git a/src/qt/transactionrecord.cpp b/src/qt/transactionrecord.cpp
index 53cfb409ff..017244ffd0 100644
--- a/src/qt/transactionrecord.cpp
+++ b/src/qt/transactionrecord.cpp
@@ -40,114 +40,111 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet *
uint256 hash = wtx.GetHash();
std::map<std::string, std::string> mapValue = wtx.mapValue;
- if (showTransaction(wtx))
+ if (nNet > 0 || wtx.IsCoinBase())
{
- if (nNet > 0 || wtx.IsCoinBase())
+ //
+ // Credit
+ //
+ BOOST_FOREACH(const CTxOut& txout, wtx.vout)
{
- //
- // Credit
- //
- BOOST_FOREACH(const CTxOut& txout, wtx.vout)
+ if(wallet->IsMine(txout))
{
- if(wallet->IsMine(txout))
+ TransactionRecord sub(hash, nTime);
+ CBitcoinAddress address;
+ sub.idx = parts.size(); // sequence number
+ sub.credit = txout.nValue;
+ if (wtx.IsCoinBase())
{
- TransactionRecord sub(hash, nTime);
- CBitcoinAddress address;
- sub.idx = parts.size(); // sequence number
- sub.credit = txout.nValue;
- if (wtx.IsCoinBase())
- {
- // Generated
- sub.type = TransactionRecord::Generated;
- }
- else if (ExtractAddress(txout.scriptPubKey, address) && wallet->HaveKey(address))
- {
- // Received by Bitcoin Address
- sub.type = TransactionRecord::RecvWithAddress;
- sub.address = address.ToString();
- }
- else
- {
- // Received by IP connection (deprecated features), or a multisignature or other non-simple transaction
- sub.type = TransactionRecord::RecvFromOther;
- sub.address = mapValue["from"];
- }
-
- parts.append(sub);
+ // Generated
+ sub.type = TransactionRecord::Generated;
}
+ else if (ExtractAddress(txout.scriptPubKey, address) && wallet->HaveKey(address))
+ {
+ // Received by Bitcoin Address
+ sub.type = TransactionRecord::RecvWithAddress;
+ sub.address = address.ToString();
+ }
+ else
+ {
+ // Received by IP connection (deprecated features), or a multisignature or other non-simple transaction
+ sub.type = TransactionRecord::RecvFromOther;
+ sub.address = mapValue["from"];
+ }
+
+ parts.append(sub);
}
}
- else
+ }
+ else
+ {
+ bool fAllFromMe = true;
+ BOOST_FOREACH(const CTxIn& txin, wtx.vin)
+ fAllFromMe = fAllFromMe && wallet->IsMine(txin);
+
+ bool fAllToMe = true;
+ BOOST_FOREACH(const CTxOut& txout, wtx.vout)
+ fAllToMe = fAllToMe && wallet->IsMine(txout);
+
+ if (fAllFromMe && fAllToMe)
{
- bool fAllFromMe = true;
- BOOST_FOREACH(const CTxIn& txin, wtx.vin)
- fAllFromMe = fAllFromMe && wallet->IsMine(txin);
+ // Payment to self
+ int64 nChange = wtx.GetChange();
- bool fAllToMe = true;
- BOOST_FOREACH(const CTxOut& txout, wtx.vout)
- fAllToMe = fAllToMe && wallet->IsMine(txout);
+ parts.append(TransactionRecord(hash, nTime, TransactionRecord::SendToSelf, "",
+ -(nDebit - nChange), nCredit - nChange));
+ }
+ else if (fAllFromMe)
+ {
+ //
+ // Debit
+ //
+ int64 nTxFee = nDebit - wtx.GetValueOut();
- if (fAllFromMe && fAllToMe)
+ for (unsigned int nOut = 0; nOut < wtx.vout.size(); nOut++)
{
- // Payment to self
- int64 nChange = wtx.GetChange();
+ const CTxOut& txout = wtx.vout[nOut];
+ TransactionRecord sub(hash, nTime);
+ sub.idx = parts.size();
- parts.append(TransactionRecord(hash, nTime, TransactionRecord::SendToSelf, "",
- -(nDebit - nChange), nCredit - nChange));
- }
- else if (fAllFromMe)
- {
- //
- // Debit
- //
- int64 nTxFee = nDebit - wtx.GetValueOut();
+ if(wallet->IsMine(txout))
+ {
+ // Ignore parts sent to self, as this is usually the change
+ // from a transaction sent back to our own address.
+ continue;
+ }
- for (unsigned int nOut = 0; nOut < wtx.vout.size(); nOut++)
+ CBitcoinAddress address;
+ if (ExtractAddress(txout.scriptPubKey, address))
{
- const CTxOut& txout = wtx.vout[nOut];
- TransactionRecord sub(hash, nTime);
- sub.idx = parts.size();
-
- if(wallet->IsMine(txout))
- {
- // Ignore parts sent to self, as this is usually the change
- // from a transaction sent back to our own address.
- continue;
- }
-
- CBitcoinAddress address;
- if (ExtractAddress(txout.scriptPubKey, address))
- {
- // Sent to Bitcoin Address
- sub.type = TransactionRecord::SendToAddress;
- sub.address = address.ToString();
- }
- else
- {
- // Sent to IP, or other non-address transaction like OP_EVAL
- sub.type = TransactionRecord::SendToOther;
- sub.address = mapValue["to"];
- }
-
- int64 nValue = txout.nValue;
- /* Add fee to first output */
- if (nTxFee > 0)
- {
- nValue += nTxFee;
- nTxFee = 0;
- }
- sub.debit = -nValue;
-
- parts.append(sub);
+ // Sent to Bitcoin Address
+ sub.type = TransactionRecord::SendToAddress;
+ sub.address = address.ToString();
}
+ else
+ {
+ // Sent to IP, or other non-address transaction like OP_EVAL
+ sub.type = TransactionRecord::SendToOther;
+ sub.address = mapValue["to"];
+ }
+
+ int64 nValue = txout.nValue;
+ /* Add fee to first output */
+ if (nTxFee > 0)
+ {
+ nValue += nTxFee;
+ nTxFee = 0;
+ }
+ sub.debit = -nValue;
+
+ parts.append(sub);
}
- else
- {
- //
- // Mixed debit transaction, can't break down payees
- //
- parts.append(TransactionRecord(hash, nTime, TransactionRecord::Other, "", nNet, 0));
- }
+ }
+ else
+ {
+ //
+ // Mixed debit transaction, can't break down payees
+ //
+ parts.append(TransactionRecord(hash, nTime, TransactionRecord::Other, "", nNet, 0));
}
}
diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp
index 5f505f444e..d36bb495a0 100644
--- a/src/qt/transactiontablemodel.cpp
+++ b/src/qt/transactiontablemodel.cpp
@@ -9,6 +9,7 @@
#include "bitcoinunits.h"
#include "wallet.h"
+#include "ui_interface.h"
#include <QLocale>
#include <QList>
@@ -66,15 +67,14 @@ public:
*/
void refreshWallet()
{
-#ifdef WALLET_UPDATE_DEBUG
- qDebug() << "refreshWallet";
-#endif
+ OutputDebugStringF("refreshWallet\n");
cachedWallet.clear();
{
LOCK(wallet->cs_wallet);
for(std::map<uint256, CWalletTx>::iterator it = wallet->mapWallet.begin(); it != wallet->mapWallet.end(); ++it)
{
- cachedWallet.append(TransactionRecord::decomposeTransaction(wallet, it->second));
+ if(TransactionRecord::showTransaction(it->second))
+ cachedWallet.append(TransactionRecord::decomposeTransaction(wallet, it->second));
}
}
}
@@ -82,49 +82,55 @@ public:
/* Update our model of the wallet incrementally, to synchronize our model of the wallet
with that of the core.
- Call with list of hashes of transactions that were added, removed or changed.
+ Call with transaction that was added, removed or changed.
*/
- void updateWallet(const QList<uint256> &updated)
+ void updateWallet(const uint256 &hash, int status)
{
- // Walk through updated transactions, update model as needed.
-#ifdef WALLET_UPDATE_DEBUG
- qDebug() << "updateWallet";
-#endif
- // Sort update list, and iterate through it in reverse, so that model updates
- // can be emitted from end to beginning (so that earlier updates will not influence
- // the indices of latter ones).
- QList<uint256> updated_sorted = updated;
- qSort(updated_sorted);
-
+ OutputDebugStringF("updateWallet %s %i\n", hash.ToString().c_str(), status);
{
LOCK(wallet->cs_wallet);
- for(int update_idx = updated_sorted.size()-1; update_idx >= 0; --update_idx)
+
+ // Find transaction in wallet
+ std::map<uint256, CWalletTx>::iterator mi = wallet->mapWallet.find(hash);
+ bool inWallet = mi != wallet->mapWallet.end();
+
+ // Find bounds of this transaction in model
+ QList<TransactionRecord>::iterator lower = qLowerBound(
+ cachedWallet.begin(), cachedWallet.end(), hash, TxLessThan());
+ QList<TransactionRecord>::iterator upper = qUpperBound(
+ cachedWallet.begin(), cachedWallet.end(), hash, TxLessThan());
+ int lowerIndex = (lower - cachedWallet.begin());
+ int upperIndex = (upper - cachedWallet.begin());
+ bool inModel = (lower != upper);
+
+ // Determine whether to show transaction or not
+ bool showTransaction = (inWallet && TransactionRecord::showTransaction(mi->second));
+
+ if(status == CT_UPDATED)
{
- const uint256 &hash = updated_sorted.at(update_idx);
- // Find transaction in wallet
- std::map<uint256, CWalletTx>::iterator mi = wallet->mapWallet.find(hash);
- bool inWallet = mi != wallet->mapWallet.end();
- // Find bounds of this transaction in model
- QList<TransactionRecord>::iterator lower = qLowerBound(
- cachedWallet.begin(), cachedWallet.end(), hash, TxLessThan());
- QList<TransactionRecord>::iterator upper = qUpperBound(
- cachedWallet.begin(), cachedWallet.end(), hash, TxLessThan());
- int lowerIndex = (lower - cachedWallet.begin());
- int upperIndex = (upper - cachedWallet.begin());
-
- // Determine if transaction is in model already
- bool inModel = false;
- if(lower != upper)
- {
- inModel = true;
- }
+ if(showTransaction && !inModel)
+ status = CT_NEW; /* Not in model, but want to show, treat as new */
+ if(!showTransaction && inModel)
+ status = CT_DELETED; /* In model, but want to hide, treat as deleted */
+ }
-#ifdef WALLET_UPDATE_DEBUG
- qDebug() << " " << QString::fromStdString(hash.ToString()) << inWallet << " " << inModel
- << lowerIndex << "-" << upperIndex;
-#endif
+ OutputDebugStringF(" inWallet=%i inModel=%i Index=%i-%i showTransaction=%i derivedStatus=%i\n",
+ inWallet, inModel, lowerIndex, upperIndex, showTransaction, status);
- if(inWallet && !inModel)
+ switch(status)
+ {
+ case CT_NEW:
+ if(inModel)
+ {
+ OutputDebugStringF("Warning: updateWallet: Got CT_NEW, but transaction is already in model\n");
+ break;
+ }
+ if(!inWallet)
+ {
+ OutputDebugStringF("Warning: updateWallet: Got CT_NEW, but transaction is not in wallet\n");
+ break;
+ }
+ if(showTransaction)
{
// Added -- insert at the right position
QList<TransactionRecord> toInsert =
@@ -141,17 +147,22 @@ public:
parent->endInsertRows();
}
}
- else if(!inWallet && inModel)
- {
- // Removed -- remove entire transaction from table
- parent->beginRemoveRows(QModelIndex(), lowerIndex, upperIndex-1);
- cachedWallet.erase(lower, upper);
- parent->endRemoveRows();
- }
- else if(inWallet && inModel)
+ break;
+ case CT_DELETED:
+ if(!inModel)
{
- // Updated -- nothing to do, status update will take care of this
+ OutputDebugStringF("Warning: updateWallet: Got CT_DELETED, but transaction is not in model\n");
+ break;
}
+ // Removed -- remove entire transaction from table
+ parent->beginRemoveRows(QModelIndex(), lowerIndex, upperIndex-1);
+ cachedWallet.erase(lower, upper);
+ parent->endRemoveRows();
+ break;
+ case CT_UPDATED:
+ // Miscellaneous updates -- nothing to do, status update will take care of this, and is only computed for
+ // visible transactions.
+ break;
}
}
}
@@ -209,14 +220,15 @@ TransactionTableModel::TransactionTableModel(CWallet* wallet, WalletModel *paren
QAbstractTableModel(parent),
wallet(wallet),
walletModel(parent),
- priv(new TransactionTablePriv(wallet, this))
+ priv(new TransactionTablePriv(wallet, this)),
+ cachedNumBlocks(0)
{
columns << QString() << tr("Date") << tr("Type") << tr("Address") << tr("Amount");
priv->refreshWallet();
QTimer *timer = new QTimer(this);
- connect(timer, SIGNAL(timeout()), this, SLOT(update()));
+ connect(timer, SIGNAL(timeout()), this, SLOT(updateConfirmations()));
timer->start(MODEL_UPDATE_DELAY);
}
@@ -225,29 +237,23 @@ TransactionTableModel::~TransactionTableModel()
delete priv;
}
-void TransactionTableModel::update()
+void TransactionTableModel::updateTransaction(const QString &hash, int status)
{
- QList<uint256> updated;
+ uint256 updated;
+ updated.SetHex(hash.toStdString());
- // Check if there are changes to wallet map
- {
- TRY_LOCK(wallet->cs_wallet, lockWallet);
- if (lockWallet && !wallet->vWalletUpdated.empty())
- {
- BOOST_FOREACH(uint256 hash, wallet->vWalletUpdated)
- {
- updated.append(hash);
- }
- wallet->vWalletUpdated.clear();
- }
- }
+ priv->updateWallet(updated, status);
+}
- if(!updated.empty())
+void TransactionTableModel::updateConfirmations()
+{
+ if(nBestHeight != cachedNumBlocks)
{
- priv->updateWallet(updated);
-
- // Status (number of confirmations) and (possibly) description
- // columns changed for all rows.
+ cachedNumBlocks = nBestHeight;
+ // Blocks came in since last poll.
+ // Invalidate status (number of confirmations) and (possibly) description
+ // for all rows. Qt is smart enough to only actually request the data for the
+ // visible rows.
emit dataChanged(index(0, Status), index(priv->size()-1, Status));
emit dataChanged(index(0, ToAddress), index(priv->size()-1, ToAddress));
}
diff --git a/src/qt/transactiontablemodel.h b/src/qt/transactiontablemodel.h
index db88a0604f..0aafa70915 100644
--- a/src/qt/transactiontablemodel.h
+++ b/src/qt/transactiontablemodel.h
@@ -60,6 +60,7 @@ private:
WalletModel *walletModel;
QStringList columns;
TransactionTablePriv *priv;
+ int cachedNumBlocks;
QString lookupAddress(const std::string &address, bool tooltip) const;
QVariant addressColor(const TransactionRecord *wtx) const;
@@ -72,8 +73,9 @@ private:
QVariant txStatusDecoration(const TransactionRecord *wtx) const;
QVariant txAddressDecoration(const TransactionRecord *wtx) const;
-private slots:
- void update();
+public slots:
+ void updateTransaction(const QString &hash, int status);
+ void updateConfirmations();
friend class TransactionTablePriv;
};
diff --git a/src/qt/verifymessagedialog.cpp b/src/qt/verifymessagedialog.cpp
index 1f82e2ac31..0bac24820c 100644
--- a/src/qt/verifymessagedialog.cpp
+++ b/src/qt/verifymessagedialog.cpp
@@ -25,7 +25,7 @@ VerifyMessageDialog::VerifyMessageDialog(AddressTableModel *addressModel, QWidge
#if (QT_VERSION >= 0x040700)
/* Do not move this to the XML file, Qt before 4.7 will choke on it */
ui->lnSig->setPlaceholderText(tr("Enter Bitcoin signature"));
- ui->lnAddress->setPlaceholderText(tr("Click \"Apply\" to obtain address"));
+ ui->lnAddress->setPlaceholderText(tr("Click \"Verify Message\" to obtain address"));
#endif
GUIUtil::setupAddressWidget(ui->lnAddress, this);
diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp
index b9ccb06c09..b89c3dba33 100644
--- a/src/qt/walletmodel.cpp
+++ b/src/qt/walletmodel.cpp
@@ -18,6 +18,13 @@ WalletModel::WalletModel(CWallet *wallet, OptionsModel *optionsModel, QObject *p
{
addressTableModel = new AddressTableModel(wallet, this);
transactionTableModel = new TransactionTableModel(wallet, this);
+
+ subscribeToCoreSignals();
+}
+
+WalletModel::~WalletModel()
+{
+ unsubscribeFromCoreSignals();
}
qint64 WalletModel::getBalance() const
@@ -40,30 +47,38 @@ int WalletModel::getNumTransactions() const
return numTransactions;
}
-void WalletModel::update()
+void WalletModel::updateStatus()
+{
+ EncryptionStatus newEncryptionStatus = getEncryptionStatus();
+
+ if(cachedEncryptionStatus != newEncryptionStatus)
+ emit encryptionStatusChanged(newEncryptionStatus);
+}
+
+void WalletModel::updateTransaction(const QString &hash, int status)
{
+ if(transactionTableModel)
+ transactionTableModel->updateTransaction(hash, status);
+
+ // Balance and number of transactions might have changed
qint64 newBalance = getBalance();
qint64 newUnconfirmedBalance = getUnconfirmedBalance();
int newNumTransactions = getNumTransactions();
- EncryptionStatus newEncryptionStatus = getEncryptionStatus();
if(cachedBalance != newBalance || cachedUnconfirmedBalance != newUnconfirmedBalance)
emit balanceChanged(newBalance, newUnconfirmedBalance);
-
if(cachedNumTransactions != newNumTransactions)
emit numTransactionsChanged(newNumTransactions);
- if(cachedEncryptionStatus != newEncryptionStatus)
- emit encryptionStatusChanged(newEncryptionStatus);
-
cachedBalance = newBalance;
cachedUnconfirmedBalance = newUnconfirmedBalance;
cachedNumTransactions = newNumTransactions;
}
-void WalletModel::updateAddressList()
+void WalletModel::updateAddressBook(const QString &address, const QString &label, bool isMine, int status)
{
- addressTableModel->update();
+ if(addressTableModel)
+ addressTableModel->updateEntry(address, label, isMine, status);
}
bool WalletModel::validateAddress(const QString &address)
@@ -139,7 +154,7 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(const QList<SendCoinsRecipie
}
return TransactionCreationFailed;
}
- if(!ThreadSafeAskFee(nFeeRequired, tr("Sending...").toStdString()))
+ if(!uiInterface.ThreadSafeAskFee(nFeeRequired, tr("Sending...").toStdString()))
{
return Aborted;
}
@@ -246,6 +261,47 @@ bool WalletModel::backupWallet(const QString &filename)
return BackupWallet(*wallet, filename.toLocal8Bit().data());
}
+// Handlers for core signals
+static void NotifyKeyStoreStatusChanged(WalletModel *walletmodel, CCryptoKeyStore *wallet)
+{
+ OutputDebugStringF("NotifyKeyStoreStatusChanged\n");
+ QMetaObject::invokeMethod(walletmodel, "updateStatus", Qt::QueuedConnection);
+}
+
+static void NotifyAddressBookChanged(WalletModel *walletmodel, CWallet *wallet, const std::string &address, const std::string &label, bool isMine, ChangeType status)
+{
+ OutputDebugStringF("NotifyAddressBookChanged %s %s isMine=%i status=%i\n", address.c_str(), label.c_str(), isMine, status);
+ QMetaObject::invokeMethod(walletmodel, "updateAddressBook", Qt::QueuedConnection,
+ Q_ARG(QString, QString::fromStdString(address)),
+ Q_ARG(QString, QString::fromStdString(label)),
+ Q_ARG(bool, isMine),
+ Q_ARG(int, status));
+}
+
+static void NotifyTransactionChanged(WalletModel *walletmodel, CWallet *wallet, const uint256 &hash, ChangeType status)
+{
+ OutputDebugStringF("NotifyTransactionChanged %s status=%i\n", hash.GetHex().c_str(), status);
+ QMetaObject::invokeMethod(walletmodel, "updateTransaction", Qt::QueuedConnection,
+ Q_ARG(QString, QString::fromStdString(hash.GetHex())),
+ Q_ARG(int, status));
+}
+
+void WalletModel::subscribeToCoreSignals()
+{
+ // Connect signals to wallet
+ wallet->NotifyStatusChanged.connect(boost::bind(&NotifyKeyStoreStatusChanged, this, _1));
+ wallet->NotifyAddressBookChanged.connect(boost::bind(NotifyAddressBookChanged, this, _1, _2, _3, _4, _5));
+ wallet->NotifyTransactionChanged.connect(boost::bind(NotifyTransactionChanged, this, _1, _2, _3));
+}
+
+void WalletModel::unsubscribeFromCoreSignals()
+{
+ // Disconnect signals from wallet
+ wallet->NotifyStatusChanged.disconnect(boost::bind(&NotifyKeyStoreStatusChanged, this, _1));
+ wallet->NotifyAddressBookChanged.disconnect(boost::bind(NotifyAddressBookChanged, this, _1, _2, _3, _4, _5));
+ wallet->NotifyTransactionChanged.disconnect(boost::bind(NotifyTransactionChanged, this, _1, _2, _3));
+}
+
// WalletModel::UnlockContext implementation
WalletModel::UnlockContext WalletModel::requestUnlock()
{
diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h
index 6c47f61bef..8b615ffe8e 100644
--- a/src/qt/walletmodel.h
+++ b/src/qt/walletmodel.h
@@ -24,6 +24,7 @@ class WalletModel : public QObject
Q_OBJECT
public:
explicit WalletModel(CWallet *wallet, OptionsModel *optionsModel, QObject *parent = 0);
+ ~WalletModel();
enum StatusCode // Returned by sendCoins
{
@@ -118,6 +119,8 @@ private:
qint64 cachedNumTransactions;
EncryptionStatus cachedEncryptionStatus;
+ void subscribeToCoreSignals();
+ void unsubscribeFromCoreSignals();
signals:
// Signal that balance in wallet changed
void balanceChanged(qint64 balance, qint64 unconfirmedBalance);
@@ -137,8 +140,12 @@ signals:
void error(const QString &title, const QString &message, bool modal);
public slots:
- void update();
- void updateAddressList();
+ /* Wallet status might have changed */
+ void updateStatus();
+ /* New transaction, or transaction changed status */
+ void updateTransaction(const QString &hash, int status);
+ /* New, updated or removed address book entry */
+ void updateAddressBook(const QString &address, const QString &label, bool isMine, int status);
};
diff --git a/src/rpcdump.cpp b/src/rpcdump.cpp
index 1119aeaf75..5fa24f638d 100644
--- a/src/rpcdump.cpp
+++ b/src/rpcdump.cpp
@@ -1,6 +1,6 @@
// Copyright (c) 2009-2012 Bitcoin Developers
// Distributed under the MIT/X11 software license, see the accompanying
-// file license.txt or http://www.opensource.org/licenses/mit-license.php.
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "init.h" // for pwalletMain
#include "bitcoinrpc.h"
@@ -73,8 +73,6 @@ Value importprivkey(const Array& params, bool fHelp)
pwalletMain->ReacceptWalletTransactions();
}
- MainFrameRepaint();
-
return Value::null;
}
diff --git a/src/script.cpp b/src/script.cpp
index 0b103a80bc..f7c2d316f2 100644
--- a/src/script.cpp
+++ b/src/script.cpp
@@ -1,7 +1,7 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
-// file license.txt or http://www.opensource.org/licenses/mit-license.php.
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <boost/foreach.hpp>
using namespace std;
diff --git a/src/script.h b/src/script.h
index e41e09b6b3..5397a1972f 100644
--- a/src/script.h
+++ b/src/script.h
@@ -1,7 +1,7 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
-// file license.txt or http://www.opensource.org/licenses/mit-license.php.
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef H_BITCOIN_SCRIPT
#define H_BITCOIN_SCRIPT
diff --git a/src/serialize.h b/src/serialize.h
index fe2aebe7f5..349a40bfe8 100644
--- a/src/serialize.h
+++ b/src/serialize.h
@@ -1,7 +1,7 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
-// file license.txt or http://www.opensource.org/licenses/mit-license.php.
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_SERIALIZE_H
#define BITCOIN_SERIALIZE_H
diff --git a/src/sync.cpp b/src/sync.cpp
index d8d86d525e..f2403a43f2 100644
--- a/src/sync.cpp
+++ b/src/sync.cpp
@@ -1,6 +1,6 @@
// Copyright (c) 2011-2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
-// file license.txt or http://www.opensource.org/licenses/mit-license.php.
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "sync.h"
#include "util.h"
diff --git a/src/sync.h b/src/sync.h
index 1604338fb6..dffe4f6ee8 100644
--- a/src/sync.h
+++ b/src/sync.h
@@ -1,7 +1,7 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
-// file license.txt or http://www.opensource.org/licenses/mit-license.php.
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_SYNC_H
#define BITCOIN_SYNC_H
diff --git a/src/test/DoS_tests.cpp b/src/test/DoS_tests.cpp
index 04e2a95d70..7defd23f80 100644
--- a/src/test/DoS_tests.cpp
+++ b/src/test/DoS_tests.cpp
@@ -1,7 +1,10 @@
//
// Unit tests for denial-of-service detection/prevention code
//
+#include <algorithm>
+
#include <boost/assign/list_of.hpp> // for 'map_list_of()'
+#include <boost/date_time/posix_time/posix_time_types.hpp>
#include <boost/test/unit_test.hpp>
#include <boost/foreach.hpp>
@@ -13,10 +16,10 @@
#include <stdint.h>
// Tests this internal-to-main.cpp method:
-extern void AddOrphanTx(const CDataStream& vMsg);
+extern bool AddOrphanTx(const CDataStream& vMsg);
extern unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans);
extern std::map<uint256, CDataStream*> mapOrphanTransactions;
-extern std::multimap<uint256, CDataStream*> mapOrphanTransactionsByPrev;
+extern std::map<uint256, std::map<uint256, CDataStream*> > mapOrphanTransactionsByPrev;
CService ip(uint32_t i)
{
@@ -57,7 +60,7 @@ BOOST_AUTO_TEST_CASE(DoS_banscore)
BOOST_CHECK(!CNode::IsBanned(addr1));
dummyNode1.Misbehaving(1);
BOOST_CHECK(CNode::IsBanned(addr1));
- mapArgs["-banscore"] = "100";
+ mapArgs.erase("-banscore");
}
BOOST_AUTO_TEST_CASE(DoS_bantime)
@@ -129,18 +132,10 @@ BOOST_AUTO_TEST_CASE(DoS_checknbits)
}
-static uint256 RandomHash()
-{
- std::vector<unsigned char> randbytes(32);
- RAND_bytes(&randbytes[0], 32);
- uint256 randomhash(randbytes);
- return randomhash;
-}
-
CTransaction RandomOrphan()
{
std::map<uint256, CDataStream*>::iterator it;
- it = mapOrphanTransactions.lower_bound(RandomHash());
+ it = mapOrphanTransactions.lower_bound(GetRandHash());
if (it == mapOrphanTransactions.end())
it = mapOrphanTransactions.begin();
const CDataStream* pvMsg = it->second;
@@ -162,7 +157,7 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans)
CTransaction tx;
tx.vin.resize(1);
tx.vin[0].prevout.n = 0;
- tx.vin[0].prevout.hash = RandomHash();
+ tx.vin[0].prevout.hash = GetRandHash();
tx.vin[0].scriptSig << OP_1;
tx.vout.resize(1);
tx.vout[0].nValue = 1*CENT;
@@ -192,6 +187,32 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans)
AddOrphanTx(ds);
}
+ // This really-big orphan should be ignored:
+ for (int i = 0; i < 10; i++)
+ {
+ CTransaction txPrev = RandomOrphan();
+
+ CTransaction tx;
+ tx.vout.resize(1);
+ tx.vout[0].nValue = 1*CENT;
+ tx.vout[0].scriptPubKey.SetBitcoinAddress(key.GetPubKey());
+ tx.vin.resize(500);
+ for (int j = 0; j < tx.vin.size(); j++)
+ {
+ tx.vin[j].prevout.n = j;
+ tx.vin[j].prevout.hash = txPrev.GetHash();
+ }
+ SignSignature(keystore, txPrev, tx, 0);
+ // Re-use same signature for other inputs
+ // (they don't have to be valid for this test)
+ for (int j = 1; j < tx.vin.size(); j++)
+ tx.vin[j].scriptSig = tx.vin[0].scriptSig;
+
+ CDataStream ds(SER_DISK, CLIENT_VERSION);
+ ds << tx;
+ BOOST_CHECK(!AddOrphanTx(ds));
+ }
+
// Test LimitOrphanTxSize() function:
LimitOrphanTxSize(40);
BOOST_CHECK(mapOrphanTransactions.size() <= 40);
@@ -202,4 +223,92 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans)
BOOST_CHECK(mapOrphanTransactionsByPrev.empty());
}
+BOOST_AUTO_TEST_CASE(DoS_checkSig)
+{
+ // Test signature caching code (see key.cpp Verify() methods)
+
+ CKey key;
+ key.MakeNewKey(true);
+ CBasicKeyStore keystore;
+ keystore.AddKey(key);
+
+ // 100 orphan transactions:
+ static const int NPREV=100;
+ CTransaction orphans[NPREV];
+ for (int i = 0; i < NPREV; i++)
+ {
+ CTransaction& tx = orphans[i];
+ tx.vin.resize(1);
+ tx.vin[0].prevout.n = 0;
+ tx.vin[0].prevout.hash = GetRandHash();
+ tx.vin[0].scriptSig << OP_1;
+ tx.vout.resize(1);
+ tx.vout[0].nValue = 1*CENT;
+ tx.vout[0].scriptPubKey.SetBitcoinAddress(key.GetPubKey());
+
+ CDataStream ds(SER_DISK, CLIENT_VERSION);
+ ds << tx;
+ AddOrphanTx(ds);
+ }
+
+ // Create a transaction that depends on orphans:
+ CTransaction tx;
+ tx.vout.resize(1);
+ tx.vout[0].nValue = 1*CENT;
+ tx.vout[0].scriptPubKey.SetBitcoinAddress(key.GetPubKey());
+ tx.vin.resize(NPREV);
+ for (int j = 0; j < tx.vin.size(); j++)
+ {
+ tx.vin[j].prevout.n = 0;
+ tx.vin[j].prevout.hash = orphans[j].GetHash();
+ }
+ // Creating signatures primes the cache:
+ boost::posix_time::ptime mst1 = boost::posix_time::microsec_clock::local_time();
+ for (int j = 0; j < tx.vin.size(); j++)
+ BOOST_CHECK(SignSignature(keystore, orphans[j], tx, j));
+ boost::posix_time::ptime mst2 = boost::posix_time::microsec_clock::local_time();
+ boost::posix_time::time_duration msdiff = mst2 - mst1;
+ long nOneValidate = msdiff.total_milliseconds();
+ if (fDebug) printf("DoS_Checksig sign: %ld\n", nOneValidate);
+
+ // ... now validating repeatedly should be quick:
+ // 2.8GHz machine, -g build: Sign takes ~760ms,
+ // uncached Verify takes ~250ms, cached Verify takes ~50ms
+ // (for 100 single-signature inputs)
+ mst1 = boost::posix_time::microsec_clock::local_time();
+ for (int i = 0; i < 5; i++)
+ for (int j = 0; j < tx.vin.size(); j++)
+ BOOST_CHECK(VerifySignature(orphans[j], tx, j, true, SIGHASH_ALL));
+ mst2 = boost::posix_time::microsec_clock::local_time();
+ msdiff = mst2 - mst1;
+ long nManyValidate = msdiff.total_milliseconds();
+ if (fDebug) printf("DoS_Checksig five: %ld\n", nManyValidate);
+
+ BOOST_CHECK_MESSAGE(nManyValidate < nOneValidate, "Signature cache timing failed");
+
+ // Empty a signature, validation should fail:
+ CScript save = tx.vin[0].scriptSig;
+ tx.vin[0].scriptSig = CScript();
+ BOOST_CHECK(!VerifySignature(orphans[0], tx, 0, true, SIGHASH_ALL));
+ tx.vin[0].scriptSig = save;
+
+ // Swap signatures, validation should fail:
+ std::swap(tx.vin[0].scriptSig, tx.vin[1].scriptSig);
+ BOOST_CHECK(!VerifySignature(orphans[0], tx, 0, true, SIGHASH_ALL));
+ BOOST_CHECK(!VerifySignature(orphans[1], tx, 1, true, SIGHASH_ALL));
+ std::swap(tx.vin[0].scriptSig, tx.vin[1].scriptSig);
+
+ // Exercise -maxsigcachesize code:
+ mapArgs["-maxsigcachesize"] = "10";
+ // Generate a new, different signature for vin[0] to trigger cache clear:
+ CScript oldSig = tx.vin[0].scriptSig;
+ BOOST_CHECK(SignSignature(keystore, orphans[0], tx, 0));
+ BOOST_CHECK(tx.vin[0].scriptSig != oldSig);
+ for (int j = 0; j < tx.vin.size(); j++)
+ BOOST_CHECK(VerifySignature(orphans[j], tx, j, true, SIGHASH_ALL));
+ mapArgs.erase("-maxsigcachesize");
+
+ LimitOrphanTxSize(0);
+}
+
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp
index 7ff7545ab4..bf597c9b73 100644
--- a/src/test/test_bitcoin.cpp
+++ b/src/test/test_bitcoin.cpp
@@ -5,11 +5,15 @@
#include "wallet.h"
CWallet* pwalletMain;
+CClientUIInterface uiInterface;
extern bool fPrintToConsole;
+extern void noui_connect();
+
struct TestingSetup {
TestingSetup() {
fPrintToConsole = true; // don't want to write to debug.log file
+ noui_connect();
pwalletMain = new CWallet();
RegisterWallet(pwalletMain);
}
diff --git a/src/ui_interface.h b/src/ui_interface.h
index 514768086d..b94446cc20 100644
--- a/src/ui_interface.h
+++ b/src/ui_interface.h
@@ -1,50 +1,104 @@
// Copyright (c) 2010 Satoshi Nakamoto
// Distributed under the MIT/X11 software license, see the accompanying
-// file license.txt or http://www.opensource.org/licenses/mit-license.php.
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_UI_INTERFACE_H
#define BITCOIN_UI_INTERFACE_H
#include <string>
#include "util.h" // for int64
+#include <boost/signals2/signal.hpp>
+#include <boost/signals2/last_value.hpp>
-#define wxYES 0x00000002
-#define wxOK 0x00000004
-#define wxNO 0x00000008
-#define wxYES_NO (wxYES|wxNO)
-#define wxCANCEL 0x00000010
-#define wxAPPLY 0x00000020
-#define wxCLOSE 0x00000040
-#define wxOK_DEFAULT 0x00000000
-#define wxYES_DEFAULT 0x00000000
-#define wxNO_DEFAULT 0x00000080
-#define wxCANCEL_DEFAULT 0x80000000
-#define wxICON_EXCLAMATION 0x00000100
-#define wxICON_HAND 0x00000200
-#define wxICON_WARNING wxICON_EXCLAMATION
-#define wxICON_ERROR wxICON_HAND
-#define wxICON_QUESTION 0x00000400
-#define wxICON_INFORMATION 0x00000800
-#define wxICON_STOP wxICON_HAND
-#define wxICON_ASTERISK wxICON_INFORMATION
-#define wxICON_MASK (0x00000100|0x00000200|0x00000400|0x00000800)
-#define wxFORWARD 0x00001000
-#define wxBACKWARD 0x00002000
-#define wxRESET 0x00004000
-#define wxHELP 0x00008000
-#define wxMORE 0x00010000
-#define wxSETUP 0x00020000
-// Force blocking, modal message box dialog (not just notification)
-#define wxMODAL 0x00040000
-
-/* These UI communication functions are implemented in bitcoin.cpp (for ui) and noui.cpp (no ui) */
-
-extern int ThreadSafeMessageBox(const std::string& message, const std::string& caption, int style=wxOK);
-extern bool ThreadSafeAskFee(int64 nFeeRequired, const std::string& strCaption);
-extern void ThreadSafeHandleURI(const std::string& strURI);
-extern void MainFrameRepaint();
-extern void AddressBookRepaint();
-extern void QueueShutdown();
-extern void InitMessage(const std::string &message);
-extern std::string _(const char* psz);
+class CBasicKeyStore;
+class CWallet;
+class uint256;
+
+/** General change type (added, updated, removed). */
+enum ChangeType
+{
+ CT_NEW,
+ CT_UPDATED,
+ CT_DELETED
+};
+
+/** Signals for UI communication. */
+class CClientUIInterface
+{
+public:
+ /** Flags for CClientUIInterface::ThreadSafeMessageBox */
+ enum MessageBoxFlags
+ {
+ YES = 0x00000002,
+ OK = 0x00000004,
+ NO = 0x00000008,
+ YES_NO = (YES|NO),
+ CANCEL = 0x00000010,
+ APPLY = 0x00000020,
+ CLOSE = 0x00000040,
+ OK_DEFAULT = 0x00000000,
+ YES_DEFAULT = 0x00000000,
+ NO_DEFAULT = 0x00000080,
+ CANCEL_DEFAULT = 0x80000000,
+ ICON_EXCLAMATION = 0x00000100,
+ ICON_HAND = 0x00000200,
+ ICON_WARNING = ICON_EXCLAMATION,
+ ICON_ERROR = ICON_HAND,
+ ICON_QUESTION = 0x00000400,
+ ICON_INFORMATION = 0x00000800,
+ ICON_STOP = ICON_HAND,
+ ICON_ASTERISK = ICON_INFORMATION,
+ ICON_MASK = (0x00000100|0x00000200|0x00000400|0x00000800),
+ FORWARD = 0x00001000,
+ BACKWARD = 0x00002000,
+ RESET = 0x00004000,
+ HELP = 0x00008000,
+ MORE = 0x00010000,
+ SETUP = 0x00020000,
+ // Force blocking, modal message box dialog (not just OS notification)
+ MODAL = 0x00040000
+ };
+
+ /** Show message box. */
+ boost::signals2::signal<void (const std::string& message, const std::string& caption, int style)> ThreadSafeMessageBox;
+
+ /** Ask the user whether he want to pay a fee or not. */
+ boost::signals2::signal<bool (int64 nFeeRequired, const std::string& strCaption), boost::signals2::last_value<bool> > ThreadSafeAskFee;
+
+ /** Handle an URL passed on the command line. */
+ boost::signals2::signal<void (const std::string& strURI)> ThreadSafeHandleURI;
+
+ /** Progress message during initialization. */
+ boost::signals2::signal<void (const std::string &message)> InitMessage;
+
+ /** Initiate client shutdown. */
+ boost::signals2::signal<void ()> QueueShutdown;
+
+ /** Translate a message to the native language of the user. */
+ boost::signals2::signal<std::string (const char* psz)> Translate;
+
+ /** Block chain changed. */
+ boost::signals2::signal<void ()> NotifyBlocksChanged;
+
+ /** Number of network connections changed. */
+ boost::signals2::signal<void (int newNumConnections)> NotifyNumConnectionsChanged;
+
+ /**
+ * New, updated or cancelled alert.
+ * @note called with lock cs_mapAlerts held.
+ */
+ boost::signals2::signal<void (const uint256 &hash, ChangeType status)> NotifyAlertChanged;
+};
+
+extern CClientUIInterface uiInterface;
+
+/**
+ * Translation function: Call Translate signal on UI interface, which returns a boost::optional result.
+ * If no translation slot is registered, nothing is returned, and simply return the input.
+ */
+inline std::string _(const char* psz)
+{
+ boost::optional<std::string> rv = uiInterface.Translate(psz);
+ return rv ? (*rv) : psz;
+}
#endif
diff --git a/src/uint256.h b/src/uint256.h
index 9966a14ed7..fc5ed26592 100644
--- a/src/uint256.h
+++ b/src/uint256.h
@@ -1,7 +1,7 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
-// file license.txt or http://www.opensource.org/licenses/mit-license.php.
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_UINT256_H
#define BITCOIN_UINT256_H
diff --git a/src/util.cpp b/src/util.cpp
index b0c80f6dfc..08e3625b3d 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -1,7 +1,7 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
-// file license.txt or http://www.opensource.org/licenses/mit-license.php.
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "util.h"
#include "sync.h"
@@ -25,6 +25,7 @@ namespace boost {
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
#include <boost/foreach.hpp>
+#include <boost/thread.hpp>
#include <openssl/crypto.h>
#include <openssl/rand.h>
#include <stdarg.h>
@@ -69,6 +70,7 @@ bool fTestNet = false;
bool fNoListen = false;
bool fLogTimestamps = false;
CMedianFilter<int64> vTimeOffsets(200,0);
+bool fReopenDebugLog = false;
// Init openssl library multithreading support
static CCriticalSection** ppmutexOpenSSL;
@@ -174,8 +176,12 @@ int GetRandInt(int nMax)
return GetRand(nMax);
}
-
-
+uint256 GetRandHash()
+{
+ uint256 hash;
+ RAND_bytes((unsigned char*)&hash, sizeof(hash));
+ return hash;
+}
@@ -209,6 +215,16 @@ inline int OutputDebugStringF(const char* pszFormat, ...)
if (fileout)
{
static bool fStartedNewLine = true;
+ static boost::mutex mutexDebugLog;
+ boost::mutex::scoped_lock scoped_lock(mutexDebugLog);
+
+ // reopen the log file, if requested
+ if (fReopenDebugLog) {
+ fReopenDebugLog = false;
+ boost::filesystem::path pathDebug = GetDataDir() / "debug.log";
+ if (freopen(pathDebug.string().c_str(),"a",fileout) != NULL)
+ setbuf(fileout, NULL); // unbuffered
+ }
// Debug print useful for profiling
if (fLogTimestamps && fStartedNewLine)
@@ -230,68 +246,30 @@ inline int OutputDebugStringF(const char* pszFormat, ...)
{
static CCriticalSection cs_OutputDebugStringF;
- // accumulate a line at a time
+ // accumulate and output a line at a time
{
LOCK(cs_OutputDebugStringF);
- static char pszBuffer[50000];
- static char* pend;
- if (pend == NULL)
- pend = pszBuffer;
+ static std::string buffer;
+
va_list arg_ptr;
va_start(arg_ptr, pszFormat);
- int limit = END(pszBuffer) - pend - 2;
- int ret = _vsnprintf(pend, limit, pszFormat, arg_ptr);
+ buffer += vstrprintf(pszFormat, arg_ptr);
va_end(arg_ptr);
- if (ret < 0 || ret >= limit)
- {
- pend = END(pszBuffer) - 2;
- *pend++ = '\n';
- }
- else
- pend += ret;
- *pend = '\0';
- char* p1 = pszBuffer;
- char* p2;
- while ((p2 = strchr(p1, '\n')))
+
+ int line_start = 0, line_end;
+ while((line_end = buffer.find('\n', line_start)) != -1)
{
- p2++;
- char c = *p2;
- *p2 = '\0';
- OutputDebugStringA(p1);
- *p2 = c;
- p1 = p2;
+ OutputDebugStringA(buffer.substr(line_start, line_end - line_start).c_str());
+ line_start = line_end + 1;
}
- if (p1 != pszBuffer)
- memmove(pszBuffer, p1, pend - p1 + 1);
- pend -= (p1 - pszBuffer);
+ buffer.erase(0, line_start);
}
}
#endif
return ret;
}
-
-// Safer snprintf
-// - prints up to limit-1 characters
-// - output string is always null terminated even if limit reached
-// - return value is the number of characters actually printed
-int my_snprintf(char* buffer, size_t limit, const char* format, ...)
-{
- if (limit == 0)
- return 0;
- va_list arg_ptr;
- va_start(arg_ptr, format);
- int ret = _vsnprintf(buffer, limit, format, arg_ptr);
- va_end(arg_ptr);
- if (ret < 0 || ret >= (int)limit)
- {
- ret = limit - 1;
- buffer[limit-1] = 0;
- }
- return ret;
-}
-
-string real_strprintf(const std::string &format, int dummy, ...)
+string vstrprintf(const std::string &format, va_list ap)
{
char buffer[50000];
char* p = buffer;
@@ -300,7 +278,7 @@ string real_strprintf(const std::string &format, int dummy, ...)
loop
{
va_list arg_ptr;
- va_start(arg_ptr, dummy);
+ va_copy(arg_ptr, ap);
ret = _vsnprintf(p, limit, format.c_str(), arg_ptr);
va_end(arg_ptr);
if (ret >= 0 && ret < limit)
@@ -318,19 +296,22 @@ string real_strprintf(const std::string &format, int dummy, ...)
return str;
}
+string real_strprintf(const std::string &format, int dummy, ...)
+{
+ va_list arg_ptr;
+ va_start(arg_ptr, dummy);
+ string str = vstrprintf(format, arg_ptr);
+ va_end(arg_ptr);
+ return str;
+}
+
bool error(const char *format, ...)
{
- char buffer[50000];
- int limit = sizeof(buffer);
va_list arg_ptr;
va_start(arg_ptr, format);
- int ret = _vsnprintf(buffer, limit, format, arg_ptr);
+ std::string str = vstrprintf(format, arg_ptr);
va_end(arg_ptr);
- if (ret < 0 || ret >= limit)
- {
- buffer[limit - 1] = 0;
- }
- printf("ERROR: %s\n", buffer);
+ printf("ERROR: %s\n", str.c_str());
return false;
}
@@ -758,7 +739,7 @@ bool WildcardMatch(const string& str, const string& mask)
-void FormatException(char* pszMessage, std::exception* pex, const char* pszThread)
+static std::string FormatException(std::exception* pex, const char* pszThread)
{
#ifdef WIN32
char pszModule[MAX_PATH] = "";
@@ -767,37 +748,34 @@ void FormatException(char* pszMessage, std::exception* pex, const char* pszThrea
const char* pszModule = "bitcoin";
#endif
if (pex)
- snprintf(pszMessage, 1000,
+ return strprintf(
"EXCEPTION: %s \n%s \n%s in %s \n", typeid(*pex).name(), pex->what(), pszModule, pszThread);
else
- snprintf(pszMessage, 1000,
+ return strprintf(
"UNKNOWN EXCEPTION \n%s in %s \n", pszModule, pszThread);
}
void LogException(std::exception* pex, const char* pszThread)
{
- char pszMessage[10000];
- FormatException(pszMessage, pex, pszThread);
- printf("\n%s", pszMessage);
+ std::string message = FormatException(pex, pszThread);
+ printf("\n%s", message.c_str());
}
void PrintException(std::exception* pex, const char* pszThread)
{
- char pszMessage[10000];
- FormatException(pszMessage, pex, pszThread);
- printf("\n\n************************\n%s\n", pszMessage);
- fprintf(stderr, "\n\n************************\n%s\n", pszMessage);
- strMiscWarning = pszMessage;
+ std::string message = FormatException(pex, pszThread);
+ printf("\n\n************************\n%s\n", message.c_str());
+ fprintf(stderr, "\n\n************************\n%s\n", message.c_str());
+ strMiscWarning = message;
throw;
}
void PrintExceptionContinue(std::exception* pex, const char* pszThread)
{
- char pszMessage[10000];
- FormatException(pszMessage, pex, pszThread);
- printf("\n\n************************\n%s\n", pszMessage);
- fprintf(stderr, "\n\n************************\n%s\n", pszMessage);
- strMiscWarning = pszMessage;
+ std::string message = FormatException(pex, pszThread);
+ printf("\n\n************************\n%s\n", message.c_str());
+ fprintf(stderr, "\n\n************************\n%s\n", message.c_str());
+ strMiscWarning = message;
}
boost::filesystem::path GetDefaultDataDir()
@@ -1040,7 +1018,7 @@ void AddTimeData(const CNetAddr& ip, int64 nTime)
string strMessage = _("Warning: Please check that your computer's date and time are correct. If your clock is wrong Bitcoin will not work properly.");
strMiscWarning = strMessage;
printf("*** %s\n", strMessage.c_str());
- ThreadSafeMessageBox(strMessage+" ", string("Bitcoin"), wxOK | wxICON_EXCLAMATION);
+ uiInterface.ThreadSafeMessageBox(strMessage+" ", string("Bitcoin"), CClientUIInterface::OK | CClientUIInterface::ICON_EXCLAMATION);
}
}
}
diff --git a/src/util.h b/src/util.h
index f7bdaf5332..5b58147ce6 100644
--- a/src/util.h
+++ b/src/util.h
@@ -1,7 +1,7 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
-// file license.txt or http://www.opensource.org/licenses/mit-license.php.
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_UTIL_H
#define BITCOIN_UTIL_H
@@ -43,11 +43,6 @@ static const int64 CENT = 1000000;
#define ARRAYLEN(array) (sizeof(array)/sizeof((array)[0]))
#define printf OutputDebugStringF
-#ifdef snprintf
-#undef snprintf
-#endif
-#define snprintf my_snprintf
-
#ifndef PRI64d
#if defined(_MSC_VER) || defined(__MSVCRT__)
#define PRI64d "I64d"
@@ -121,6 +116,7 @@ extern std::string strMiscWarning;
extern bool fTestNet;
extern bool fNoListen;
extern bool fLogTimestamps;
+extern bool fReopenDebugLog;
void RandAddSeed();
void RandAddSeedPerfmon();
@@ -133,6 +129,7 @@ int my_snprintf(char* buffer, size_t limit, const char* format, ...);
*/
std::string real_strprintf(const std::string &format, int dummy, ...);
#define strprintf(format, ...) real_strprintf(format, 0, __VA_ARGS__)
+std::string vstrprintf(const std::string &format, va_list ap);
bool error(const char *format, ...);
void LogException(std::exception* pex, const char* pszThread);
@@ -167,6 +164,7 @@ boost::filesystem::path GetSpecialFolderPath(int nFolder, bool fCreate = true);
void ShrinkDebugFile();
int GetRandInt(int nMax);
uint64 GetRand(uint64 nMax);
+uint256 GetRandHash();
int64 GetTime();
void SetMockTime(int64 nMockTimeIn);
int64 GetAdjustedTime();
diff --git a/src/version.cpp b/src/version.cpp
index 0c1e8bfa80..60b7aae2e5 100644
--- a/src/version.cpp
+++ b/src/version.cpp
@@ -1,6 +1,6 @@
// Copyright (c) 2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
-// file license.txt or http://www.opensource.org/licenses/mit-license.php.
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <string>
#include "version.h"
diff --git a/src/version.h b/src/version.h
index 7859fb2dcd..c0d53e8b91 100644
--- a/src/version.h
+++ b/src/version.h
@@ -1,6 +1,6 @@
// Copyright (c) 2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
-// file license.txt or http://www.opensource.org/licenses/mit-license.php.
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_VERSION_H
#define BITCOIN_VERSION_H
diff --git a/src/wallet.cpp b/src/wallet.cpp
index 768f9f85ea..62f663c0dc 100644
--- a/src/wallet.cpp
+++ b/src/wallet.cpp
@@ -1,7 +1,7 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
-// file license.txt or http://www.opensource.org/licenses/mit-license.php.
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "wallet.h"
#include "walletdb.h"
@@ -274,7 +274,9 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
// Need to completely rewrite the wallet file; if we don't, bdb might keep
// bits of the unencrypted private key in slack space in the database file.
CDB::Rewrite(strWalletFile);
+
}
+ NotifyStatusChanged(this);
return true;
}
@@ -297,7 +299,7 @@ void CWallet::WalletUpdateSpent(const CTransaction &tx)
printf("WalletUpdateSpent found spent coin %sbc %s\n", FormatMoney(wtx.GetCredit()).c_str(), wtx.GetHash().ToString().c_str());
wtx.MarkSpent(txin.prevout.n);
wtx.WriteToDisk();
- vWalletUpdated.push_back(txin.prevout.hash);
+ NotifyTransactionChanged(this, txin.prevout.hash, CT_UPDATED);
}
}
}
@@ -373,15 +375,12 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn)
}
}
#endif
- // Notify UI
- vWalletUpdated.push_back(hash);
-
// since AddToWallet is called directly for self-originating transactions, check for consumption of own coins
WalletUpdateSpent(wtx);
- }
- // Refresh UI
- MainFrameRepaint();
+ // Notify UI of new or updated transaction
+ NotifyTransactionChanged(this, hash, fInsertedNew ? CT_NEW : CT_UPDATED);
+ }
return true;
}
@@ -1183,7 +1182,7 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey)
coin.BindWallet(this);
coin.MarkSpent(txin.prevout.n);
coin.WriteToDisk();
- vWalletUpdated.push_back(coin.GetHash());
+ NotifyTransactionChanged(this, coin.GetHash(), CT_UPDATED);
}
if (fFileBacked)
@@ -1202,7 +1201,6 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey)
}
wtxNew.RelayWalletTransaction();
}
- MainFrameRepaint();
return true;
}
@@ -1231,13 +1229,12 @@ string CWallet::SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew,
return strError;
}
- if (fAskFee && !ThreadSafeAskFee(nFeeRequired, _("Sending...")))
+ if (fAskFee && !uiInterface.ThreadSafeAskFee(nFeeRequired, _("Sending...")))
return "ABORTED";
if (!CommitTransaction(wtxNew, reservekey))
return _("Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here.");
- MainFrameRepaint();
return "";
}
@@ -1290,8 +1287,9 @@ int CWallet::LoadWallet(bool& fFirstRunRet)
bool CWallet::SetAddressBookName(const CBitcoinAddress& address, const string& strName)
{
+ std::map<CBitcoinAddress, std::string>::iterator mi = mapAddressBook.find(address);
mapAddressBook[address] = strName;
- AddressBookRepaint();
+ NotifyAddressBookChanged(this, address.ToString(), strName, HaveKey(address), (mi == mapAddressBook.end()) ? CT_NEW : CT_UPDATED);
if (!fFileBacked)
return false;
return CWalletDB(strWalletFile).WriteName(address.ToString(), strName);
@@ -1300,7 +1298,7 @@ bool CWallet::SetAddressBookName(const CBitcoinAddress& address, const string& s
bool CWallet::DelAddressBookName(const CBitcoinAddress& address)
{
mapAddressBook.erase(address);
- AddressBookRepaint();
+ NotifyAddressBookChanged(this, address.ToString(), "", HaveKey(address), CT_DELETED);
if (!fFileBacked)
return false;
return CWalletDB(strWalletFile).EraseName(address.ToString());
@@ -1558,3 +1556,14 @@ void CWallet::GetAllReserveAddresses(set<CBitcoinAddress>& setAddress)
setAddress.insert(address);
}
}
+
+void CWallet::UpdatedTransaction(const uint256 &hashTx)
+{
+ {
+ LOCK(cs_wallet);
+ // Only notify UI if this transaction is in this wallet
+ map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(hashTx);
+ if (mi != mapWallet.end())
+ NotifyTransactionChanged(this, hashTx, CT_UPDATED);
+ }
+}
diff --git a/src/wallet.h b/src/wallet.h
index 44c11e2ec4..57633c4aa3 100644
--- a/src/wallet.h
+++ b/src/wallet.h
@@ -1,7 +1,7 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
-// file license.txt or http://www.opensource.org/licenses/mit-license.php.
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_WALLET_H
#define BITCOIN_WALLET_H
@@ -9,6 +9,7 @@
#include "key.h"
#include "keystore.h"
#include "script.h"
+#include "ui_interface.h"
class CWalletTx;
class CReserveKey;
@@ -102,8 +103,6 @@ public:
}
std::map<uint256, CWalletTx> mapWallet;
- std::vector<uint256> vWalletUpdated;
-
std::map<uint256, int> mapRequestCount;
std::map<CBitcoinAddress, std::string> mapAddressBook;
@@ -232,13 +231,7 @@ public:
bool DelAddressBookName(const CBitcoinAddress& address);
- void UpdatedTransaction(const uint256 &hashTx)
- {
- {
- LOCK(cs_wallet);
- vWalletUpdated.push_back(hashTx);
- }
- }
+ void UpdatedTransaction(const uint256 &hashTx);
void PrintWallet(const CBlock& block);
@@ -269,6 +262,16 @@ public:
// get the current wallet format (the oldest client version guaranteed to understand this wallet)
int GetVersion() { return nWalletVersion; }
+
+ /** Address book entry changed.
+ * @note called with lock cs_wallet held.
+ */
+ boost::signals2::signal<void (CWallet *wallet, const std::string &address, const std::string &label, bool isMine, ChangeType status)> NotifyAddressBookChanged;
+
+ /** Wallet transaction added, removed or updated.
+ * @note called with lock cs_wallet held.
+ */
+ boost::signals2::signal<void (CWallet *wallet, const uint256 &hashTx, ChangeType status)> NotifyTransactionChanged;
};
/** A key allocated from the key pool. */
diff --git a/src/walletdb.cpp b/src/walletdb.cpp
index 84dedbc88e..2d44e4982f 100644
--- a/src/walletdb.cpp
+++ b/src/walletdb.cpp
@@ -1,7 +1,7 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
-// file license.txt or http://www.opensource.org/licenses/mit-license.php.
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "walletdb.h"
#include "wallet.h"
diff --git a/src/walletdb.h b/src/walletdb.h
index 46ba7967ca..dee1750262 100644
--- a/src/walletdb.h
+++ b/src/walletdb.h
@@ -1,7 +1,7 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
-// file license.txt or http://www.opensource.org/licenses/mit-license.php.
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_WALLETDB_H
#define BITCOIN_WALLETDB_H