aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md2
-rw-r--r--bitcoin-qt.pro9
-rw-r--r--contrib/homebrew/makefile.osx.patch47
-rw-r--r--doc/build-osx.md173
-rw-r--r--doc/build-osx.txt54
-rw-r--r--share/qt/Info.plist31
-rw-r--r--src/bitcoinrpc.cpp2
-rw-r--r--src/checkpoints.cpp75
-rw-r--r--src/checkpoints.h2
-rw-r--r--src/init.cpp3
-rw-r--r--src/main.cpp45
-rw-r--r--src/main.h35
-rw-r--r--src/qt/bitcoin.cpp33
-rw-r--r--src/qt/bitcoingui.cpp84
-rw-r--r--src/qt/bitcoingui.h2
-rw-r--r--src/qt/clientmodel.cpp6
-rw-r--r--src/qt/clientmodel.h1
-rw-r--r--src/qt/guiconstants.h2
-rw-r--r--src/qt/paymentserver.cpp159
-rw-r--r--src/qt/paymentserver.h66
-rw-r--r--src/qt/qtipcserver.cpp165
-rw-r--r--src/qt/qtipcserver.h16
-rw-r--r--src/rpcwallet.cpp1
-rw-r--r--src/test/util_tests.cpp62
-rw-r--r--src/txdb.cpp6
-rw-r--r--src/txdb.h6
-rw-r--r--src/util.cpp80
-rw-r--r--src/util.h28
-rw-r--r--src/wallet.cpp21
29 files changed, 848 insertions, 368 deletions
diff --git a/README.md b/README.md
index 58dc2969a6..ce9bfae872 100644
--- a/README.md
+++ b/README.md
@@ -66,7 +66,7 @@ Unit tests for the GUI code are in `src/qt/test/`. To compile and run them:
qmake BITCOIN_QT_TEST=1 -o Makefile.test bitcoin-qt.pro
make -f Makefile.test
- ./Bitcoin-Qt
+ ./bitcoin-qt_test
Every pull request is built for both Windows and Linux on a dedicated server,
and unit and sanity tests are automatically run. The binaries produced may be
diff --git a/bitcoin-qt.pro b/bitcoin-qt.pro
index c527b76dad..5042adfbdf 100644
--- a/bitcoin-qt.pro
+++ b/bitcoin-qt.pro
@@ -1,7 +1,9 @@
TEMPLATE = app
TARGET = bitcoin-qt
+macx:TARGET = "Bitcoin-Qt"
VERSION = 0.8.0
INCLUDEPATH += src src/json src/qt
+QT += network
DEFINES += QT_GUI BOOST_THREAD_USE_LIB BOOST_SPIRIT_THREADSAFE
CONFIG += no_include_pwd
CONFIG += thread
@@ -195,7 +197,7 @@ HEADERS += src/qt/bitcoingui.h \
src/qt/askpassphrasedialog.h \
src/protocol.h \
src/qt/notificator.h \
- src/qt/qtipcserver.h \
+ src/qt/paymentserver.h \
src/allocators.h \
src/ui_interface.h \
src/qt/rpcconsole.h \
@@ -265,7 +267,7 @@ SOURCES += src/qt/bitcoin.cpp \
src/qt/askpassphrasedialog.cpp \
src/protocol.cpp \
src/qt/notificator.cpp \
- src/qt/qtipcserver.cpp \
+ src/qt/paymentserver.cpp \
src/qt/rpcconsole.cpp \
src/noui.cpp \
src/leveldb.cpp \
@@ -299,6 +301,7 @@ DEPENDPATH += src/qt/test
QT += testlib
TARGET = bitcoin-qt_test
DEFINES += BITCOIN_QT_TEST
+ macx: CONFIG -= app_bundle
}
CODECFORTR = UTF-8
@@ -380,10 +383,10 @@ macx:OBJECTIVE_SOURCES += src/qt/macdockiconhandler.mm
macx:LIBS += -framework Foundation -framework ApplicationServices -framework AppKit
macx:DEFINES += MAC_OSX MSG_NOSIGNAL=0
macx:ICON = src/qt/res/icons/bitcoin.icns
-macx:TARGET = "Bitcoin-Qt"
macx:QMAKE_CFLAGS_THREAD += -pthread
macx:QMAKE_LFLAGS_THREAD += -pthread
macx:QMAKE_CXXFLAGS_THREAD += -pthread
+macx:QMAKE_INFO_PLIST = share/qt/Info.plist
# Set libraries and includes at end, to use platform-defined defaults if not overridden
INCLUDEPATH += $$BOOST_INCLUDE_PATH $$BDB_INCLUDE_PATH $$OPENSSL_INCLUDE_PATH $$QRENCODE_INCLUDE_PATH
diff --git a/contrib/homebrew/makefile.osx.patch b/contrib/homebrew/makefile.osx.patch
new file mode 100644
index 0000000000..340de0efdf
--- /dev/null
+++ b/contrib/homebrew/makefile.osx.patch
@@ -0,0 +1,47 @@
+diff --git a/src/makefile.osx b/src/makefile.osx
+index 8b7c559..8a0560c 100644
+--- a/src/makefile.osx
++++ b/src/makefile.osx
+@@ -7,17 +7,21 @@
+ # Originally by Laszlo Hanyecz (solar@heliacal.net)
+
+ CXX=llvm-g++
+-DEPSDIR=/opt/local
++DEPSDIR=/usr/local
++DB4DIR=/usr/local/opt/berkeley-db4
++OPENSSLDIR=/usr/local/opt/openssl
+
+ INCLUDEPATHS= \
+ -I"$(CURDIR)" \
+- -I"$(CURDIR)"/obj \
++ -I"$(CURDIR)/obj" \
+ -I"$(DEPSDIR)/include" \
+- -I"$(DEPSDIR)/include/db48"
++ -I"$(DB4DIR)/include" \
++ -I"$(OPENSSLDIR)/include"
+
+ LIBPATHS= \
+ -L"$(DEPSDIR)/lib" \
+- -L"$(DEPSDIR)/lib/db48"
++ -L"$(DB4DIR)/lib" \
++ -L"$(OPENSSLDIR)/lib"
+
+ USE_UPNP:=1
+ USE_IPV6:=1
+@@ -31,13 +35,13 @@ ifdef STATIC
+ TESTLIBS += \
+ $(DEPSDIR)/lib/libboost_unit_test_framework-mt.a
+ LIBS += \
+- $(DEPSDIR)/lib/db48/libdb_cxx-4.8.a \
++ $(DB4DIR)/lib/libdb_cxx-4.8.a \
+ $(DEPSDIR)/lib/libboost_system-mt.a \
+ $(DEPSDIR)/lib/libboost_filesystem-mt.a \
+ $(DEPSDIR)/lib/libboost_program_options-mt.a \
+ $(DEPSDIR)/lib/libboost_thread-mt.a \
+- $(DEPSDIR)/lib/libssl.a \
+- $(DEPSDIR)/lib/libcrypto.a \
++ $(OPENSSLDIR)/lib/libssl.a \
++ $(OPENSSLDIR)/lib/libcrypto.a \
+ -lz
+ else
+ TESTLIBS += \
diff --git a/doc/build-osx.md b/doc/build-osx.md
new file mode 100644
index 0000000000..1ed593d5eb
--- /dev/null
+++ b/doc/build-osx.md
@@ -0,0 +1,173 @@
+Mac OS X bitcoind build instructions
+====================================
+
+Authors
+-------
+
+* Laszlo Hanyecz <solar@heliacal.net>
+* Douglas Huff <dhuff@jrbobdobbs.org>
+* Colin Dean <cad@cad.cx>
+* Gavin Andresen <gavinandresen@gmail.com>
+
+License
+-------
+
+Copyright (c) 2009-2012 Bitcoin Developers
+
+Distributed under the MIT/X11 software license, see the accompanying
+file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+This product includes software developed by the OpenSSL Project for use in
+the OpenSSL Toolkit (http://www.openssl.org/).
+
+This product includes cryptographic software written by
+Eric Young (eay@cryptsoft.com) and UPnP software written by Thomas Bernard.
+
+Notes
+-----
+
+See `doc/readme-qt.rst` for instructions on building Bitcoin-Qt, the
+graphical user interface.
+
+Tested on OS X 10.5 through 10.8 on Intel processors only. PPC is not
+supported because it is big-endian.
+
+All of the commands should be executed in a Terminal application. The
+built-in one is located in `/Applications/Utilities`.
+
+Preparation
+-----------
+
+You need to install XCode with all the options checked so that the compiler
+and everything is available in /usr not just /Developer. XCode should be
+available on your OS X installation media, but if not, you can get the
+current version from https://developer.apple.com/xcode/. If you install
+Xcode 4.3 or later, you'll need to install its command line tools. This can
+be done in `Xcode > Preferences > Downloads > Components` and generally must
+be re-done or updated every time Xcode is updated.
+
+There's an assumption that you already have `git` installed, as well. If
+not, it's the path of least resistance to install Github for Mac
+(OS X 10.7+) or
+[Git for OS X](https://code.google.com/p/git-osx-installer/). It is also
+available via Homebrew or MacPorts.
+
+You will also need to install [Homebrew](http://mxcl.github.com/homebrew/)
+or [MacPorts](http://www.macports.org/) in order to install library
+dependencies. It's largely a religious decision which to choose, but, as of
+December 2012, MacPorts is a little easier because you can just install the
+dependencies immediately - no other work required. If you're unsure, read
+the instructions through first in order to assess what you want to do.
+Homebrew is a little more popular among those newer to OS X.
+
+The installation of the actual dependencies is covered in the Instructions
+sections below.
+
+Instructions: MacPorts
+----------------------
+
+### Install dependencies
+
+Installing the dependencies using MacPorts is very straightforward.
+
+ sudo port install boost db48@+no_java openssl miniupnpc
+
+### Building `bitcoind`
+
+1. Clone the github tree to get the source code and go into the directory.
+
+ git clone git@github.com:bitcoin/bitcoin.git bitcoin
+ cd bitcoin
+
+2. Build bitcoind:
+
+ cd src
+ make -f makefile.osx
+
+3. It is a good idea to build and run the unit tests, too:
+
+ make -f makefile.osx test
+
+Instructions: HomeBrew
+----------------------
+
+#### Install dependencies using Homebrew
+
+ brew install boost miniupnpc openssl berkeley-db4
+
+### Building `bitcoind`
+
+1. Clone the github tree to get the source code and go into the directory.
+
+ git clone git@github.com:bitcoin/bitcoin.git bitcoin
+ cd bitcoin
+
+2. Modify source in order to pick up the `openssl` library.
+
+ Edit `makefile.osx` to account for library location differences. There's a
+ diff in `contrib/homebrew/makefile.osx.patch` that shows what you need to
+ change, or you can just patch by doing
+
+ patch -p1 < contrib/homebrew/makefile.osx.patch
+
+3. Build bitcoind:
+
+ cd src
+ make -f makefile.osx
+
+4. It is a good idea to build and run the unit tests, too:
+
+ make -f makefile.osx test
+
+Creating a release build
+------------------------
+
+A bitcoind binary is not included in the Bitcoin-Qt.app bundle. You can ignore
+this section if you are building `bitcoind` for your own use.
+
+If you are building `bitcoind` for others, your build machine should be set up
+as follows for maximum compatibility:
+
+All dependencies should be compiled with these flags:
+
+ -mmacosx-version-min=10.5 -arch i386 -isysroot /Developer/SDKs/MacOSX10.5.sdk
+
+For MacPorts, that means editing your macports.conf and setting
+`macosx_deployment_target` and `build_arch`:
+
+ macosx_deployment_target=10.5
+ build_arch=i386
+
+... and then uninstalling and re-installing, or simply rebuilding, all ports.
+
+As of December 2012, the `boost` port does not obey `macosx_deployment_target`.
+Download `http://gavinandresen-bitcoin.s3.amazonaws.com/boost_macports_fix.zip`
+for a fix. Some ports also seem to obey either `build_arch` or
+`macosx_deployment_target`, but not both at the same time. For example, building
+on an OS X 10.6 64-bit machine fails. Official release builds of Bitcoin-Qt are
+compiled on an OS X 10.6 32-bit machine to workaround that problem.
+
+Once dependencies are compiled, creating `Bitcoin-Qt.app` is easy:
+
+ make -f Makefile.osx RELEASE=1
+
+Running
+-------
+
+It's now available at `./bitcoind`, provided that you are still in the `src`
+directory. We have to first create the RPC configuration file, though.
+
+Run `./bitcoind` to get the filename where it should be put, or just try these
+commands:
+
+ echo -e "rpcuser=bitcoinrpc\nrpcpassword=$(xxd -l 16 -p /dev/urandom)" > "/Users/${USER}/Library/Application Support/Bitcoin/bitcoin.conf"
+ chmod 600 "/Users/${USER}/Library/Application Support/Bitcoin/bitcoin.conf"
+
+When next you run it, it will start downloading the blockchain, but it won't
+output anything while it's doing this. This process may take several hours.
+
+Other commands:
+
+ ./bitcoind --help # for a list of command-line options.
+ ./bitcoind -daemon # to start the bitcoin daemon.
+ ./bitcoind help # When the daemon is running, to get a list of RPC commands
diff --git a/doc/build-osx.txt b/doc/build-osx.txt
deleted file mode 100644
index fd878043c0..0000000000
--- a/doc/build-osx.txt
+++ /dev/null
@@ -1,54 +0,0 @@
-Copyright (c) 2009-2012 Bitcoin Developers
-Distributed under the MIT/X11 software license, see the accompanying
-file COPYING or http://www.opensource.org/licenses/mit-license.php.
-This product includes software developed by the OpenSSL Project for use in
-the OpenSSL Toolkit (http://www.openssl.org/). This product includes
-cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP
-software written by Thomas Bernard.
-
-
-Mac OS X bitcoind build instructions
-Laszlo Hanyecz <solar@heliacal.net>
-Douglas Huff <dhuff@jrbobdobbs.org>
-
-
-See readme-qt.rst for instructions on building Bitcoin-Qt, the
-graphical user interface.
-
-Tested on 10.5, 10.6 and 10.7 intel. PPC is not supported because it's big-endian.
-
-All of the commands should be executed in Terminal.app.. it's in
-/Applications/Utilities
-
-You need to install XCode with all the options checked so that the compiler and
-everything is available in /usr not just /Developer. XCode should be available on your OS X
-install DVD, but if not, you can get the current version from https://developer.apple.com/xcode/
-
-
-1. Clone the github tree to get the source code:
-
-git clone git@github.com:bitcoin/bitcoin.git bitcoin
-
-2. Download and install MacPorts from http://www.macports.org/
-
-2a. (for 10.7 Lion)
- Edit /opt/local/etc/macports/macports.conf and uncomment "build_arch i386"
-
-3. Install dependencies from MacPorts
-
-sudo port install boost db48 openssl miniupnpc
-
-Optionally install qrencode (and set USE_QRCODE=1):
-sudo port install qrencode
-
-4. Now you should be able to build bitcoind:
-
-cd bitcoin/src
-make -f makefile.osx
-
-Run:
- ./bitcoind --help # for a list of command-line options.
-Run
- ./bitcoind -daemon # to start the bitcoin daemon.
-Run
- ./bitcoind help # When the daemon is running, to get a list of RPC commands
diff --git a/share/qt/Info.plist b/share/qt/Info.plist
new file mode 100644
index 0000000000..58b2152e9f
--- /dev/null
+++ b/share/qt/Info.plist
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd">
+<plist version="0.9">
+<dict>
+ <key>CFBundleIconFile</key>
+ <string>bitcoin.icns</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleGetInfoString</key>
+ <string>Bitcoin-Qt</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleExecutable</key>
+ <string>Bitcoin-Qt</string>
+ <key>CFBundleIdentifier</key>
+ <string>org.bitcoinfoundation.Bitcoin-Qt</string>
+ <key>CFBundleURLTypes</key>
+ <array>
+ <dict>
+ <key>CFBundleTypeRole</key>
+ <string>Editor</string>
+ <key>CFBundleURLName</key>
+ <string>org.bitcoinfoundation.BitcoinPayment</string>
+ <key>CFBundleURLSchemes</key>
+ <array>
+ <string>bitcoin</string>
+ </array>
+ </dict>
+ </array>
+</dict>
+</plist>
diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp
index 7751e4c8b6..230a248422 100644
--- a/src/bitcoinrpc.cpp
+++ b/src/bitcoinrpc.cpp
@@ -246,7 +246,7 @@ static const CRPCCommand vRPCCommands[] =
{ "getblocktemplate", &getblocktemplate, true, false },
{ "submitblock", &submitblock, false, false },
{ "listsinceblock", &listsinceblock, false, false },
- { "dumpprivkey", &dumpprivkey, false, false },
+ { "dumpprivkey", &dumpprivkey, true, false },
{ "importprivkey", &importprivkey, false, false },
{ "listunspent", &listunspent, false, false },
{ "getrawtransaction", &getrawtransaction, false, false },
diff --git a/src/checkpoints.cpp b/src/checkpoints.cpp
index e2c420edd7..9b11f0b351 100644
--- a/src/checkpoints.cpp
+++ b/src/checkpoints.cpp
@@ -14,13 +14,25 @@ namespace Checkpoints
{
typedef std::map<int, uint256> MapCheckpoints;
- //
+ // How many times we expect transactions after the last checkpoint to
+ // be slower. This number is conservative. On multi-core CPUs with
+ // parallel signature checking enabled, this number is way too high.
+ // We prefer a progressbar that's faster at the end than the other
+ // way around, though.
+ static const double fSigcheckVerificationFactor = 15.0;
+
+ struct CCheckpointData {
+ const MapCheckpoints *mapCheckpoints;
+ int64 nTimeLastCheckpoint;
+ int64 nTransactionsLastCheckpoint;
+ double fTransactionsPerDay;
+ };
+
// What makes a good checkpoint block?
// + Is surrounded by blocks with reasonable timestamps
// (no blocks before with a timestamp after, none after with
// timestamp before)
// + Contains no strange transactions
- //
static MapCheckpoints mapCheckpoints =
boost::assign::map_list_of
( 11111, uint256("0x0000000069e244f73d78e8fd29ba2fd2ed618bd6fa2ee92559f542fdb26e7c1d"))
@@ -33,30 +45,81 @@ namespace Checkpoints
(210000, uint256("0x000000000000048b95347e83192f69cf0366076336c639f9b7228e9ba171342e"))
(216116, uint256("0x00000000000001b4f4b433e81ee46494af945cf96014816a4e2370f11b23df4e"))
;
+ static const CCheckpointData data = {
+ &mapCheckpoints,
+ 1357902690, // * UNIX timestamp of last checkpoint block
+ 11011160, // * total number of transactions between genesis and last checkpoint
+ // (the tx=... number in the SetBestChain debug.log lines)
+ 50000.0 // * estimated number of transactions per day after checkpoint
+ };
- static MapCheckpoints mapCheckpointsTestnet =
+ static MapCheckpoints mapCheckpointsTestnet =
boost::assign::map_list_of
( 546, uint256("000000002a936ca763904c3c35fce2f3556c559c0214345d31b1bcebf76acb70"))
;
+ static const CCheckpointData dataTestnet = {
+ &mapCheckpointsTestnet,
+ 1338180505,
+ 16341,
+ 300
+ };
+
+ const CCheckpointData &Checkpoints() {
+ if (fTestNet)
+ return dataTestnet;
+ else
+ return data;
+ }
bool CheckBlock(int nHeight, const uint256& hash)
{
if (!GetBoolArg("-checkpoints", true))
return true;
- MapCheckpoints& checkpoints = (fTestNet ? mapCheckpointsTestnet : mapCheckpoints);
+ const MapCheckpoints& checkpoints = *Checkpoints().mapCheckpoints;
MapCheckpoints::const_iterator i = checkpoints.find(nHeight);
if (i == checkpoints.end()) return true;
return hash == i->second;
}
+ // Guess how far we are in the verification process at the given block index
+ double GuessVerificationProgress(CBlockIndex *pindex) {
+ if (pindex==NULL)
+ return 0.0;
+
+ int64 nNow = time(NULL);
+
+ double fWorkBefore = 0.0; // Amount of work done before pindex
+ double fWorkAfter = 0.0; // Amount of work left after pindex (estimated)
+ // Work is defined as: 1.0 per transaction before the last checkoint, and
+ // fSigcheckVerificationFactor per transaction after.
+
+ const CCheckpointData &data = Checkpoints();
+
+ if (pindex->nChainTx <= data.nTransactionsLastCheckpoint) {
+ double nCheapBefore = pindex->nChainTx;
+ double nCheapAfter = data.nTransactionsLastCheckpoint - pindex->nChainTx;
+ double nExpensiveAfter = (nNow - data.nTimeLastCheckpoint)/86400.0*data.fTransactionsPerDay;
+ fWorkBefore = nCheapBefore;
+ fWorkAfter = nCheapAfter + nExpensiveAfter*fSigcheckVerificationFactor;
+ } else {
+ double nCheapBefore = data.nTransactionsLastCheckpoint;
+ double nExpensiveBefore = pindex->nChainTx - data.nTransactionsLastCheckpoint;
+ double nExpensiveAfter = (nNow - pindex->nTime)/86400.0*data.fTransactionsPerDay;
+ fWorkBefore = nCheapBefore + nExpensiveBefore*fSigcheckVerificationFactor;
+ fWorkAfter = nExpensiveAfter*fSigcheckVerificationFactor;
+ }
+
+ return fWorkBefore / (fWorkBefore + fWorkAfter);
+ }
+
int GetTotalBlocksEstimate()
{
if (!GetBoolArg("-checkpoints", true))
return 0;
- MapCheckpoints& checkpoints = (fTestNet ? mapCheckpointsTestnet : mapCheckpoints);
+ const MapCheckpoints& checkpoints = *Checkpoints().mapCheckpoints;
return checkpoints.rbegin()->first;
}
@@ -66,7 +129,7 @@ namespace Checkpoints
if (!GetBoolArg("-checkpoints", true))
return NULL;
- MapCheckpoints& checkpoints = (fTestNet ? mapCheckpointsTestnet : mapCheckpoints);
+ const MapCheckpoints& checkpoints = *Checkpoints().mapCheckpoints;
BOOST_REVERSE_FOREACH(const MapCheckpoints::value_type& i, checkpoints)
{
diff --git a/src/checkpoints.h b/src/checkpoints.h
index 240bd12fde..3d56885556 100644
--- a/src/checkpoints.h
+++ b/src/checkpoints.h
@@ -22,6 +22,8 @@ namespace Checkpoints
// Returns last CBlockIndex* in mapBlockIndex that is a checkpoint
CBlockIndex* GetLastCheckpoint(const std::map<uint256, CBlockIndex*>& mapBlockIndex);
+
+ double GuessVerificationProgress(CBlockIndex *pindex);
}
#endif
diff --git a/src/init.cpp b/src/init.cpp
index cf49831b6b..5b8436651a 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -300,6 +300,7 @@ std::string HelpMessage()
" -rpcallowip=<ip> " + _("Allow JSON-RPC connections from specified IP address") + "\n" +
" -rpcconnect=<ip> " + _("Send commands to node running on <ip> (default: 127.0.0.1)") + "\n" +
" -blocknotify=<cmd> " + _("Execute command when the best block changes (%s in cmd is replaced by block hash)") + "\n" +
+ " -walletnotify=<cmd> " + _("Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)") + "\n" +
" -upgradewallet " + _("Upgrade wallet to latest format") + "\n" +
" -keypool=<n> " + _("Set key pool size to <n> (default: 100)") + "\n" +
" -rescan " + _("Rescan the block chain for missing wallet transactions") + "\n" +
@@ -825,7 +826,7 @@ bool AppInit2()
break;
}
- uiInterface.InitMessage(_("Verifying block database integrity..."));
+ uiInterface.InitMessage(_("Verifying database..."));
if (!VerifyDB()) {
strLoadError = _("Corrupted block database detected");
break;
diff --git a/src/main.cpp b/src/main.cpp
index 9fde08b2c8..9a06dbf13e 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -162,9 +162,9 @@ void static ResendWalletTransactions()
// CCoinsView implementations
//
-bool CCoinsView::GetCoins(uint256 txid, CCoins &coins) { return false; }
-bool CCoinsView::SetCoins(uint256 txid, const CCoins &coins) { return false; }
-bool CCoinsView::HaveCoins(uint256 txid) { return false; }
+bool CCoinsView::GetCoins(const uint256 &txid, CCoins &coins) { return false; }
+bool CCoinsView::SetCoins(const uint256 &txid, const CCoins &coins) { return false; }
+bool CCoinsView::HaveCoins(const uint256 &txid) { return false; }
CBlockIndex *CCoinsView::GetBestBlock() { return NULL; }
bool CCoinsView::SetBestBlock(CBlockIndex *pindex) { return false; }
bool CCoinsView::BatchWrite(const std::map<uint256, CCoins> &mapCoins, CBlockIndex *pindex) { return false; }
@@ -172,9 +172,9 @@ bool CCoinsView::GetStats(CCoinsStats &stats) { return false; }
CCoinsViewBacked::CCoinsViewBacked(CCoinsView &viewIn) : base(&viewIn) { }
-bool CCoinsViewBacked::GetCoins(uint256 txid, CCoins &coins) { return base->GetCoins(txid, coins); }
-bool CCoinsViewBacked::SetCoins(uint256 txid, const CCoins &coins) { return base->SetCoins(txid, coins); }
-bool CCoinsViewBacked::HaveCoins(uint256 txid) { return base->HaveCoins(txid); }
+bool CCoinsViewBacked::GetCoins(const uint256 &txid, CCoins &coins) { return base->GetCoins(txid, coins); }
+bool CCoinsViewBacked::SetCoins(const uint256 &txid, const CCoins &coins) { return base->SetCoins(txid, coins); }
+bool CCoinsViewBacked::HaveCoins(const uint256 &txid) { return base->HaveCoins(txid); }
CBlockIndex *CCoinsViewBacked::GetBestBlock() { return base->GetBestBlock(); }
bool CCoinsViewBacked::SetBestBlock(CBlockIndex *pindex) { return base->SetBestBlock(pindex); }
void CCoinsViewBacked::SetBackend(CCoinsView &viewIn) { base = &viewIn; }
@@ -183,7 +183,7 @@ bool CCoinsViewBacked::GetStats(CCoinsStats &stats) { return base->GetStats(stat
CCoinsViewCache::CCoinsViewCache(CCoinsView &baseIn, bool fDummy) : CCoinsViewBacked(baseIn), pindexTip(NULL) { }
-bool CCoinsViewCache::GetCoins(uint256 txid, CCoins &coins) {
+bool CCoinsViewCache::GetCoins(const uint256 &txid, CCoins &coins) {
if (cacheCoins.count(txid)) {
coins = cacheCoins[txid];
return true;
@@ -195,29 +195,30 @@ bool CCoinsViewCache::GetCoins(uint256 txid, CCoins &coins) {
return false;
}
-std::map<uint256,CCoins>::iterator CCoinsViewCache::FetchCoins(uint256 txid) {
- std::map<uint256,CCoins>::iterator it = cacheCoins.find(txid);
- if (it != cacheCoins.end())
+std::map<uint256,CCoins>::iterator CCoinsViewCache::FetchCoins(const uint256 &txid) {
+ std::map<uint256,CCoins>::iterator it = cacheCoins.lower_bound(txid);
+ if (it != cacheCoins.end() && it->first == txid)
return it;
CCoins tmp;
if (!base->GetCoins(txid,tmp))
- return it;
- std::pair<std::map<uint256,CCoins>::iterator,bool> ret = cacheCoins.insert(std::make_pair(txid, tmp));
- return ret.first;
+ return cacheCoins.end();
+ std::map<uint256,CCoins>::iterator ret = cacheCoins.insert(it, std::make_pair(txid, CCoins()));
+ tmp.swap(ret->second);
+ return ret;
}
-CCoins &CCoinsViewCache::GetCoins(uint256 txid) {
+CCoins &CCoinsViewCache::GetCoins(const uint256 &txid) {
std::map<uint256,CCoins>::iterator it = FetchCoins(txid);
assert(it != cacheCoins.end());
return it->second;
}
-bool CCoinsViewCache::SetCoins(uint256 txid, const CCoins &coins) {
+bool CCoinsViewCache::SetCoins(const uint256 &txid, const CCoins &coins) {
cacheCoins[txid] = coins;
return true;
}
-bool CCoinsViewCache::HaveCoins(uint256 txid) {
+bool CCoinsViewCache::HaveCoins(const uint256 &txid) {
return FetchCoins(txid) != cacheCoins.end();
}
@@ -254,7 +255,7 @@ unsigned int CCoinsViewCache::GetCacheSize() {
It does not check for spendings by memory pool transactions. */
CCoinsViewMemPool::CCoinsViewMemPool(CCoinsView &baseIn, CTxMemPool &mempoolIn) : CCoinsViewBacked(baseIn), mempool(mempoolIn) { }
-bool CCoinsViewMemPool::GetCoins(uint256 txid, CCoins &coins) {
+bool CCoinsViewMemPool::GetCoins(const uint256 &txid, CCoins &coins) {
if (base->GetCoins(txid, coins))
return true;
if (mempool.exists(txid)) {
@@ -265,7 +266,7 @@ bool CCoinsViewMemPool::GetCoins(uint256 txid, CCoins &coins) {
return false;
}
-bool CCoinsViewMemPool::HaveCoins(uint256 txid) {
+bool CCoinsViewMemPool::HaveCoins(const uint256 &txid) {
return mempool.exists(txid) || base->HaveCoins(txid);
}
@@ -1532,7 +1533,7 @@ bool CBlock::DisconnectBlock(CValidationState &state, CBlockIndex *pindex, CCoin
}
}
-void static FlushBlockFile()
+void static FlushBlockFile(bool fFinalize = false)
{
LOCK(cs_LastBlockFile);
@@ -1540,12 +1541,16 @@ void static FlushBlockFile()
FILE *fileOld = OpenBlockFile(posOld);
if (fileOld) {
+ if (fFinalize)
+ TruncateFile(fileOld, infoLastBlockFile.nSize);
FileCommit(fileOld);
fclose(fileOld);
}
fileOld = OpenUndoFile(posOld);
if (fileOld) {
+ if (fFinalize)
+ TruncateFile(fileOld, infoLastBlockFile.nUndoSize);
FileCommit(fileOld);
fclose(fileOld);
}
@@ -1963,7 +1968,7 @@ bool FindBlockPos(CValidationState &state, CDiskBlockPos &pos, unsigned int nAdd
} else {
while (infoLastBlockFile.nSize + nAddSize >= MAX_BLOCKFILE_SIZE) {
printf("Leaving block file %i: %s\n", nLastBlockFile, infoLastBlockFile.ToString().c_str());
- FlushBlockFile();
+ FlushBlockFile(true);
nLastBlockFile++;
infoLastBlockFile.SetNull();
pblocktree->ReadBlockFileInfo(nLastBlockFile, infoLastBlockFile); // check whether data for the new file somehow already exist; can fail just fine
diff --git a/src/main.h b/src/main.h
index e9601c3a44..43c3051e4c 100644
--- a/src/main.h
+++ b/src/main.h
@@ -908,6 +908,15 @@ public:
void Cleanup() {
while (vout.size() > 0 && vout.back().IsNull())
vout.pop_back();
+ if (vout.empty())
+ std::vector<CTxOut>().swap(vout);
+ }
+
+ void swap(CCoins &to) {
+ std::swap(to.fCoinBase, fCoinBase);
+ to.vout.swap(vout);
+ std::swap(to.nHeight, nHeight);
+ std::swap(to.nVersion, nVersion);
}
// equality test
@@ -2108,14 +2117,14 @@ class CCoinsView
{
public:
// Retrieve the CCoins (unspent transaction outputs) for a given txid
- virtual bool GetCoins(uint256 txid, CCoins &coins);
+ virtual bool GetCoins(const uint256 &txid, CCoins &coins);
// Modify the CCoins for a given txid
- virtual bool SetCoins(uint256 txid, const CCoins &coins);
+ virtual bool SetCoins(const uint256 &txid, const CCoins &coins);
// Just check whether we have data for a given txid.
// This may (but cannot always) return true for fully spent transactions
- virtual bool HaveCoins(uint256 txid);
+ virtual bool HaveCoins(const uint256 &txid);
// Retrieve the block index whose state this CCoinsView currently represents
virtual CBlockIndex *GetBestBlock();
@@ -2141,9 +2150,9 @@ protected:
public:
CCoinsViewBacked(CCoinsView &viewIn);
- bool GetCoins(uint256 txid, CCoins &coins);
- bool SetCoins(uint256 txid, const CCoins &coins);
- bool HaveCoins(uint256 txid);
+ bool GetCoins(const uint256 &txid, CCoins &coins);
+ bool SetCoins(const uint256 &txid, const CCoins &coins);
+ bool HaveCoins(const uint256 &txid);
CBlockIndex *GetBestBlock();
bool SetBestBlock(CBlockIndex *pindex);
void SetBackend(CCoinsView &viewIn);
@@ -2162,9 +2171,9 @@ public:
CCoinsViewCache(CCoinsView &baseIn, bool fDummy = false);
// Standard CCoinsView methods
- bool GetCoins(uint256 txid, CCoins &coins);
- bool SetCoins(uint256 txid, const CCoins &coins);
- bool HaveCoins(uint256 txid);
+ bool GetCoins(const uint256 &txid, CCoins &coins);
+ bool SetCoins(const uint256 &txid, const CCoins &coins);
+ bool HaveCoins(const uint256 &txid);
CBlockIndex *GetBestBlock();
bool SetBestBlock(CBlockIndex *pindex);
bool BatchWrite(const std::map<uint256, CCoins> &mapCoins, CBlockIndex *pindex);
@@ -2172,7 +2181,7 @@ public:
// Return a modifiable reference to a CCoins. Check HaveCoins first.
// Many methods explicitly require a CCoinsViewCache because of this method, to reduce
// copying.
- CCoins &GetCoins(uint256 txid);
+ CCoins &GetCoins(const uint256 &txid);
// Push the modifications applied to this cache to its base.
// Failure to call this method before destruction will cause the changes to be forgotten.
@@ -2182,7 +2191,7 @@ public:
unsigned int GetCacheSize();
private:
- std::map<uint256,CCoins>::iterator FetchCoins(uint256 txid);
+ std::map<uint256,CCoins>::iterator FetchCoins(const uint256 &txid);
};
/** CCoinsView that brings transactions from a memorypool into view.
@@ -2194,8 +2203,8 @@ protected:
public:
CCoinsViewMemPool(CCoinsView &baseIn, CTxMemPool &mempoolIn);
- bool GetCoins(uint256 txid, CCoins &coins);
- bool HaveCoins(uint256 txid);
+ bool GetCoins(const uint256 &txid, CCoins &coins);
+ bool HaveCoins(const uint256 &txid);
};
/** Global variable that points to the active CCoinsView (protected by cs_main) */
diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp
index afd8d71a0e..75e9b965b1 100644
--- a/src/qt/bitcoin.cpp
+++ b/src/qt/bitcoin.cpp
@@ -9,12 +9,13 @@
#include "guiconstants.h"
#include "init.h"
#include "ui_interface.h"
-#include "qtipcserver.h"
+#include "paymentserver.h"
#include <QApplication>
#include <QMessageBox>
#include <QTextCodec>
#include <QLocale>
+#include <QTimer>
#include <QTranslator>
#include <QSplashScreen>
#include <QLibraryInfo>
@@ -74,15 +75,6 @@ static bool ThreadSafeAskFee(int64 nFeeRequired)
return payFee;
}
-static void ThreadSafeHandleURI(const std::string& strURI)
-{
- if(!guiref)
- return;
-
- QMetaObject::invokeMethod(guiref, "handleURI", GUIUtil::blockingGUIThreadConnection(),
- Q_ARG(QString, QString::fromStdString(strURI)));
-}
-
static void InitMessage(const std::string &message)
{
if(splashref)
@@ -121,14 +113,6 @@ int main(int argc, char *argv[])
// Command-line options take precedence:
ParseParameters(argc, argv);
- if(GetBoolArg("-testnet")) // Separate message queue name for testnet
- strBitcoinURIQueueName = BITCOINURI_QUEUE_NAME_TESTNET;
- else
- strBitcoinURIQueueName = BITCOINURI_QUEUE_NAME_MAINNET;
-
- // Do this early as we don't want to bother initializing if we are just calling IPC
- ipcScanRelay(argc, argv);
-
// Internal string conversion is all UTF-8
QTextCodec::setCodecForTr(QTextCodec::codecForName("UTF-8"));
QTextCodec::setCodecForCStrings(QTextCodec::codecForTr());
@@ -136,6 +120,12 @@ int main(int argc, char *argv[])
Q_INIT_RESOURCE(bitcoin);
QApplication app(argc, argv);
+ // Do this early as we don't want to bother initializing if we are just calling IPC
+ // ... but do it after creating app, so QCoreApplication::arguments is initialized:
+ if (PaymentServer::ipcSendCommandLine())
+ exit(0);
+ PaymentServer* paymentServer = new PaymentServer(&app);
+
// Install global event filter that makes sure that long tooltips can be word-wrapped
app.installEventFilter(new GUIUtil::ToolTipToRichTextFilter(TOOLTIP_WRAP_THRESHOLD, &app));
@@ -192,7 +182,6 @@ int main(int argc, char *argv[])
// 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);
@@ -253,8 +242,10 @@ int main(int argc, char *argv[])
window.show();
}
- // Place this here as guiref has to be defined if we don't want to lose URIs
- ipcInit(argc, argv);
+ // Now that initialization/startup is done, process any command-line
+ // bitcoin: URIs
+ QObject::connect(paymentServer, SIGNAL(receivedURI(QString)), &window, SLOT(handleURI(QString)));
+ QTimer::singleShot(100, paymentServer, SLOT(uiReady()));
app.exec();
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index d884701883..f1bf5f5880 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -67,7 +67,8 @@ BitcoinGUI::BitcoinGUI(QWidget *parent):
aboutQtAction(0),
trayIcon(0),
notificator(0),
- rpcConsole(0)
+ rpcConsole(0),
+ prevBlocks(0)
{
resize(850, 550);
setWindowTitle(tr("Bitcoin") + " - " + tr("Wallet"));
@@ -527,52 +528,17 @@ void BitcoinGUI::setNumBlocks(int count, int nTotalBlocks)
importText = tr("Reindexing blocks on disk...");
}
- if(count < nTotalBlocks)
- {
- int nRemainingBlocks = nTotalBlocks - count;
- float nPercentageDone = count / (nTotalBlocks * 0.01f);
-
- progressBarLabel->setText(importText);
- progressBarLabel->setVisible(true);
- progressBar->setFormat(tr("~%n block(s) remaining", "", nRemainingBlocks));
- progressBar->setMaximum(nTotalBlocks);
- progressBar->setValue(count);
- progressBar->setVisible(true);
-
- tooltip = tr("Processed %1 of %2 blocks of transaction history (%3% done).").arg(count).arg(nTotalBlocks).arg(nPercentageDone, 0, 'f', 2);
- }
- else
- {
- progressBarLabel->setVisible(false);
-
- progressBar->setVisible(false);
- tooltip = tr("Processed %1 blocks of transaction history.").arg(count);
- }
-
QDateTime lastBlockDate = clientModel->getLastBlockDate();
- int secs = lastBlockDate.secsTo(QDateTime::currentDateTime());
- QString text;
+ QDateTime currentDate = QDateTime::currentDateTime();
+ int secs = lastBlockDate.secsTo(currentDate);
- // Represent time from last generated block in human readable text
- if(secs <= 0)
- {
- // Fully up to date. Leave text empty.
- }
- else if(secs < 60)
- {
- text = tr("%n second(s) ago","",secs);
- }
- else if(secs < 60*60)
- {
- text = tr("%n minute(s) ago","",secs/60);
- }
- else if(secs < 24*60*60)
+ if(count < nTotalBlocks)
{
- text = tr("%n hour(s) ago","",secs/(60*60));
+ tooltip = tr("Processed %1 of %2 (estimated) blocks of transaction history.").arg(count).arg(nTotalBlocks);
}
else
{
- text = tr("%n day(s) ago","",secs/(60*60*24));
+ tooltip = tr("Processed %1 blocks of transaction history.").arg(count);
}
// Set icon state: spinning if catching up, tick otherwise
@@ -582,20 +548,46 @@ void BitcoinGUI::setNumBlocks(int count, int nTotalBlocks)
labelBlocksIcon->setPixmap(QIcon(":/icons/synced").pixmap(STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE));
overviewPage->showOutOfSyncWarning(false);
+
+ progressBarLabel->setVisible(false);
+ progressBar->setVisible(false);
}
else
{
+ // Represent time from last generated block in human readable text
+ QString timeBehindText;
+ if(secs < 48*60*60)
+ {
+ timeBehindText = tr("%n hour(s)","",secs/(60*60));
+ }
+ else if(secs < 14*24*60*60)
+ {
+ timeBehindText = tr("%n day(s)","",secs/(24*60*60));
+ }
+ else
+ {
+ timeBehindText = tr("%n week(s)","",secs/(7*24*60*60));
+ }
+
+ progressBarLabel->setText(importText);
+ progressBarLabel->setVisible(true);
+ progressBar->setFormat(tr("%1 behind").arg(timeBehindText));
+ progressBar->setMaximum(1000000000);
+ progressBar->setValue(clientModel->getVerificationProgress() * 1000000000.0 + 0.5);
+ progressBar->setVisible(true);
+
tooltip = tr("Catching up...") + QString("<br>") + tooltip;
labelBlocksIcon->setMovie(syncIconMovie);
- syncIconMovie->start();
+ if(count != prevBlocks)
+ syncIconMovie->jumpToNextFrame();
+ prevBlocks = count;
overviewPage->showOutOfSyncWarning(true);
- }
- if(!text.isEmpty())
- {
tooltip += QString("<br>");
- tooltip += tr("Last received block was generated %1.").arg(text);
+ tooltip += tr("Last received block was generated %1 ago.").arg(timeBehindText);
+ tooltip += QString("<br>");
+ tooltip += tr("Transactions after this will not yet be visible.");
}
// Don't word-wrap this (fixed-width) tooltip
diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h
index c684fcf249..8ce0335bcd 100644
--- a/src/qt/bitcoingui.h
+++ b/src/qt/bitcoingui.h
@@ -98,6 +98,8 @@ private:
RPCConsole *rpcConsole;
QMovie *syncIconMovie;
+ /** Keep track of previous number of blocks, to detect progress */
+ int prevBlocks;
/** Create the main UI actions. */
void createActions();
diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp
index 084ad12a56..858fbe241f 100644
--- a/src/qt/clientmodel.cpp
+++ b/src/qt/clientmodel.cpp
@@ -6,6 +6,7 @@
#include "alert.h"
#include "main.h"
+#include "checkpoints.h"
#include "ui_interface.h"
#include <QDateTime>
@@ -54,6 +55,11 @@ QDateTime ClientModel::getLastBlockDate() const
return QDateTime::fromTime_t(1231006505); // Genesis block's time
}
+double ClientModel::getVerificationProgress() const
+{
+ return Checkpoints::GuessVerificationProgress(pindexBest);
+}
+
void ClientModel::updateTimer()
{
// Some quantities (such as number of blocks) change so fast that we don't want to be notified for each change.
diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h
index 1afccb7859..a3fe92048c 100644
--- a/src/qt/clientmodel.h
+++ b/src/qt/clientmodel.h
@@ -34,6 +34,7 @@ public:
int getNumBlocks() const;
int getNumBlocksAtStartup();
+ double getVerificationProgress() const;
QDateTime getLastBlockDate() const;
//! Return true if client connected to testnet
diff --git a/src/qt/guiconstants.h b/src/qt/guiconstants.h
index 405ba396b7..92417834ec 100644
--- a/src/qt/guiconstants.h
+++ b/src/qt/guiconstants.h
@@ -2,7 +2,7 @@
#define GUICONSTANTS_H
/* Milliseconds between model updates */
-static const int MODEL_UPDATE_DELAY = 500;
+static const int MODEL_UPDATE_DELAY = 250;
/* AskPassphraseDialog -- Maximum passphrase length */
static const int MAX_PASSPHRASE_SIZE = 1024;
diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp
new file mode 100644
index 0000000000..05f2ac10e4
--- /dev/null
+++ b/src/qt/paymentserver.cpp
@@ -0,0 +1,159 @@
+// Copyright (c) 2009-2012 The Bitcoin developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include "paymentserver.h"
+#include "guiconstants.h"
+#include "ui_interface.h"
+#include "util.h"
+
+#include <QApplication>
+#include <QByteArray>
+#include <QCoreApplication>
+#include <QDataStream>
+#include <QDebug>
+#include <QFileOpenEvent>
+#include <QHash>
+#include <QLocalServer>
+#include <QLocalSocket>
+#include <QStringList>
+#include <QUrl>
+
+using namespace boost;
+
+const int BITCOIN_IPC_CONNECT_TIMEOUT = 1000; // milliseconds
+const QString BITCOIN_IPC_PREFIX("bitcoin:");
+
+//
+// Create a name that is unique for:
+// testnet / non-testnet
+// data directory
+//
+static QString ipcServerName()
+{
+ QString name("BitcoinQt");
+
+ // Append a simple hash of the datadir
+ // Note that GetDataDir(true) returns a different path
+ // for -testnet versus main net
+ QString ddir(GetDataDir(true).string().c_str());
+ name.append(QString::number(qHash(ddir)));
+
+ return name;
+}
+
+//
+// This stores payment requests received before
+// the main GUI window is up and ready to ask the user
+// to send payment.
+//
+static QStringList savedPaymentRequests;
+
+//
+// Sending to the server is done synchronously, at startup.
+// If the server isn't already running, startup continues,
+// and the items in savedPaymentRequest will be handled
+// when uiReady() is called.
+//
+bool PaymentServer::ipcSendCommandLine()
+{
+ bool fResult = false;
+
+ const QStringList& args = QCoreApplication::arguments();
+ for (int i = 1; i < args.size(); i++)
+ {
+ if (!args[i].startsWith(BITCOIN_IPC_PREFIX, Qt::CaseInsensitive))
+ continue;
+ savedPaymentRequests.append(args[i]);
+ }
+
+ foreach (const QString& arg, savedPaymentRequests)
+ {
+ QLocalSocket* socket = new QLocalSocket();
+ socket->connectToServer(ipcServerName(), QIODevice::WriteOnly);
+ if (!socket->waitForConnected(BITCOIN_IPC_CONNECT_TIMEOUT))
+ return false;
+
+ QByteArray block;
+ QDataStream out(&block, QIODevice::WriteOnly);
+ out.setVersion(QDataStream::Qt_4_0);
+ out << arg;
+ out.device()->seek(0);
+ socket->write(block);
+ socket->flush();
+
+ socket->waitForBytesWritten(BITCOIN_IPC_CONNECT_TIMEOUT);
+ socket->disconnectFromServer();
+ delete socket;
+ fResult = true;
+ }
+ return fResult;
+}
+
+PaymentServer::PaymentServer(QApplication* parent) : QObject(parent), saveURIs(true)
+{
+ // Install global event filter to catch QFileOpenEvents on the mac (sent when you click bitcoin: links)
+ parent->installEventFilter(this);
+
+ QString name = ipcServerName();
+
+ // Clean up old socket leftover from a crash:
+ QLocalServer::removeServer(name);
+
+ uriServer = new QLocalServer(this);
+
+ if (!uriServer->listen(name))
+ qDebug() << tr("Cannot start bitcoin: click-to-pay handler");
+ else
+ connect(uriServer, SIGNAL(newConnection()), this, SLOT(handleURIConnection()));
+}
+
+bool PaymentServer::eventFilter(QObject *object, QEvent *event)
+{
+ // clicking on bitcoin: URLs creates FileOpen events on the Mac:
+ if (event->type() == QEvent::FileOpen)
+ {
+ QFileOpenEvent* fileEvent = static_cast<QFileOpenEvent*>(event);
+ if (!fileEvent->url().isEmpty())
+ {
+ if (saveURIs) // Before main window is ready:
+ savedPaymentRequests.append(fileEvent->url().toString());
+ else
+ emit receivedURI(fileEvent->url().toString());
+ return true;
+ }
+ }
+ return false;
+}
+
+void PaymentServer::uiReady()
+{
+ saveURIs = false;
+ foreach (const QString& s, savedPaymentRequests)
+ emit receivedURI(s);
+ savedPaymentRequests.clear();
+}
+
+void PaymentServer::handleURIConnection()
+{
+ QLocalSocket *clientConnection = uriServer->nextPendingConnection();
+
+ while (clientConnection->bytesAvailable() < (int)sizeof(quint32))
+ clientConnection->waitForReadyRead();
+
+ connect(clientConnection, SIGNAL(disconnected()),
+ clientConnection, SLOT(deleteLater()));
+
+ QDataStream in(clientConnection);
+ in.setVersion(QDataStream::Qt_4_0);
+ if (clientConnection->bytesAvailable() < (int)sizeof(quint16)) {
+ return;
+ }
+ QString message;
+ in >> message;
+
+ if (saveURIs)
+ savedPaymentRequests.append(message);
+ else
+ emit receivedURI(message);
+}
diff --git a/src/qt/paymentserver.h b/src/qt/paymentserver.h
new file mode 100644
index 0000000000..cfc48afb38
--- /dev/null
+++ b/src/qt/paymentserver.h
@@ -0,0 +1,66 @@
+#ifndef PAYMENTSERVER_H
+#define PAYMENTSERVER_H
+
+//
+// This class handles payment requests from clicking on
+// bitcoin: URIs
+//
+// This is somewhat tricky, because we have to deal with
+// the situation where the user clicks on a link during
+// startup/initialization, when the splash-screen is up
+// but the main window (and the Send Coins tab) is not.
+//
+// So, the strategy is:
+//
+// Create the server, and register the event handler,
+// when the application is created. Save any URIs
+// received at or during startup in a list.
+//
+// When startup is finished and the main window is
+// show, a signal is sent to slot uiReady(), which
+// emits a receivedURL() signal for any payment
+// requests that happened during startup.
+//
+// After startup, receivedURL() happens as usual.
+//
+// This class has one more feature: a static
+// method that finds URIs passed in the command line
+// and, if a server is running in another process,
+// sends them to the server.
+//
+#include <QObject>
+#include <QString>
+
+class QApplication;
+class QLocalServer;
+
+class PaymentServer : public QObject
+{
+ Q_OBJECT
+private:
+ bool saveURIs;
+ QLocalServer* uriServer;
+
+public:
+ // Returns true if there were URIs on the command line
+ // which were successfully sent to an already-running
+ // process.
+ static bool ipcSendCommandLine();
+
+ PaymentServer(QApplication* parent);
+
+ bool eventFilter(QObject *object, QEvent *event);
+
+signals:
+ void receivedURI(QString);
+
+public slots:
+ // Signal this when the main window's UI is ready
+ // to display payment requests to the user
+ void uiReady();
+
+private slots:
+ void handleURIConnection();
+};
+
+#endif // PAYMENTSERVER_H
diff --git a/src/qt/qtipcserver.cpp b/src/qt/qtipcserver.cpp
deleted file mode 100644
index 2777fab852..0000000000
--- a/src/qt/qtipcserver.cpp
+++ /dev/null
@@ -1,165 +0,0 @@
-// Copyright (c) 2009-2012 The Bitcoin developers
-// Distributed under the MIT/X11 software license, see the accompanying
-// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-#include <boost/version.hpp>
-#if defined(WIN32) && BOOST_VERSION == 104900
-#define BOOST_INTERPROCESS_HAS_WINDOWS_KERNEL_BOOTTIME
-#define BOOST_INTERPROCESS_HAS_KERNEL_BOOTTIME
-#endif
-
-#include "qtipcserver.h"
-#include "guiconstants.h"
-#include "ui_interface.h"
-#include "util.h"
-
-#include <boost/algorithm/string/predicate.hpp>
-#include <boost/date_time/posix_time/posix_time.hpp>
-#include <boost/interprocess/ipc/message_queue.hpp>
-#include <boost/version.hpp>
-
-#if defined(WIN32) && (!defined(BOOST_INTERPROCESS_HAS_WINDOWS_KERNEL_BOOTTIME) || !defined(BOOST_INTERPROCESS_HAS_KERNEL_BOOTTIME) || BOOST_VERSION < 104900)
-#warning Compiling without BOOST_INTERPROCESS_HAS_WINDOWS_KERNEL_BOOTTIME and BOOST_INTERPROCESS_HAS_KERNEL_BOOTTIME uncommented in boost/interprocess/detail/tmp_dir_helpers.hpp or using a boost version before 1.49 may have unintended results see svn.boost.org/trac/boost/ticket/5392
-#endif
-
-using namespace boost;
-using namespace boost::interprocess;
-using namespace boost::posix_time;
-
-// holds Bitcoin-Qt message queue name (initialized in bitcoin.cpp)
-std::string strBitcoinURIQueueName;
-
-#if defined MAC_OSX || defined __FreeBSD__
-// URI handling not implemented on OSX yet
-
-void ipcScanRelay(int argc, char *argv[]) { }
-void ipcInit(int argc, char *argv[]) { }
-
-#else
-
-static void ipcThread2(void* pArg);
-
-static bool ipcScanCmd(int argc, char *argv[], bool fRelay)
-{
- // Check for URI in argv
- bool fSent = false;
- for (int i = 1; i < argc; i++)
- {
- if (boost::algorithm::istarts_with(argv[i], "bitcoin:"))
- {
- const char *strURI = argv[i];
- try {
- boost::interprocess::message_queue mq(boost::interprocess::open_only, strBitcoinURIQueueName.c_str());
- if (mq.try_send(strURI, strlen(strURI), 0))
- fSent = true;
- else if (fRelay)
- break;
- }
- catch (boost::interprocess::interprocess_exception &ex) {
- // don't log the "file not found" exception, because that's normal for
- // the first start of the first instance
- if (ex.get_error_code() != boost::interprocess::not_found_error || !fRelay)
- {
- printf("main() - boost interprocess exception #%d: %s\n", ex.get_error_code(), ex.what());
- break;
- }
- }
- }
- }
- return fSent;
-}
-
-void ipcScanRelay(int argc, char *argv[])
-{
- if (ipcScanCmd(argc, argv, true))
- exit(0);
-}
-
-static void ipcThread(void* pArg)
-{
- // Make this thread recognisable as the GUI-IPC thread
- RenameThread("bitcoin-gui-ipc");
-
- try
- {
- ipcThread2(pArg);
- }
- catch (std::exception& e) {
- PrintExceptionContinue(&e, "ipcThread()");
- } catch (...) {
- PrintExceptionContinue(NULL, "ipcThread()");
- }
- printf("ipcThread exited\n");
-}
-
-static void ipcThread2(void* pArg)
-{
- printf("ipcThread started\n");
-
- message_queue* mq = (message_queue*)pArg;
- char buffer[MAX_URI_LENGTH + 1] = "";
- size_t nSize = 0;
- unsigned int nPriority = 0;
-
- loop
- {
- ptime d = boost::posix_time::microsec_clock::universal_time() + millisec(100);
- if (mq->timed_receive(&buffer, sizeof(buffer), nSize, nPriority, d))
- {
- uiInterface.ThreadSafeHandleURI(std::string(buffer, nSize));
- Sleep(1000);
- }
-
- if (fShutdown)
- break;
- }
-
- // Remove message queue
- message_queue::remove(strBitcoinURIQueueName.c_str());
- // Cleanup allocated memory
- delete mq;
-}
-
-void ipcInit(int argc, char *argv[])
-{
- message_queue* mq = NULL;
- char buffer[MAX_URI_LENGTH + 1] = "";
- size_t nSize = 0;
- unsigned int nPriority = 0;
-
- try {
- mq = new message_queue(open_or_create, strBitcoinURIQueueName.c_str(), 2, MAX_URI_LENGTH);
-
- // Make sure we don't lose any bitcoin: URIs
- for (int i = 0; i < 2; i++)
- {
- ptime d = boost::posix_time::microsec_clock::universal_time() + millisec(1);
- if (mq->timed_receive(&buffer, sizeof(buffer), nSize, nPriority, d))
- {
- uiInterface.ThreadSafeHandleURI(std::string(buffer, nSize));
- }
- else
- break;
- }
-
- // Make sure only one bitcoin instance is listening
- message_queue::remove(strBitcoinURIQueueName.c_str());
- delete mq;
-
- mq = new message_queue(open_or_create, strBitcoinURIQueueName.c_str(), 2, MAX_URI_LENGTH);
- }
- catch (interprocess_exception &ex) {
- printf("ipcInit() - boost interprocess exception #%d: %s\n", ex.get_error_code(), ex.what());
- return;
- }
-
- if (!NewThread(ipcThread, mq))
- {
- delete mq;
- return;
- }
-
- ipcScanCmd(argc, argv, false);
-}
-
-#endif
diff --git a/src/qt/qtipcserver.h b/src/qt/qtipcserver.h
deleted file mode 100644
index f775f272c2..0000000000
--- a/src/qt/qtipcserver.h
+++ /dev/null
@@ -1,16 +0,0 @@
-#ifndef QTIPCSERVER_H
-#define QTIPCSERVER_H
-
-#include <string>
-
-// Define Bitcoin-Qt message queue name for mainnet
-#define BITCOINURI_QUEUE_NAME_MAINNET "BitcoinURI"
-// Define Bitcoin-Qt message queue name for testnet
-#define BITCOINURI_QUEUE_NAME_TESTNET "BitcoinURI-testnet"
-
-extern std::string strBitcoinURIQueueName;
-
-void ipcScanRelay(int argc, char *argv[]);
-void ipcInit(int argc, char *argv[]);
-
-#endif // QTIPCSERVER_H
diff --git a/src/rpcwallet.cpp b/src/rpcwallet.cpp
index 90a68f560a..21eb2fd1aa 100644
--- a/src/rpcwallet.cpp
+++ b/src/rpcwallet.cpp
@@ -75,6 +75,7 @@ Value getinfo(const Array& params, bool fHelp)
obj.push_back(Pair("walletversion", pwalletMain->GetVersion()));
obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
obj.push_back(Pair("blocks", (int)nBestHeight));
+ obj.push_back(Pair("timeoffset", (boost::int64_t)GetTimeOffset()));
obj.push_back(Pair("connections", (int)vNodes.size()));
obj.push_back(Pair("proxy", (proxy.first.IsValid() ? proxy.first.ToStringIPPort() : string())));
obj.push_back(Pair("difficulty", (double)GetDifficulty()));
diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp
index f56969cba6..1b0ccad511 100644
--- a/src/test/util_tests.cpp
+++ b/src/test/util_tests.cpp
@@ -261,4 +261,66 @@ BOOST_AUTO_TEST_CASE(util_IsHex)
BOOST_CHECK(!IsHex("0x0000"));
}
+BOOST_AUTO_TEST_CASE(util_seed_insecure_rand)
+{
+ // Expected results for the determinstic seed.
+ const uint32_t exp_vals[11] = { 91632771U,1889679809U,3842137544U,3256031132U,
+ 1761911779U, 489223532U,2692793790U,2737472863U,
+ 2796262275U,1309899767U,840571781U};
+ // Expected 0s in rand()%(idx+2) for the determinstic seed.
+ const int exp_count[9] = {5013,3346,2415,1972,1644,1386,1176,1096,1009};
+ int i;
+ int count=0;
+
+ seed_insecure_rand();
+
+ //Does the non-determistic rand give us results that look too like the determinstic one?
+ for (i=0;i<10;i++)
+ {
+ int match = 0;
+ uint32_t rval = insecure_rand();
+ for (int j=0;j<11;j++)match |= rval==exp_vals[j];
+ count += match;
+ }
+ // sum(binomial(10,i)*(11/(2^32))^i*(1-(11/(2^32)))^(10-i),i,0,4) ~= 1-1/2^134.73
+ // So _very_ unlikely to throw a false failure here.
+ BOOST_CHECK(count<=4);
+
+ for (int mod=2;mod<11;mod++)
+ {
+ int mask = 1;
+ // Really rough binomal confidence approximation.
+ int err = 30*10000./mod*sqrt((1./mod*(1-1./mod))/10000.);
+ //mask is 2^ceil(log2(mod))-1
+ while(mask<mod-1)mask=(mask<<1)+1;
+
+ count = 0;
+ //How often does it get a zero from the uniform range [0,mod)?
+ for (i=0;i<10000;i++)
+ {
+ uint32_t rval;
+ do{
+ rval=insecure_rand()&mask;
+ }while(rval>=(uint32_t)mod);
+ count += rval==0;
+ }
+ BOOST_CHECK(count<=10000/mod+err);
+ BOOST_CHECK(count>=10000/mod-err);
+ }
+
+ seed_insecure_rand(true);
+
+ for (i=0;i<11;i++)
+ {
+ BOOST_CHECK_EQUAL(insecure_rand(),exp_vals[i]);
+ }
+
+ for (int mod=2;mod<11;mod++)
+ {
+ count = 0;
+ for (i=0;i<10000;i++) count += insecure_rand()%mod==0;
+ BOOST_CHECK_EQUAL(count,exp_count[mod-2]);
+ }
+}
+
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/txdb.cpp b/src/txdb.cpp
index 8c01158254..ae7aceb7f1 100644
--- a/src/txdb.cpp
+++ b/src/txdb.cpp
@@ -22,17 +22,17 @@ void static BatchWriteHashBestChain(CLevelDBBatch &batch, const uint256 &hash) {
CCoinsViewDB::CCoinsViewDB(size_t nCacheSize, bool fMemory, bool fWipe) : db(GetDataDir() / "chainstate", nCacheSize, fMemory, fWipe) {
}
-bool CCoinsViewDB::GetCoins(uint256 txid, CCoins &coins) {
+bool CCoinsViewDB::GetCoins(const uint256 &txid, CCoins &coins) {
return db.Read(make_pair('c', txid), coins);
}
-bool CCoinsViewDB::SetCoins(uint256 txid, const CCoins &coins) {
+bool CCoinsViewDB::SetCoins(const uint256 &txid, const CCoins &coins) {
CLevelDBBatch batch;
BatchWriteCoins(batch, txid, coins);
return db.WriteBatch(batch);
}
-bool CCoinsViewDB::HaveCoins(uint256 txid) {
+bool CCoinsViewDB::HaveCoins(const uint256 &txid) {
return db.Exists(make_pair('c', txid));
}
diff --git a/src/txdb.h b/src/txdb.h
index eb8f574e46..f59fc5da86 100644
--- a/src/txdb.h
+++ b/src/txdb.h
@@ -16,9 +16,9 @@ protected:
public:
CCoinsViewDB(size_t nCacheSize, bool fMemory = false, bool fWipe = false);
- bool GetCoins(uint256 txid, CCoins &coins);
- bool SetCoins(uint256 txid, const CCoins &coins);
- bool HaveCoins(uint256 txid);
+ bool GetCoins(const uint256 &txid, CCoins &coins);
+ bool SetCoins(const uint256 &txid, const CCoins &coins);
+ bool HaveCoins(const uint256 &txid);
CBlockIndex *GetBestBlock();
bool SetBestBlock(CBlockIndex *pindex);
bool BatchWrite(const std::map<uint256, CCoins> &mapCoins, CBlockIndex *pindex);
diff --git a/src/util.cpp b/src/util.cpp
index d8f05cb9fd..fc3e846a6b 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -3,6 +3,15 @@
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#ifndef WIN32
+// for posix_fallocate
+#ifdef __linux__
+#define _POSIX_C_SOURCE 200112L
+#endif
+#include <fcntl.h>
+#include <sys/stat.h>
+#endif
+
#include "util.h"
#include "sync.h"
#include "version.h"
@@ -1152,9 +1161,46 @@ int GetFilesize(FILE* file)
return nFilesize;
}
+bool TruncateFile(FILE *file, unsigned int length) {
+#if defined(WIN32)
+ return _chsize(_fileno(file), length) == 0;
+#else
+ return ftruncate(fileno(file), length) == 0;
+#endif
+}
+
// this function tries to make a particular range of a file allocated (corresponding to disk space)
// it is advisory, and the range specified in the arguments will never contain live data
void AllocateFileRange(FILE *file, unsigned int offset, unsigned int length) {
+#if defined(WIN32)
+ // Windows-specific version
+ HANDLE hFile = (HANDLE)_get_osfhandle(_fileno(file));
+ LARGE_INTEGER nFileSize;
+ int64 nEndPos = (int64)offset + length;
+ nFileSize.u.LowPart = nEndPos & 0xFFFFFFFF;
+ nFileSize.u.HighPart = nEndPos >> 32;
+ SetFilePointerEx(hFile, nFileSize, 0, FILE_BEGIN);
+ SetEndOfFile(hFile);
+#elif defined(MAC_OSX)
+ // OSX specific version
+ fstore_t fst;
+ fst.fst_flags = F_ALLOCATECONTIG;
+ fst.fst_posmode = F_PEOFPOSMODE;
+ fst.fst_offset = 0;
+ fst.fst_length = (off_t)offset + length;
+ fst.fst_bytesalloc = 0;
+ if (fcntl(fileno(file), F_PREALLOCATE, &fst) == -1) {
+ fst.fst_flags = F_ALLOCATEALL;
+ fcntl(fileno(file), F_PREALLOCATE, &fst);
+ }
+ ftruncate(fileno(file), fst.fst_length);
+#elif defined(__linux__)
+ // Version using posix_fallocate
+ off_t nEndPos = (off_t)offset + length;
+ posix_fallocate(fileno(file), 0, nEndPos);
+#else
+ // Fallback version
+ // TODO: just write one byte per block
static const char buf[65536] = {};
fseek(file, offset, SEEK_SET);
while (length > 0) {
@@ -1164,6 +1210,7 @@ void AllocateFileRange(FILE *file, unsigned int offset, unsigned int length) {
fwrite(buf, 1, now, file); // allowed to fail; this function is advisory anyway
length -= now;
}
+#endif
}
void ShrinkDebugFile()
@@ -1218,9 +1265,14 @@ void SetMockTime(int64 nMockTimeIn)
static int64 nTimeOffset = 0;
+int64 GetTimeOffset()
+{
+ return nTimeOffset;
+}
+
int64 GetAdjustedTime()
{
- return GetTime() + nTimeOffset;
+ return GetTime() + GetTimeOffset();
}
void AddTimeData(const CNetAddr& ip, int64 nTime)
@@ -1276,12 +1328,26 @@ void AddTimeData(const CNetAddr& ip, int64 nTime)
}
}
-
-
-
-
-
-
+uint32_t insecure_rand_Rz = 11;
+uint32_t insecure_rand_Rw = 11;
+void seed_insecure_rand(bool fDeterministic)
+{
+ //The seed values have some unlikely fixed points which we avoid.
+ if(fDeterministic)
+ {
+ insecure_rand_Rz = insecure_rand_Rw = 11;
+ } else {
+ uint32_t tmp;
+ do{
+ RAND_bytes((unsigned char*)&tmp,4);
+ }while(tmp==0 || tmp==0x9068ffffU);
+ insecure_rand_Rz=tmp;
+ do{
+ RAND_bytes((unsigned char*)&tmp,4);
+ }while(tmp==0 || tmp==0x464fffffU);
+ insecure_rand_Rw=tmp;
+ }
+}
string FormatVersion(int nVersion)
{
diff --git a/src/util.h b/src/util.h
index 97911d7493..d129d13692 100644
--- a/src/util.h
+++ b/src/util.h
@@ -193,6 +193,7 @@ bool WildcardMatch(const char* psz, const char* mask);
bool WildcardMatch(const std::string& str, const std::string& mask);
void FileCommit(FILE *fileout);
int GetFilesize(FILE* file);
+bool TruncateFile(FILE *file, unsigned int length);
void AllocateFileRange(FILE *file, unsigned int offset, unsigned int length);
bool RenameOver(boost::filesystem::path src, boost::filesystem::path dest);
boost::filesystem::path GetDefaultDataDir();
@@ -212,6 +213,7 @@ uint256 GetRandHash();
int64 GetTime();
void SetMockTime(int64 nMockTimeIn);
int64 GetAdjustedTime();
+int64 GetTimeOffset();
std::string FormatFullVersion();
std::string FormatSubVersion(const std::string& name, int nClientVersion, const std::vector<std::string>& comments);
void AddTimeData(const CNetAddr& ip, int64 nTime);
@@ -403,13 +405,27 @@ bool SoftSetArg(const std::string& strArg, const std::string& strValue);
*/
bool SoftSetBoolArg(const std::string& strArg, bool fValue);
+/**
+ * MWC RNG of George Marsaglia
+ * This is intended to be fast. It has a period of 2^59.3, though the
+ * least significant 16 bits only have a period of about 2^30.1.
+ *
+ * @return random value
+ */
+extern uint32_t insecure_rand_Rz;
+extern uint32_t insecure_rand_Rw;
+static inline uint32_t insecure_rand(void)
+{
+ insecure_rand_Rz=36969*(insecure_rand_Rz&65535)+(insecure_rand_Rz>>16);
+ insecure_rand_Rw=18000*(insecure_rand_Rw&65535)+(insecure_rand_Rw>>16);
+ return (insecure_rand_Rw<<16)+insecure_rand_Rz;
+}
-
-
-
-
-
-
+/**
+ * Seed insecure_rand using the random pool.
+ * @param Deterministic Use a determinstic seed
+ */
+void seed_insecure_rand(bool fDeterministic=false);
/** Median filter over a stream of values.
* Returns the median of the last N numbers
diff --git a/src/wallet.cpp b/src/wallet.cpp
index 2317ac31ac..eecb7d2d22 100644
--- a/src/wallet.cpp
+++ b/src/wallet.cpp
@@ -8,6 +8,7 @@
#include "crypter.h"
#include "ui_interface.h"
#include "base58.h"
+#include <boost/algorithm/string/replace.hpp>
using namespace std;
@@ -476,6 +477,16 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn)
// Notify UI of new or updated transaction
NotifyTransactionChanged(this, hash, fInsertedNew ? CT_NEW : CT_UPDATED);
+
+ // notify an external script when a wallet transaction comes in or is updated
+ std::string strCmd = GetArg("-walletnotify", "");
+
+ if ( !strCmd.empty())
+ {
+ boost::replace_all(strCmd, "%s", wtxIn.GetHash().GetHex());
+ boost::thread t(runCommand, strCmd); // thread runs free
+ }
+
}
return true;
}
@@ -973,6 +984,8 @@ static void ApproximateBestSubset(vector<pair<int64, pair<const CWalletTx*,unsig
vfBest.assign(vValue.size(), true);
nBest = nTotalLower;
+ seed_insecure_rand();
+
for (int nRep = 0; nRep < iterations && nBest != nTargetValue; nRep++)
{
vfIncluded.assign(vValue.size(), false);
@@ -982,7 +995,13 @@ static void ApproximateBestSubset(vector<pair<int64, pair<const CWalletTx*,unsig
{
for (unsigned int i = 0; i < vValue.size(); i++)
{
- if (nPass == 0 ? rand() % 2 : !vfIncluded[i])
+ //The solver here uses a randomized algorithm,
+ //the randomness serves no real security purpose but is just
+ //needed to prevent degenerate behavior and it is important
+ //that the rng fast. We do not use a constant random sequence,
+ //because there may be some privacy improvement by making
+ //the selection random.
+ if (nPass == 0 ? insecure_rand()&1 : !vfIncluded[i])
{
nTotal += vValue[i].first;
vfIncluded[i] = true;