aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md10
-rw-r--r--configure.ac14
-rw-r--r--contrib/README.md50
-rw-r--r--contrib/bitrpc/README.md2
-rw-r--r--contrib/debian/README20
-rw-r--r--contrib/debian/README.md21
-rw-r--r--contrib/debian/bitcoin-qt.desktop2
-rw-r--r--contrib/debian/changelog24
-rw-r--r--contrib/gitian-descriptors/README.md (renamed from contrib/gitian-descriptors/README)44
-rw-r--r--contrib/gitian-descriptors/boost-win32.yml57
-rw-r--r--contrib/gitian-descriptors/deps-win32.yml35
-rw-r--r--contrib/gitian-descriptors/gitian-win32.yml29
-rw-r--r--contrib/gitian-descriptors/protobuf-win32.yml11
-rw-r--r--contrib/gitian-descriptors/qt-win32.yml30
-rw-r--r--contrib/gitian-downloader/michagogo-key.pgp82
-rw-r--r--contrib/linearize/README.md2
-rw-r--r--contrib/linearize/example-linearize.cfg (renamed from contrib/misc/example-linearize.cfg)0
-rw-r--r--[-rwxr-xr-x]contrib/linearize/linearize.py (renamed from contrib/misc/linearize.py)0
-rw-r--r--contrib/macdeploy/README.md19
-rw-r--r--contrib/macdeploy/notes.txt14
-rw-r--r--contrib/pyminer/README.md (renamed from contrib/pyminer/README)3
-rw-r--r--contrib/qos/README.md (renamed from contrib/qos/README)2
-rw-r--r--contrib/seeds/README.md (renamed from contrib/seeds/README)6
-rw-r--r--contrib/spendfrom/README.md (renamed from contrib/spendfrom/README)16
-rw-r--r--contrib/test-patches/README.md (renamed from contrib/test-patches/README)5
-rw-r--r--contrib/testgen/README1
-rw-r--r--contrib/testgen/README.md8
-rw-r--r--contrib/verifysfbinaries/README.md7
-rw-r--r--contrib/wallettools/README.md2
-rw-r--r--doc/README.md22
-rw-r--r--doc/build-unix.md27
-rw-r--r--doc/readme-qt.md101
-rw-r--r--doc/release-process.md29
-rw-r--r--doc/tor.md1
-rwxr-xr-xqa/pull-tester/build-tests.sh.in69
-rwxr-xr-xqa/pull-tester/pull-tester.py16
-rw-r--r--src/Makefile.am9
-rw-r--r--src/Makefile.include6
-rw-r--r--src/allocators.cpp64
-rw-r--r--src/allocators.h56
-rw-r--r--src/bitcoind-res.rc36
-rw-r--r--src/bitcoind.cpp18
-rw-r--r--src/bitcoinrpc.cpp162
-rw-r--r--src/bitcoinrpc.h4
-rw-r--r--src/chainparams.h2
-rw-r--r--src/compat.h6
-rw-r--r--src/core.h34
-rw-r--r--src/db.h2
-rw-r--r--src/init.cpp56
-rw-r--r--src/leveldb/Makefile6
-rw-r--r--src/leveldb/db/autocompact_test.cc118
-rw-r--r--src/leveldb/db/corruption_test.cc51
-rw-r--r--src/leveldb/db/db_impl.cc41
-rw-r--r--src/leveldb/db/db_impl.h9
-rw-r--r--src/leveldb/db/db_iter.cc41
-rw-r--r--src/leveldb/db/db_iter.h8
-rw-r--r--src/leveldb/db/dbformat.h3
-rw-r--r--src/leveldb/db/version_set.cc96
-rw-r--r--src/leveldb/db/version_set.h15
-rw-r--r--src/leveldb/include/leveldb/db.h2
-rw-r--r--src/leveldb/util/env_posix.cc33
-rw-r--r--src/leveldb/util/random.h7
-rw-r--r--src/m4/bitcoin_subdir_to_include.m46
-rw-r--r--src/main.cpp381
-rw-r--r--src/main.h122
-rw-r--r--src/miner.cpp8
-rw-r--r--src/net.cpp56
-rw-r--r--src/net.h30
-rw-r--r--src/netbase.cpp2
-rw-r--r--src/netbase.h2
-rw-r--r--src/qt/Makefile.am10
-rw-r--r--src/qt/bitcoin.cpp3
-rw-r--r--src/qt/bitcoinamountfield.cpp5
-rw-r--r--src/qt/bitcoingui.cpp14
-rw-r--r--src/qt/bitcoingui.h2
-rw-r--r--src/qt/clientmodel.cpp23
-rw-r--r--src/qt/clientmodel.h4
-rw-r--r--src/qt/forms/rpcconsole.ui261
-rw-r--r--src/qt/forms/sendcoinsentry.ui40
-rw-r--r--src/qt/paymentserver.cpp9
-rw-r--r--src/qt/rpcconsole.cpp55
-rw-r--r--src/qt/rpcconsole.h9
-rw-r--r--src/qt/sendcoinsdialog.cpp86
-rw-r--r--src/qt/sendcoinsentry.cpp33
-rw-r--r--src/qt/sendcoinsentry.h3
-rw-r--r--src/qt/test/Makefile.am4
-rw-r--r--src/qt/trafficgraphwidget.cpp169
-rw-r--r--src/qt/trafficgraphwidget.h44
-rw-r--r--src/qt/transactiondesc.cpp2
-rw-r--r--src/qt/transactionrecord.cpp6
-rw-r--r--src/qt/transactiontablemodel.cpp4
-rw-r--r--src/qt/walletframe.cpp7
-rw-r--r--src/qt/walletmodel.cpp38
-rw-r--r--src/qt/walletmodeltransaction.cpp4
-rw-r--r--src/rpcblockchain.cpp16
-rw-r--r--src/rpcdump.cpp12
-rw-r--r--src/rpcmining.cpp76
-rw-r--r--src/rpcnet.cpp35
-rw-r--r--src/rpcrawtransaction.cpp7
-rw-r--r--src/rpcwallet.cpp49
-rw-r--r--src/test/Makefile.am4
-rw-r--r--src/test/miner_tests.cpp12
-rw-r--r--src/txdb.cpp4
-rw-r--r--src/util.cpp1
-rw-r--r--src/util.h1
-rw-r--r--src/wallet.cpp10
106 files changed, 2316 insertions, 1019 deletions
diff --git a/README.md b/README.md
index 0ac3222328..2534a62b08 100644
--- a/README.md
+++ b/README.md
@@ -20,7 +20,7 @@ the Bitcoin client software, see http://www.bitcoin.org.
License
-------
-Bitcoin is released under the terms of the MIT license. See `COPYING` for more
+Bitcoin is released under the terms of the MIT license. See [COPYING](COPYING) for more
information or see http://opensource.org/licenses/MIT.
Development process
@@ -38,7 +38,7 @@ submitter will be asked to start a discussion (if they haven't already) on the
The patch will be accepted if there is broad consensus that it is a good thing.
Developers should expect to rework and resubmit patches if the code doesn't
-match the project's coding conventions (see `doc/coding.md`) or are
+match the project's coding conventions (see [doc/coding.md](doc/coding.md)) or are
controversial.
The `master` branch is regularly built and tested, but is not guaranteed to be
@@ -56,10 +56,7 @@ lots of money.
### Automated Testing
Developers are strongly encouraged to write unit tests for new code, and to
-submit new unit tests for old code.
-
-Unit tests can be compiled and run (assuming they weren't disabled in configure) with:
- make check
+submit new unit tests for old code. Unit tests can be compiled and run (assuming they weren't disabled in configure) with: `make check`
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
@@ -71,5 +68,4 @@ for the build/test scripts.
Large changes should have a test plan, and should be tested by somebody other
than the developer who wrote the code.
-
See https://github.com/bitcoin/QA/ for how to create a test plan.
diff --git a/configure.ac b/configure.ac
index 11357669dd..905acd573c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -125,7 +125,6 @@ AC_PROG_MKDIR_P
AC_PROG_SED
AC_PATH_TOOL(AR, ar)
AC_PATH_TOOL(RANLIB, ranlib)
-AC_PATH_TOOL(WINDRES, windres)
AC_PATH_TOOL(STRIP, strip)
AC_PATH_TOOL(GCOV, gcov)
AC_PATH_PROG(LCOV, lcov)
@@ -155,7 +154,7 @@ use_pkgconfig=yes
case $host in
*mingw*)
- #pkgconfig does more harm than good with mingw
+ #pkgconfig does more harm than good with MinGW
use_pkgconfig=no
TARGET_OS=windows
@@ -177,12 +176,21 @@ case $host in
AC_CHECK_LIB([mswsock], [main],, AC_MSG_ERROR(lib missing))
AC_CHECK_LIB([shlwapi], [main],, AC_MSG_ERROR(lib missing))
AC_CHECK_LIB([iphlpapi], [main],, AC_MSG_ERROR(lib missing))
+ AC_CHECK_LIB([crypt32], [main],, AC_MSG_ERROR(lib missing))
+
+ AX_CHECK_LINK_FLAG([[-static-libgcc]],[LDFLAGS="$LDFLAGS -static-libgcc"])
+ AX_CHECK_LINK_FLAG([[-static-libstdc++]],[LDFLAGS="$LDFLAGS -static-libstdc++"])
AC_PATH_PROG([MAKENSIS], [makensis], none)
if test x$MAKENSIS = xnone; then
AC_MSG_WARN("makensis not found. Cannot create installer.")
fi
+ AC_PATH_TOOL(WINDRES, windres, none)
+ if test x$WINDRES = xnone; then
+ AC_MSG_ERROR("windres not found")
+ fi
+
CPPFLAGS="$CPPFLAGS -D_MT -DWIN32 -D_WINDOWS -DBOOST_THREAD_USE_LIB"
LEVELDB_TARGET_FLAGS="TARGET_OS=OS_WINDOWS_CROSSCOMPILE"
CXXFLAGS="$CXXFLAGS -w"
@@ -290,7 +298,7 @@ if test x$use_hardening != xno; then
AX_CHECK_COMPILE_FLAG([-fno-stack-protector],[HARDENED_CXXFLAGS="$HARDENED_CXXFLAGS -fno-stack-protector"])
AX_CHECK_COMPILE_FLAG([-fstack-protector-all],[HARDENED_CXXFLAGS="$HARDENED_CXXFLAGS -fstack-protector-all"])
- # -pie will link successfully with mingw, but it's unsupported and leads to undeterministic binaries
+ # -pie will link successfully with MinGW, but it's unsupported and leads to undeterministic binaries
AX_CHECK_LINK_FLAG([[-pie]], [HARDENED_LDFLAGS="$HARDENED_LDFLAGS -pie"])
fi
diff --git a/contrib/README.md b/contrib/README.md
new file mode 100644
index 0000000000..7128fd5eb0
--- /dev/null
+++ b/contrib/README.md
@@ -0,0 +1,50 @@
+Contrib Index
+---------------------
+
+### [BitRPC](/contrib/bitrpc) ###
+Added bitrpc.py which allows for sending of all standard Bitcoin commands via RPC rather than as command line args.
+
+### [Debian](/contrib/debian) ###
+Contains files used to package bitcoind/bitcoin-qt
+for Debian-based Linux systems. If you compile bitcoind/bitcoin-qt yourself, there are some useful files here.
+
+### [Gitian-descriptors](/contrib/gitian-descriptors) ###
+Gavin's notes on getting gitian builds up and running using KVM.
+
+### [Gitian-downloader](/contrib/gitian-downloader)
+Various PGP files of core developers.
+
+### [Linearize](/contrib/linearize) ###
+Construct a linear, no-fork, best version of the blockchain.
+
+### [MacDeploy](/contrib/macdeploy) ###
+Scripts and notes for Mac builds.
+
+### [PyMiner](/contrib/pyminer) ###
+
+This is a 'getwork' CPU mining client for Bitcoin. It is pure-python, and therefore very, very slow. The purpose is to provide a reference implementation of a miner, for study.
+
+### [Qos](/contrib/qos) ###
+
+A Linux bash script that will set up tc to limit the outgoing bandwidth for connections to the Bitcoin network. This means one can have an always-on bitcoind instance running, and another local bitcoind/bitcoin-qt instance which connects to this node and receives blocks from it.
+
+### [Seeds](/contrib/seeds) ###
+Utility to generate the pnSeed[] array that is compiled into the client.
+
+### [SpendFrom](/contrib/spendfrom) ###
+
+Use the raw transactions API to send coins received on a particular
+address (or addresses).
+
+### [TestGen](/contrib/testgen) ###
+Utilities to generate test vectors for the data-driven Bitcoin tests.
+
+### [Test Patches](/contrib/test-patches) ###
+These patches are applied when the automated pull-tester
+tests each pull and when master is tested using jenkins.
+
+### [Verify SF Binaries](/contrib/verifysfbinaries) ###
+This script attempts to download and verify the signature file SHA256SUMS.asc from SourceForge.
+
+### [Wallet Tools](/contrib/wallettools) ###
+Contains a wallet change password and unlock script.
diff --git a/contrib/bitrpc/README.md b/contrib/bitrpc/README.md
new file mode 100644
index 0000000000..2dde60a08e
--- /dev/null
+++ b/contrib/bitrpc/README.md
@@ -0,0 +1,2 @@
+### BitRPC ###
+Allows for sending of all standard Bitcoin commands via RPC rather than as command line args. \ No newline at end of file
diff --git a/contrib/debian/README b/contrib/debian/README
deleted file mode 100644
index 1cb9b75fbd..0000000000
--- a/contrib/debian/README
+++ /dev/null
@@ -1,20 +0,0 @@
-This directory contains files used to package bitcoind/bitcoin-qt
-for Debian-based Linux systems.
-
-If you compile bitcoind/bitcoin-qt yourself, there are some
-useful files here:
-
-bitcoin: URI support
---------------------
-
-bitcoin-qt.desktop (Gnome / Open Desktop)
-To install:
- sudo desktop-file-install bitcoin-qt.desktop
- sudo update-desktop-database
-
-If you build yourself, you will either need to modify the paths in
-the .desktop file or copy or symlink your bitcoin-qt binary to /usr/bin
-and the ../../share/pixmaps/bitcoin128.png to /usr/share/pixmaps
-
-bitcoin-qt.protocol (KDE)
-
diff --git a/contrib/debian/README.md b/contrib/debian/README.md
new file mode 100644
index 0000000000..fab9cc2381
--- /dev/null
+++ b/contrib/debian/README.md
@@ -0,0 +1,21 @@
+
+Debian
+====================
+This directory contains files used to package bitcoind/bitcoin-qt
+for Debian-based Linux systems. If you compile bitcoind/bitcoin-qt yourself, there are some useful files here.
+
+## bitcoin: URI support ##
+
+
+bitcoin-qt.desktop (Gnome / Open Desktop)
+To install:
+
+ sudo desktop-file-install bitcoin-qt.desktop
+ sudo update-desktop-database
+
+If you build yourself, you will either need to modify the paths in
+the .desktop file or copy or symlink your bitcoin-qt binary to `/usr/bin`
+and the `../../share/pixmaps/bitcoin128.png` to `/usr/share/pixmaps`
+
+bitcoin-qt.protocol (KDE)
+
diff --git a/contrib/debian/bitcoin-qt.desktop b/contrib/debian/bitcoin-qt.desktop
index b2a2cef622..82bc80a734 100644
--- a/contrib/debian/bitcoin-qt.desktop
+++ b/contrib/debian/bitcoin-qt.desktop
@@ -9,4 +9,4 @@ Terminal=false
Type=Application
Icon=/usr/share/pixmaps/bitcoin128.png
MimeType=x-scheme-handler/bitcoin;
-Categories=Office;
+Categories=Office;Finance;
diff --git a/contrib/debian/changelog b/contrib/debian/changelog
index e600e46705..bd6b42dc51 100644
--- a/contrib/debian/changelog
+++ b/contrib/debian/changelog
@@ -1,3 +1,27 @@
+bitcoin (0.8.5-precise1) precise; urgency=medium
+
+ * New upstream release.
+
+ -- Matt Corallo <matt@bluematt.me> Sun, 15 Sep 2013 14:02:00 -0400
+
+bitcoin (0.8.4-precise1) precise; urgency=medium
+
+ * New upstream release.
+
+ -- Matt Corallo <matt@bluematt.me> Wed, 4 Sep 2013 10:25:00 -0400
+
+bitcoin (0.8.3-natty1) natty; urgency=low
+
+ * New upstream release.
+
+ -- Matt Corallo <matt@bluematt.me> Wed, 26 Jun 2013 00:18:00 +0100
+
+bitcoin (0.8.2-natty1) natty; urgency=low
+
+ * New upstream release.
+
+ -- Matt Corallo <matt@bluematt.me> Wed, 29 Mar 2013 23:23:00 +0100
+
bitcoin (0.8.1-natty3) natty; urgency=low
* New pixmaps
diff --git a/contrib/gitian-descriptors/README b/contrib/gitian-descriptors/README.md
index e9c7d4efc2..40bdbd8e32 100644
--- a/contrib/gitian-descriptors/README
+++ b/contrib/gitian-descriptors/README.md
@@ -1,7 +1,7 @@
-Gavin's notes on getting gitian builds up and running using KVM:
+### Gavin's notes on getting gitian builds up and running using KVM:###
These instructions distilled from:
- https://help.ubuntu.com/community/KVM/Installation
+[ https://help.ubuntu.com/community/KVM/Installation]( https://help.ubuntu.com/community/KVM/Installation)
... see there for complete details.
You need the right hardware: you need a 64-bit-capable CPU with hardware virtualization support (Intel VT-x or AMD-V). Not all modern CPUs support hardware virtualization.
@@ -9,11 +9,13 @@ You need the right hardware: you need a 64-bit-capable CPU with hardware virtual
You probably need to enable hardware virtualization in your machine's BIOS.
You need to be running a recent version of 64-bit-Ubuntu, and you need to install several prerequisites:
- sudo apt-get install ruby apache2 git apt-cacher-ng python-vm-builder qemu-kvm
+
+ sudo apt-get install ruby apache2 git apt-cacher-ng python-vm-builder qemu-kvm
Sanity checks:
- sudo service apt-cacher-ng status # Should return apt-cacher-ng is running
- ls -l /dev/kvm # Should show a /dev/kvm device
+
+ sudo service apt-cacher-ng status # Should return apt-cacher-ng is running
+ ls -l /dev/kvm # Should show a /dev/kvm device
Once you've got the right hardware and software:
@@ -22,10 +24,12 @@ Once you've got the right hardware and software:
git clone git://github.com/devrandom/gitian-builder.git
mkdir gitian-builder/inputs
cd gitian-builder/inputs
+
# Inputs for Linux and Win32:
wget -O miniupnpc-1.6.tar.gz 'http://miniupnp.tuxfamily.org/files/download.php?file=miniupnpc-1.6.tar.gz'
wget 'http://fukuchi.org/works/qrencode/qrencode-3.2.0.tar.bz2'
- # Inputs for Win32: (Linux has packages for these)
+
+ # Inputs for Win32: (Linux has packages for these)
wget 'https://downloads.sourceforge.net/project/boost/boost/1.50.0/boost_1_50_0.tar.bz2'
wget 'http://www.openssl.org/source/openssl-1.0.1c.tar.gz'
wget 'http://download.oracle.com/berkeley-db/db-4.8.30.NC.tar.gz'
@@ -58,31 +62,29 @@ Once you've got the right hardware and software:
---------------------
-gitian-builder now also supports building using LXC. See
- https://help.ubuntu.com/12.04/serverguide/lxc.html
+`gitian-builder` now also supports building using LXC. See
+[ https://help.ubuntu.com/12.04/serverguide/lxc.html]( https://help.ubuntu.com/12.04/serverguide/lxc.html)
... for how to get LXC up and running under Ubuntu.
If your main machine is a 64-bit Mac or PC with a few gigabytes of memory
-and at least 10 gigabytes of free disk space, you can gitian-build using
+and at least 10 gigabytes of free disk space, you can `gitian-build` using
LXC running inside a virtual machine.
Here's a description of Gavin's setup on OSX 10.6:
-1. Download and install VirtualBox from https://www.virtualbox.org/
+1. Download and install VirtualBox from [https://www.virtualbox.org/](https://www.virtualbox.org/)
2. Download the 64-bit Ubuntu Desktop 12.04 LTS .iso CD image from
- http://www.ubuntu.com/
+ [http://www.ubuntu.com/](http://www.ubuntu.com/)
-3. Run VirtualBox and create a new virtual machine, using the
- Ubuntu .iso (see the VirtualBox documentation for details).
- Create it with at least 2 gigabytes of memory and a disk
- that is at least 20 gigabytes big.
+3. Run VirtualBox and create a new virtual machine, using the Ubuntu .iso (see the [VirtualBox documentation](https://www.virtualbox.org/wiki/Documentation) for details). Create it with at least 2 gigabytes of memory and a disk that is at least 20 gigabytes big.
4. Inside the running Ubuntu desktop, install:
- sudo apt-get install debootstrap lxc ruby apache2 git apt-cacher-ng python-vm-builder
-5. Still inside Ubuntu, tell gitian-builder to use LXC, then follow the "Once you've got the right
- hardware and software" instructions above:
- export USE_LXC=1
- git clone git://github.com/bitcoin/bitcoin.git
- ... etc
+ sudo apt-get install debootstrap lxc ruby apache2 git apt-cacher-ng python-vm-builder
+
+5. Still inside Ubuntu, tell gitian-builder to use LXC, then follow the "Once you've got the right hardware and software" instructions above:
+
+ export USE_LXC=1
+ git clone git://github.com/bitcoin/bitcoin.git
+ ... etc \ No newline at end of file
diff --git a/contrib/gitian-descriptors/boost-win32.yml b/contrib/gitian-descriptors/boost-win32.yml
index 9eb4cf5968..b421cbe8c5 100644
--- a/contrib/gitian-descriptors/boost-win32.yml
+++ b/contrib/gitian-descriptors/boost-win32.yml
@@ -1,33 +1,66 @@
---
name: "boost"
suites:
-- "lucid"
+- "precise"
architectures:
-- "i386"
+- "amd64"
packages:
-- "mingw32"
+- "mingw-w64"
+- "g++-mingw-w64"
- "faketime"
- "zip"
reference_datetime: "2011-01-30 00:00:00"
remotes: []
files:
-- "boost_1_50_0.tar.bz2"
+- "boost_1_54_0.tar.bz2"
+- "boost-mingw-gas-cross-compile-2013-03-03.patch"
script: |
+ # Defines
INSTALLPREFIX="$OUTDIR/staging/boost"
+ HOST=i686-w64-mingw32
+ # Input Integrity Check
+ echo "047e927de336af106a24bceba30069980c191529fd76b8dff8eb9a328b48ae1d boost_1_54_0.tar.bz2" | shasum -c
+ echo "d2b7f6a1d7051faef3c9cf41a92fa3671d905ef1e1da920d07651a43299f6268 boost-mingw-gas-cross-compile-2013-03-03.patch" | shasum -c
+
mkdir -p "$INSTALLPREFIX"
- tar xjf boost_1_50_0.tar.bz2
- cd boost_1_50_0
- echo "using gcc : 4.4 : i586-mingw32msvc-g++
+ tar xjf boost_1_54_0.tar.bz2
+ cd boost_1_54_0
+ GCCVERSION=$($HOST-g++ -E -dM $(mktemp --suffix=.h) | grep __VERSION__ | cut -d ' ' -f 3 | cut -d '"' -f 2)
+ echo "using gcc : $GCCVERSION : $HOST-g++
:
- <rc>i586-mingw32msvc-windres
- <archiver>i586-mingw32msvc-ar
+ <rc>$HOST-windres
+ <archiver>$HOST-ar
<cxxflags>-frandom-seed=boost1
+ <ranlib>$HOST-ranlib
;" > user-config.jam
./bootstrap.sh --without-icu
- ./bjam toolset=gcc target-os=windows threadapi=win32 threading=multi variant=release link=static --user-config=user-config.jam --without-mpi --without-python -sNO_BZIP2=1 -sNO_ZLIB=1 --layout=tagged --build-type=complete --prefix="$INSTALLPREFIX" $MAKEOPTS install
+
+ # Workaround: Upstream boost dev refuses to include patch that would allow Free Software cross-compile toolchain to work
+ # This patch was authored by the Fedora package developer and ships in Fedora's mingw32-boost.
+ # Please obtain the exact patch that matches the above sha256sum from one of the following mirrors.
+ #
+ # Read History: https://svn.boost.org/trac/boost/ticket/7262
+ # History Mirror: http://rose.makesad.us/~paulproteus/mirrors/7262%20Boost.Context%20fails%20to%20build%20using%20MinGW.html
+ #
+ # Patch: https://svn.boost.org/trac/boost/raw-attachment/ticket/7262/boost-mingw.patch
+ # Patch Mirror: http://wtogami.fedorapeople.org/boost-mingw-gas-cross-compile-2013-03-03.patch
+ # Patch Mirror: http://mindstalk.net/host/boost-mingw-gas-cross-compile-2013-03-03.patch
+ # Patch Mirror: http://rose.makesad.us/~paulproteus/mirrors/boost-mingw-gas-cross-compile-2013-03-03.patch
+ patch -p0 < ../boost-mingw-gas-cross-compile-2013-03-03.patch
+
+ # Bug Workaround: boost-1.54.0 broke the ability to disable zlib
+ # https://svn.boost.org/trac/boost/ticket/9156
+ sed -i 's^\[ ac.check-library /zlib//zlib : <library>/zlib//zlib^^' libs/iostreams/build/Jamfile.v2
+ sed -i 's^<source>zlib.cpp <source>gzip.cpp \]^^' libs/iostreams/build/Jamfile.v2
+
+ # http://statmt.org/~s0565741/software/boost_1_52_0/libs/context/doc/html/context/requirements.html
+ # Note: Might need these options in the future for 64bit builds.
+ # "Please note that address-model=64 must be given to bjam command line on 64bit Windows for 64bit build; otherwise 32bit code will be generated."
+ # "For cross-compiling the lib you must specify certain additional properties at bjam command line: target-os, abi, binary-format, architecture and address-model."
+ ./bjam toolset=gcc binary-format=pe target-os=windows threadapi=win32 threading=multi variant=release link=static --user-config=user-config.jam --without-mpi --without-python -sNO_BZIP2=1 -sNO_ZLIB=1 --layout=tagged --build-type=complete --prefix="$INSTALLPREFIX" $MAKEOPTS install
cd "$INSTALLPREFIX"
export LD_PRELOAD=/usr/lib/faketime/libfaketime.so.1
export FAKETIME=$REFERENCE_DATETIME
- zip -r boost-win32-1.50.0-gitian3.zip *
- cp boost-win32-1.50.0-gitian3.zip $OUTDIR
+ zip -r boost-win32-1.54.0-gitian-r6.zip *
+ cp boost-win32-1.54.0-gitian-r6.zip $OUTDIR
diff --git a/contrib/gitian-descriptors/deps-win32.yml b/contrib/gitian-descriptors/deps-win32.yml
index b00269dcc3..7ad00fcb01 100644
--- a/contrib/gitian-descriptors/deps-win32.yml
+++ b/contrib/gitian-descriptors/deps-win32.yml
@@ -1,15 +1,15 @@
---
name: "bitcoin-deps"
suites:
-- "lucid"
+- "precise"
architectures:
-- "i386"
+- "amd64"
packages:
-- "mingw32"
+- "mingw-w64"
+- "g++-mingw-w64"
- "git-core"
- "zip"
- "faketime"
-- "wine"
- "psmisc"
reference_datetime: "2011-01-30 00:00:00"
remotes: []
@@ -26,7 +26,7 @@ script: |
export FAKETIME=$REFERENCE_DATETIME
export TZ=UTC
export INSTALLPREFIX=$OUTDIR/staging/deps
- export HOST=i586-mingw32msvc
+ export HOST=i686-w64-mingw32
#
mkdir -p $INSTALLPREFIX
@@ -46,10 +46,23 @@ script: |
#
tar xzf miniupnpc-1.6.tar.gz
cd miniupnpc-1.6
- sed 's/dllwrap -k --driver-name gcc/$(DLLWRAP) -k --driver-name $(CC)/' -i Makefile.mingw
- sed 's|wingenminiupnpcstrings $< $@|./wingenminiupnpcstrings $< $@|' -i Makefile.mingw
+ echo "
+ --- miniupnpc-1.6/Makefile.mingw.orig 2013-09-29 18:52:51.014087958 -1000
+ +++ miniupnpc-1.6/Makefile.mingw 2013-09-29 19:09:29.663318691 -1000
+ @@ -67,8 +67,8 @@
+
+ wingenminiupnpcstrings.o: wingenminiupnpcstrings.c
+
+ -miniupnpcstrings.h: miniupnpcstrings.h.in wingenminiupnpcstrings
+ - wingenminiupnpcstrings \$< \$@
+ +miniupnpcstrings.h: miniupnpcstrings.h.in
+ + sed -e 's|OS/version|MSWindows/5.1.2600|' -e 's|MINIUPNPC_VERSION_STRING \"version\"|MINIUPNPC_VERSION_STRING \"VERSIONHERE\"|' \$< > \$@
+
+ minixml.o: minixml.c minixml.h miniupnpcstrings.h
+
+ " | sed "s/VERSIONHERE/$(cat VERSION)/" | patch -p1
mkdir -p dll
- make -f Makefile.mingw DLLWRAP=$HOST-dllwrap CC=$HOST-gcc AR=$HOST-ar libminiupnpc.a
+ make -f Makefile.mingw CC=$HOST-gcc AR=$HOST-ar libminiupnpc.a
install -d $INSTALLPREFIX/include/miniupnpc
install *.h $INSTALLPREFIX/include/miniupnpc
install libminiupnpc.a $INSTALLPREFIX/lib
@@ -71,12 +84,10 @@ script: |
#
tar xjf qrencode-3.2.0.tar.bz2
cd qrencode-3.2.0
- png_CFLAGS="-I$INSTALLPREFIX/include" png_LIBS="-L$INSTALLPREFIX/lib -lpng" ./configure --prefix=$INSTALLPREFIX --host=i586-mingw32msvc
+ png_CFLAGS="-I$INSTALLPREFIX/include" png_LIBS="-L$INSTALLPREFIX/lib -lpng" ./configure --prefix=$INSTALLPREFIX --host=$HOST
make
make install
cd ..
#
cd $INSTALLPREFIX
- zip -r $OUTDIR/bitcoin-deps-0.0.7.zip include lib
- # Kill wine processes as gitian won't figure out we are done otherwise
- killall wineserver services.exe explorer.exe winedevice.exe
+ zip -r $OUTDIR/bitcoin-deps-win32-gitian-r9.zip include lib
diff --git a/contrib/gitian-descriptors/gitian-win32.yml b/contrib/gitian-descriptors/gitian-win32.yml
index f8c7d818ab..a8a823cac0 100644
--- a/contrib/gitian-descriptors/gitian-win32.yml
+++ b/contrib/gitian-descriptors/gitian-win32.yml
@@ -1,11 +1,12 @@
---
name: "bitcoin"
suites:
-- "lucid"
+- "precise"
architectures:
-- "i386"
+- "amd64"
packages:
-- "mingw32"
+- "mingw-w64"
+- "g++-mingw-w64"
- "git-core"
- "unzip"
- "nsis"
@@ -21,31 +22,33 @@ remotes:
- "url": "https://github.com/bitcoin/bitcoin.git"
"dir": "bitcoin"
files:
-- "qt-win32-4.8.3-gitian-r3.zip"
-- "boost-win32-1.50.0-gitian3.zip"
-- "bitcoin-deps-0.0.7.zip"
-- "protobuf-win32-2.5.0-gitian-r2.zip"
+- "qt-win32-4.8.3-gitian-r4.zip"
+- "boost-win32-1.54.0-gitian-r6.zip"
+- "bitcoin-deps-win32-gitian-r9.zip"
+- "protobuf-win32-2.5.0-gitian-r3.zip"
script: |
#
STAGING=$HOME/staging
+ HOST=i686-w64-mingw32
+ #
mkdir -p $STAGING
cd $STAGING
- unzip ../build/qt-win32-4.8.3-gitian-r3.zip
- unzip ../build/boost-win32-1.50.0-gitian3.zip
- unzip ../build/bitcoin-deps-0.0.7.zip
- unzip ../build/protobuf-win32-2.5.0-gitian-r2.zip
+ unzip ../build/qt-win32-4.8.3-gitian-r4.zip
+ unzip ../build/boost-win32-1.54.0-gitian-r6.zip
+ unzip ../build/bitcoin-deps-win32-gitian-r9.zip
+ unzip ../build/protobuf-win32-2.5.0-gitian-r3.zip
cd $HOME/build/
#
cd bitcoin
export PATH=$STAGING/host/bin:$PATH
export TAR_OPTIONS=--mtime=`echo $REFERENCE_DATETIME | awk '{ print $1 }'`
./autogen.sh
- ./configure --bindir=$OUTDIR --prefix=$STAGING --host=i586-mingw32msvc --with-qt-plugindir=$STAGING/plugins --with-qt-incdir=$STAGING/include --with-qt-bindir=$STAGING/host/bin --with-boost=$STAGING --disable-maintainer-mode --with-protoc-bindir=$STAGING/host/bin --disable-dependency-tracking CPPFLAGS="-I$STAGING/include" LDFLAGS="-L$STAGING/lib" CXXFLAGS="-frandom-seed=bitcoin"
+ ./configure --bindir=$OUTDIR --prefix=$STAGING --host=$HOST --with-qt-plugindir=$STAGING/plugins --with-qt-incdir=$STAGING/include --with-qt-bindir=$STAGING/host/bin --with-boost=$STAGING --disable-maintainer-mode --with-protoc-bindir=$STAGING/host/bin --disable-dependency-tracking CPPFLAGS="-I$STAGING/include" LDFLAGS="-L$STAGING/lib" CXXFLAGS="-frandom-seed=bitcoin"
make dist
mkdir -p distsrc
cd distsrc
tar --strip-components=1 -xf ../bitcoin-*.tar.*
- ./configure --bindir=$OUTDIR --prefix=$STAGING --host=i586-mingw32msvc --with-qt-plugindir=$STAGING/plugins --with-qt-incdir=$STAGING/include --with-qt-bindir=$STAGING/host/bin --with-boost=$STAGING --disable-maintainer-mode --with-protoc-bindir=$STAGING/host/bin --disable-dependency-tracking CPPFLAGS="-I$STAGING/include" LDFLAGS="-L$STAGING/lib" CXXFLAGS="-frandom-seed=bitcoin"
+ ./configure --bindir=$OUTDIR --prefix=$STAGING --host=i686-w64-mingw32 --with-qt-plugindir=$STAGING/plugins --with-qt-incdir=$STAGING/include --with-qt-bindir=$STAGING/host/bin --with-boost=$STAGING --disable-maintainer-mode --with-protoc-bindir=$STAGING/host/bin --disable-dependency-tracking CPPFLAGS="-I$STAGING/include" LDFLAGS="-L$STAGING/lib" CXXFLAGS="-frandom-seed=bitcoin"
export LD_PRELOAD=/usr/lib/faketime/libfaketime.so.1
export FAKETIME=$REFERENCE_DATETIME
export TZ=UTC
diff --git a/contrib/gitian-descriptors/protobuf-win32.yml b/contrib/gitian-descriptors/protobuf-win32.yml
index 5385247732..35f261e1a2 100644
--- a/contrib/gitian-descriptors/protobuf-win32.yml
+++ b/contrib/gitian-descriptors/protobuf-win32.yml
@@ -1,11 +1,12 @@
---
name: "protobuf-win32"
suites:
-- "lucid"
+- "precise"
architectures:
-- "i386"
+- "amd64"
packages:
-- "mingw32"
+- "mingw-w64"
+- "g++-mingw-w64"
- "zip"
- "faketime"
reference_datetime: "2013-04-15 00:00:00"
@@ -16,7 +17,7 @@ script: |
#
export TZ=UTC
export INSTALLPREFIX=$OUTDIR/staging/deps
- export HOST=i586-mingw32msvc
+ export HOST=i686-w64-mingw32
#
#
mkdir -p $INSTALLPREFIX
@@ -36,6 +37,6 @@ script: |
cd $INSTALLPREFIX
export LD_PRELOAD=/usr/lib/faketime/libfaketime.so.1
export FAKETIME=$REFERENCE_DATETIME
- zip -r $OUTDIR/protobuf-win32-2.5.0-gitian-r2.zip include lib host
+ zip -r $OUTDIR/protobuf-win32-2.5.0-gitian-r3.zip include lib host
unset LD_PRELOAD
unset FAKETIME
diff --git a/contrib/gitian-descriptors/qt-win32.yml b/contrib/gitian-descriptors/qt-win32.yml
index 34495c20a6..1fc6f861e0 100644
--- a/contrib/gitian-descriptors/qt-win32.yml
+++ b/contrib/gitian-descriptors/qt-win32.yml
@@ -1,11 +1,12 @@
---
name: "qt"
suites:
-- "lucid"
+- "precise"
architectures:
-- "i386"
+- "amd64"
packages:
-- "mingw32"
+- "mingw-w64"
+- "g++-mingw-w64"
- "zip"
- "unzip"
- "faketime"
@@ -14,34 +15,37 @@ reference_datetime: "2011-01-30 00:00:00"
remotes: []
files:
- "qt-everywhere-opensource-src-4.8.3.tar.gz"
-- "bitcoin-deps-0.0.7.zip"
+- "bitcoin-deps-win32-gitian-r9.zip"
script: |
+ #
+ HOST=i686-w64-mingw32
INSTDIR="$HOME/qt/"
+ #
mkdir $INSTDIR
mkdir -p $INSTDIR/host/bin
#
# Need mingw-compiled openssl from bitcoin-deps:
- unzip bitcoin-deps-0.0.7.zip
+ unzip bitcoin-deps-win32-gitian-r9.zip
DEPSDIR=`pwd`
#
tar xzf qt-everywhere-opensource-src-4.8.3.tar.gz
cd qt-everywhere-opensource-src-4.8.3
sed 's/$TODAY/2011-01-30/' -i configure
- sed 's/i686-pc-mingw32-/i586-mingw32msvc-/' -i mkspecs/unsupported/win32-g++-cross/qmake.conf
- sed --posix 's|QMAKE_CFLAGS\t\t= -pipe|QMAKE_CFLAGS\t\t= -pipe -isystem /usr/i586-mingw32msvc/include/ -frandom-seed=qtbuild|' -i mkspecs/unsupported/win32-g++-cross/qmake.conf
+ sed "s/i686-pc-mingw32-/$HOST-/" -i mkspecs/unsupported/win32-g++-cross/qmake.conf
+ sed --posix "s|QMAKE_CFLAGS\t\t= -pipe|QMAKE_CFLAGS\t\t= -pipe -isystem /usr/$HOST/include/ -frandom-seed=qtbuild|" -i mkspecs/unsupported/win32-g++-cross/qmake.conf
sed 's/QMAKE_CXXFLAGS_EXCEPTIONS_ON = -fexceptions -mthreads/QMAKE_CXXFLAGS_EXCEPTIONS_ON = -fexceptions/' -i mkspecs/unsupported/win32-g++-cross/qmake.conf
sed 's/QMAKE_LFLAGS_EXCEPTIONS_ON = -mthreads/QMAKE_LFLAGS_EXCEPTIONS_ON = -lmingwthrd/' -i mkspecs/unsupported/win32-g++-cross/qmake.conf
- sed --posix 's/QMAKE_MOC\t\t= i586-mingw32msvc-moc/QMAKE_MOC\t\t= moc/' -i mkspecs/unsupported/win32-g++-cross/qmake.conf
- sed --posix 's/QMAKE_RCC\t\t= i586-mingw32msvc-rcc/QMAKE_RCC\t\t= rcc/' -i mkspecs/unsupported/win32-g++-cross/qmake.conf
- sed --posix 's/QMAKE_UIC\t\t= i586-mingw32msvc-uic/QMAKE_UIC\t\t= uic/' -i mkspecs/unsupported/win32-g++-cross/qmake.conf
+ sed --posix "s/QMAKE_MOC\t\t= $HOST-moc/QMAKE_MOC\t\t= moc/" -i mkspecs/unsupported/win32-g++-cross/qmake.conf
+ sed --posix "s/QMAKE_RCC\t\t= $HOST-rcc/QMAKE_RCC\t\t= rcc/" -i mkspecs/unsupported/win32-g++-cross/qmake.conf
+ sed --posix "s/QMAKE_UIC\t\t= $HOST-uic/QMAKE_UIC\t\t= uic/" -i mkspecs/unsupported/win32-g++-cross/qmake.conf
# ar adds timestamps to every object file included in the static library
# providing -D as ar argument is supposed to solve it, but doesn't work as qmake strips off the arguments and adds -M to pass a script...
# which somehow cannot be combined with other flags.
# use faketime only for ar, as it confuses make/qmake into hanging sometimes
- sed --posix "s|QMAKE_LIB\t\t= i586-mingw32msvc-ar -ru|QMAKE_LIB\t\t= $HOME/ar -Dr|" -i mkspecs/unsupported/win32-g++-cross/qmake.conf
+ sed --posix "s|QMAKE_LIB\t\t= $HOST-ar -ru|QMAKE_LIB\t\t= $HOME/ar -Dr|" -i mkspecs/unsupported/win32-g++-cross/qmake.conf
echo '#!/bin/bash' > $HOME/ar
echo 'export LD_PRELOAD=/usr/lib/faketime/libfaketime.so.1' >> $HOME/ar
- echo 'i586-mingw32msvc-ar "$@"' >> $HOME/ar
+ echo "$HOST-ar \"\$@\"" >> $HOME/ar
chmod +x $HOME/ar
#export LD_PRELOAD=/usr/lib/faketime/libfaketime.so.1
export FAKETIME=$REFERENCE_DATETIME
@@ -56,4 +60,4 @@ script: |
# as zip stores file timestamps, use faketime to intercept stat calls to set dates for all files to reference date
export LD_PRELOAD=/usr/lib/faketime/libfaketime.so.1
- zip -r $OUTDIR/qt-win32-4.8.3-gitian-r3.zip *
+ zip -r $OUTDIR/qt-win32-4.8.3-gitian-r4.zip *
diff --git a/contrib/gitian-downloader/michagogo-key.pgp b/contrib/gitian-downloader/michagogo-key.pgp
index bc20629fa0..47bc404554 100644
--- a/contrib/gitian-downloader/michagogo-key.pgp
+++ b/contrib/gitian-downloader/michagogo-key.pgp
@@ -1,27 +1,59 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
-Version: SKS 1.1.0
+Version: GnuPG v1.4.12 (GNU/Linux)
-mQENBFGeqJ4BCADb7SI3/+q93gIvN0AGRg9Mtz73OLIOzCHeeoyn+tp7JcYNzxkQ9lfeXiEf
-n72Sh8gHkLtLIqr7HlIMo8DxSS8JPRVjlJGkNyAW4SeEwN2wNa5OV8k0N4jBa9a1csFyCyrE
-kPKvkUpBkQDvNXjNxyEhHwyZqPanKxy6NXIHOJji8ObOMQXIT9HwJrpjRth3u4uKG968JBTE
-yAXAmkt0Zidl1Ykgzcedk4mJSE9uZCW8DjSv2wMLXcQz8+dYsoskT3KRdkowLHxAfj1BNyNc
-1+rKLghliM5vSQWi+Lbhi1Bxh4sY1UwAlKnAGqrnAGyIvCtkwTq5QI6ufF2ZY44bvVgpABEB
-AAG0IU1pY2hhZ29nbyA8bWljaGFnb2dvQHNlcnZlci5mYWtlPokBOAQTAQIAIgUCUZ6ongIb
-AwYLCQgHAwIGFQgCCQoLBBYCAwECHgECF4AACgkQgsXACWKOzwzMUAgAuqUmK10xE5C3lUym
-2f72z0t6a2NM5Wfjr9//Y1/okC36C5XAMEtN2UwckPzzJ5p5D5y5yzwfZq5Jd8Py29VQIMsV
-7FbC1a0H3D+bCyX+JJ6FAmUbnWOQ/+mydYc74RvD8iwjePNT6kziZNv6dMGctJTl0alwjtQY
-gyGkeYKnIxbcyjHX/IawLUrunb/6mSKun87T8+NM/omfFCTc3l8TakpM0wyNYRiUkIfUBvB8
-sDUU3A80qKN/hqRKvlFu3+/kMiAc9ZYQrbmsB+sYWdmM+4zw8NBw3yuYzWyPuoa4PR5ZmS9F
-11WLMR5vTRCdLudAqYsWu3LtV6vAIvlOUa2LMLkBDQRRnqieAQgAxZoEe6BBpBRQeal57jWB
-atZ1BgwIdHSzbQA9yehDMVGRF3Zqfg0BycOv3g0UGhvRG4zWYXsnG1VKCPCtmP2duvB0Lnhr
-iBCCb+nGWF6F3Vgmww+H5xzDVF9sDZaQ6lsW+zzVBLX1PYSN4Jhxpa+TohId4ldOromYOJ9q
-21j24+OZuSyc78KQq1APqS3JfV48NnGo2kk43Vx5PYL10wqOrNmUt/90OJfsbs2adTBjcz0B
-wEjCrMHnEiSpGIOlvCOVrFZT3fWvKEAnPzX8+wT8N9TEVUf0heRQDKml8ebi8IIVXRwdonC1
-EbDrSZQnz/FtOoAe8kvjB+OSav6MQUYiQQARAQABiQEfBBgBAgAJBQJRnqieAhsMAAoJEILF
-wAlijs8ME+MIAMuiAnJwWfZdo0rvpXcuexeo3+ZKSmYAfTVfFdpjADXmNcDEOFU1aVOLd7OB
-Ni2LRjSTZD0FR27dT3+HRj2rLzD2hzGpoMIMqoGIsarNMQ+T3Ss1a3548E06/2QBXXHEj5r8
-uf4W2NIHkP/ps3Wy9O/sWk+fCSKBuZ8kgyoZglXjr4Q2bVzFQIRFgQzxIIfx/bBLgYDIGa83
-xNY96vNNqol3kLOlrWnVpUNUTfSKtWcyIurvfwYnxCESNKTv1sCjmXVy03phVKGpKHu7k9wO
-+DferdBvS2VYoWGxKDvj3OSGhzwVeVS3kd0wdS554x1X/xcIvHJxsudJDVo3GzMhA2o=
-=YdfZ
------END PGP PUBLIC KEY BLOCK----- \ No newline at end of file
+mQENBFGeqJ4BCADb7SI3/+q93gIvN0AGRg9Mtz73OLIOzCHeeoyn+tp7JcYNzxkQ
+9lfeXiEfn72Sh8gHkLtLIqr7HlIMo8DxSS8JPRVjlJGkNyAW4SeEwN2wNa5OV8k0
+N4jBa9a1csFyCyrEkPKvkUpBkQDvNXjNxyEhHwyZqPanKxy6NXIHOJji8ObOMQXI
+T9HwJrpjRth3u4uKG968JBTEyAXAmkt0Zidl1Ykgzcedk4mJSE9uZCW8DjSv2wML
+XcQz8+dYsoskT3KRdkowLHxAfj1BNyNc1+rKLghliM5vSQWi+Lbhi1Bxh4sY1UwA
+lKnAGqrnAGyIvCtkwTq5QI6ufF2ZY44bvVgpABEBAAG0IU1pY2hhZ29nbyA8bWlj
+aGFnb2dvQHNlcnZlci5mYWtlPokBOAQTAQIAIgUCUZ6ongIbAwYLCQgHAwIGFQgC
+CQoLBBYCAwECHgECF4AACgkQgsXACWKOzwzMUAgAuqUmK10xE5C3lUym2f72z0t6
+a2NM5Wfjr9//Y1/okC36C5XAMEtN2UwckPzzJ5p5D5y5yzwfZq5Jd8Py29VQIMsV
+7FbC1a0H3D+bCyX+JJ6FAmUbnWOQ/+mydYc74RvD8iwjePNT6kziZNv6dMGctJTl
+0alwjtQYgyGkeYKnIxbcyjHX/IawLUrunb/6mSKun87T8+NM/omfFCTc3l8TakpM
+0wyNYRiUkIfUBvB8sDUU3A80qKN/hqRKvlFu3+/kMiAc9ZYQrbmsB+sYWdmM+4zw
+8NBw3yuYzWyPuoa4PR5ZmS9F11WLMR5vTRCdLudAqYsWu3LtV6vAIvlOUa2LMLRg
+TWljaGFnb2dvIChSZWdpc3RlcmVkIG5pY2sgbWljaGFnb2dvIG9uIGZyZWVub2Rl
+IGFzIG9mIE9jdG9iZXIgMTIsIDIwMTMpIDxtaWNoYWdvZ29Ac2VydmVyLmZha2U+
+iQE4BBMBAgAiBQJSWarzAhsDBgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAAKCRCC
+xcAJYo7PDA7nB/91wAiaMlU5nHLUu0anhNQbGvUdFgKK1zO90S5KzUdJcY438jcS
+UJW1az8l9U9JBRIfPRYVhz/Z1TAJ+dCzD7D8BXHFeGEr0zNOh87ly9aB5du7dpN2
+oSBD6wLcJpqxt4h+XjSS2CX98/2ZIJxXENE2KySaTXP39Xl3eNwvJTUBA4XlcMey
+J8KMp/IERli4H0O7vRyLgu3yYpUArTqAonzG1g2lfB35PQJfeInrRSniQ336otnZ
+A8qwJ63kfUtWVDRz0g1fnvtiLGPivDJaI5hyIaUeJPaXU1+sg7YNroDu60o2NGZh
+F+0IjHlvRfzzA+F9Vw38rpSqR3BmCdjf6Sv3iQEcBBABAgAGBQJSWa9/AAoJEH+r
+EUJn5PoE/hgH/1T2dAthVucA/hzY0nl4SMjbg+dzNlYBq00Qwx8DRKVjk5et8+kY
+oPI3DGILcr+ELnxNekeMv9WQBBtJanUh1K5ohZ6ohoR7lG18LXf5HCdspflB5Me6
+LMA6iMryEP6gIs9GFuoGe2YQavm58YrkqhcPu34dGN7kdurfEXLvDfVlh5ZbKCsP
+Gyd7Pbz04SpqykgK1udiTsLVjc70Xhv+jAMqeaCugDX6TLEwjVmZH/xsyKk2Uh3V
+Oib5FXADAtKH+vSqqhFpXrw7R/NaBzvCbas8l61DFHiUg1/bo8vsV8MtGcyZmzXJ
+C5Gm0njtGOil/g7JF9siUrpxs9Yyt/h+T2W0W01pY2hhZ29nbyAoVXNlciBhY2Nv
+dW50IG1pY2hhZ29nbyBvbiBHaXRodWIgYXMgb2YgT2N0b2JlciAxMiwgMjAxMykg
+PG1pY2hhZ29nb0BzZXJ2ZXIuZmFrZT6JATcEEwECACIFAlJZqxkCGwMGCwkIBwMC
+BhUIAgkKCwQWAgMBAh4BAheAAAoJEILFwAlijs8M+1AH+IU78ARblqTnJeSl0iWH
+mEsg4IBK30Q6/exDAcqOEm1Yc171uw2WnGmIvPYOQqxrRTvj3LoQ816dU6jrj6vY
+s+XX0R2hxy7ILh17D/3UKnHcddu7rmc7pNEqZeBXaMughqQaPOWkAIe52+qK5tsl
+sWllzTYE4jo29uZ3dAtDcKEJjBo/pIXnu1GOslE1+V4X1H9WDlwrS/JXHzyDQAjt
+maPR+3gNesDanhrRmrnT3ZXW2ZVd3vGBibhia8PWUhU1uwOH23ySWXncgsHH0Zad
+UMjd4w3YliZP/mLn2ghAxHB70IO7lgAgN3HYZeFoufP3pcK440A+CezfQiRcjHl/
+oIkBHAQQAQIABgUCUlmvfwAKCRB/qxFCZ+T6BOq9CACItsrUZPKGeWSTkMHknMrV
+K5vxIXJVCBb+Tppc0Q/J5p4EkW/RFhTwIP2zw8NLDKMh5oO9md4LXhvfIZkqQJFo
+6ZtLa3Vf+Kj7uyxezBo4QHA+G7tDsRGaMKVrEMiyLCwS1+hg9VaNzsf7zmQW7mYE
+vTLMHp3cVaSU7Mh2Dl8rnAaM/DpTUZQwZ+32Qrb/Z4HSa4f278iqoFpjEbBE2KCr
+vT5yEVvpCZ4lwSgA2a+uTlRTvVV6NA/kpsxU64tmhuEOjy+ToDqJ8wv4mqvWZxMv
+C6OhfVaXBy3U9gG8aQV0ffXGs+TbCtv8ApHd6E1/AVk0oyZGJaBVrEl688bBIWd/
+uQENBFGeqJ4BCADFmgR7oEGkFFB5qXnuNYFq1nUGDAh0dLNtAD3J6EMxUZEXdmp+
+DQHJw6/eDRQaG9EbjNZheycbVUoI8K2Y/Z268HQueGuIEIJv6cZYXoXdWCbDD4fn
+HMNUX2wNlpDqWxb7PNUEtfU9hI3gmHGlr5OiEh3iV06uiZg4n2rbWPbj45m5LJzv
+wpCrUA+pLcl9Xjw2cajaSTjdXHk9gvXTCo6s2ZS3/3Q4l+xuzZp1MGNzPQHASMKs
+wecSJKkYg6W8I5WsVlPd9a8oQCc/Nfz7BPw31MRVR/SF5FAMqaXx5uLwghVdHB2i
+cLURsOtJlCfP8W06gB7yS+MH45Jq/oxBRiJBABEBAAGJAR8EGAECAAkFAlGeqJ4C
+GwwACgkQgsXACWKOzwwT4wgAy6ICcnBZ9l2jSu+ldy57F6jf5kpKZgB9NV8V2mMA
+NeY1wMQ4VTVpU4t3s4E2LYtGNJNkPQVHbt1Pf4dGPasvMPaHMamgwgyqgYixqs0x
+D5PdKzVrfnjwTTr/ZAFdccSPmvy5/hbY0geQ/+mzdbL07+xaT58JIoG5nySDKhmC
+VeOvhDZtXMVAhEWBDPEgh/H9sEuBgMgZrzfE1j3q802qiXeQs6WtadWlQ1RN9Iq1
+ZzIi6u9/BifEIRI0pO/WwKOZdXLTemFUoakoe7uT3A74N96t0G9LZVihYbEoO+Pc
+5IaHPBV5VLeR3TB1LnnjHVf/Fwi8cnGy50kNWjcbMyEDag==
+=jyQ4
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/contrib/linearize/README.md b/contrib/linearize/README.md
new file mode 100644
index 0000000000..70b9f034cd
--- /dev/null
+++ b/contrib/linearize/README.md
@@ -0,0 +1,2 @@
+### Linearize ###
+Construct a linear, no-fork, best version of the blockchain. \ No newline at end of file
diff --git a/contrib/misc/example-linearize.cfg b/contrib/linearize/example-linearize.cfg
index 9e5aa404c2..9e5aa404c2 100644
--- a/contrib/misc/example-linearize.cfg
+++ b/contrib/linearize/example-linearize.cfg
diff --git a/contrib/misc/linearize.py b/contrib/linearize/linearize.py
index 2d8509f83c..2d8509f83c 100755..100644
--- a/contrib/misc/linearize.py
+++ b/contrib/linearize/linearize.py
diff --git a/contrib/macdeploy/README.md b/contrib/macdeploy/README.md
new file mode 100644
index 0000000000..5f0611f20c
--- /dev/null
+++ b/contrib/macdeploy/README.md
@@ -0,0 +1,19 @@
+### MacDeploy ###
+
+You will need the appscript package for the fancy disk image creation to work:
+
+ sudo easy_install appscript
+
+For Snow Leopard (which uses [Python 2.6](http://www.python.org/download/releases/2.6/)), you will need the param_parser package:
+
+ sudo easy_install argparse
+
+This script should not be run manually, instead, after building as usual:
+
+ make deploy
+
+During the process, the disk image window will pop up briefly where the fancy
+settings are applied. This is normal, please do not interfere.
+
+When finished, it will produce `Bitcoin-Qt.dmg`.
+
diff --git a/contrib/macdeploy/notes.txt b/contrib/macdeploy/notes.txt
deleted file mode 100644
index e7f62c4a39..0000000000
--- a/contrib/macdeploy/notes.txt
+++ /dev/null
@@ -1,14 +0,0 @@
-You will need the appscript package for the fancy disk image creation to work.
-Install it by invoking "sudo easy_install appscript".
-
-For Snow Leopard (which uses Python 2.6), you will need the param_parser package.
-Install it by invoking "sudo easy_install argparse"
-
-This script should not be run manually, instead, after building as usual:
-"make deploy"
-
-During the process, the disk image window will pop up briefly where the fancy
-settings are applied. This is normal, please do not interfere.
-
-When finished, it will produce Bitcoin-Qt.dmg.
-
diff --git a/contrib/pyminer/README b/contrib/pyminer/README.md
index d1596575dd..119d51bdc7 100644
--- a/contrib/pyminer/README
+++ b/contrib/pyminer/README.md
@@ -1,5 +1,6 @@
+### PyMiner ###
-This is a 'getwork' CPU mining client for bitcoin.
+This is a 'getwork' CPU mining client for Bitcoin.
It is pure-python, and therefore very, very slow. The purpose is to
provide a reference implementation of a miner, for study.
diff --git a/contrib/qos/README b/contrib/qos/README.md
index f419685744..5e0a975fc6 100644
--- a/contrib/qos/README
+++ b/contrib/qos/README.md
@@ -1,3 +1,5 @@
+### Qos ###
+
This is a Linux bash script that will set up tc to limit the outgoing bandwidth for connections to the Bitcoin network. It limits outbound TCP traffic with a source or destination port of 8333, but not if the destination IP is within a LAN (defined as 192.168.x.x).
This means one can have an always-on bitcoind instance running, and another local bitcoind/bitcoin-qt instance which connects to this node and receives blocks from it.
diff --git a/contrib/seeds/README b/contrib/seeds/README.md
index 97e3e1ec71..f9a0c277e2 100644
--- a/contrib/seeds/README
+++ b/contrib/seeds/README.md
@@ -1,9 +1,11 @@
+### Seeds ###
+
Utility to generate the pnSeed[] array that is compiled into the client
-(see src/net.cpp).
+(see [src/net.cpp](/src/net.cpp)).
The 600 seeds compiled into the 0.8 release were created from sipa's DNS seed data, like this:
-curl -s http://bitcoin.sipa.be/seeds.txt | head -1000 | makeseeds.py
+ curl -s http://bitcoin.sipa.be/seeds.txt | head -1000 | makeseeds.py
The input to makeseeds.py is assumed to be approximately sorted from most-reliable to least-reliable,
with IP:port first on each line (lines that don't match IPv4:port are ignored).
diff --git a/contrib/spendfrom/README b/contrib/spendfrom/README.md
index 8a087a0c1e..bc4def5f74 100644
--- a/contrib/spendfrom/README
+++ b/contrib/spendfrom/README.md
@@ -1,16 +1,18 @@
+### SpendFrom ###
+
Use the raw transactions API to send coins received on a particular
address (or addresses).
-Depends on jsonrpc
+Depends on `jsonrpc`
Usage:
-spendfrom.py --from=FROMADDRESS1[,FROMADDRESS2] --to=TOADDRESS --amount=amount \
- --fee=fee --datadir=/path/to/.bitcoin --testnet --dry_run
+ spendfrom.py --from=FROMADDRESS1[,FROMADDRESS2] --to=TOADDRESS --amount=amount \
+ --fee=fee --datadir=/path/to/.bitcoin --testnet --dry_run
With no arguments, outputs a list of amounts associated with addresses.
-With arguments, sends coins received by the FROMADDRESS addresses to the TOADDRESS.
+With arguments, sends coins received by the `FROMADDRESS` addresses to the `TOADDRESS`.
You may explictly specify how much fee to pay (a fee more than 1% of the amount
will fail, though, to prevent bitcoin-losing accidents). Spendfrom may fail if
@@ -18,11 +20,11 @@ it thinks the transaction would never be confirmed (if the amount being sent is
too small, or if the transaction is too many bytes for the fee).
If a change output needs to be created, the change will be sent to the last
-FROMADDRESS (if you specify just one FROMADDRESS, change will go back to it).
+`FROMADDRESS` (if you specify just one `FROMADDRESS`, change will go back to it).
-If --datadir is not specified, the default datadir is used.
+If `--datadir` is not specified, the default datadir is used.
-The --dry_run option will just create and sign the the transaction and print
+The `--dry_run` option will just create and sign the the transaction and print
the transaction data (as hexadecimal), instead of broadcasting it.
If the transaction is created and broadcast successfully, a transaction id
diff --git a/contrib/test-patches/README b/contrib/test-patches/README.md
index ed754cea7a..def40b0d6c 100644
--- a/contrib/test-patches/README
+++ b/contrib/test-patches/README.md
@@ -1,4 +1,7 @@
+### Test Patches ###
+
These patches are applied when the automated pull-tester
tests each pull and when master is tested using jenkins.
You can find more information about the tests run at
-http://jenkins.bluematt.me/pull-tester/files/
+[http://jenkins.bluematt.me/pull-tester/files/
+](http://jenkins.bluematt.me/pull-tester/files/) \ No newline at end of file
diff --git a/contrib/testgen/README b/contrib/testgen/README
deleted file mode 100644
index 02d6c4cdc2..0000000000
--- a/contrib/testgen/README
+++ /dev/null
@@ -1 +0,0 @@
-Utilities to generate test vectors for the data-driven Bitcoin tests
diff --git a/contrib/testgen/README.md b/contrib/testgen/README.md
new file mode 100644
index 0000000000..83624f443a
--- /dev/null
+++ b/contrib/testgen/README.md
@@ -0,0 +1,8 @@
+### TestGen ###
+
+Utilities to generate test vectors for the data-driven Bitcoin tests.
+
+Usage:
+
+ gen_base58_test_vectors.py valid 50 > ../../src/test/data/base58_keys_valid.json
+ gen_base58_test_vectors.py invalid 50 > ../../src/test/data/base58_keys_invalid.json \ No newline at end of file
diff --git a/contrib/verifysfbinaries/README.md b/contrib/verifysfbinaries/README.md
new file mode 100644
index 0000000000..caa4073605
--- /dev/null
+++ b/contrib/verifysfbinaries/README.md
@@ -0,0 +1,7 @@
+### Verify SF Binaries ###
+This script attempts to download the signature file `SHA256SUMS.asc` from SourceForge.
+
+It first checks if the signature passes, and then downloads the files specified in
+the file, and checks if the hashes of these files match those that are specified
+in the signature file. The script returns 0 if everything passes the checks. It returns 1 if either the
+signature check or the hash check doesn't pass. If an error occurs the return value is 2 \ No newline at end of file
diff --git a/contrib/wallettools/README.md b/contrib/wallettools/README.md
new file mode 100644
index 0000000000..358f52569e
--- /dev/null
+++ b/contrib/wallettools/README.md
@@ -0,0 +1,2 @@
+### Wallet Tools ###
+Contains a wallet change password and unlock script.
diff --git a/doc/README.md b/doc/README.md
index 1238033fb7..068ed988d1 100644
--- a/doc/README.md
+++ b/doc/README.md
@@ -3,22 +3,15 @@ Bitcoin 0.8.2 BETA
Copyright (c) 2009-2013 Bitcoin Developers
+License
+---------------------
Distributed under the [MIT/X11 software license](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](mailto:eay@cryptsoft.com)), and UPnP software written by Thomas Bernard.
-
-Intro
----------------------
-Bitcoin is a free open source peer-to-peer electronic cash system that is
-completely decentralized, without the need for a central server or trusted
-parties. Users hold the crypto keys to their own money and transact directly
-with each other, with the help of a P2P network to check for double-spending.
-
-
Setup
---------------------
-[Bitcoin-Qt](http://bitcoin.org/en/download) is the original Bitcoin client and it builds the backbone of the network. However, it downloads and stores the entire history of Bitcoin transactions; depending on the speed of your computer and network connection, the synchronization process can take anywhere from a few hours to a day or more.
+[Bitcoin-Qt](http://bitcoin.org/en/download) is the original Bitcoin client and it builds the backbone of the network. However, it downloads and stores the entire history of Bitcoin transactions (which is currently several GBs); depending on the speed of your computer and network connection, the synchronization process can take anywhere from a few hours to a day or more.
### Unix
@@ -44,17 +37,20 @@ Unpack the files into a directory and run bitcoin-qt.exe.
* See the documentation at the [Bitcoin Wiki](https://en.bitcoin.it/wiki/Main_Page)
for help and more information.
* Ask for help on [#bitcoin](http://webchat.freenode.net?channels=bitcoin) on Freenode. If you don't have an IRC client use [webchat here](http://webchat.freenode.net?channels=bitcoin).
-* Ask for help on the [BitcoinTalk](https://bitcointalk.org/) forums.
+* Ask for help on the [BitcoinTalk](https://bitcointalk.org/) forums, in the [technical support board](https://bitcointalk.org/index.php?board=4.0).
Building
---------------------
-- [Bitcoin-Qt Readme](readme-qt.md)
+The following are developer notes on how to build Bitcoin on your native platform. They are not complete guide, but include notes on the necessary libraries, compile flags, etc.
+
- [OSX Build Notes](build-osx.md)
- [Unix Build Notes](build-unix.md)
- [Windows Build Notes](build-msw.md)
Development
---------------------
+The Bitcoin repo's [root README](https://github.com/bitcoin/bitcoin/blob/master/README.md) contains relevant information on the development process and automated testing.
+
- [Coding Guidelines](coding.md)
- [Multiwallet Qt Development](multiwallet-qt.md)
- [Release Notes](release-notes.md)
@@ -67,4 +63,4 @@ Other Pages
---------------------
- [Assets Attribution](assets-attribution.md)
- [Files](files.md)
-- [Tor Support](tor.md) \ No newline at end of file
+- [Tor Support](tor.md)
diff --git a/doc/build-unix.md b/doc/build-unix.md
index 579341d2d9..422b46cc3a 100644
--- a/doc/build-unix.md
+++ b/doc/build-unix.md
@@ -21,6 +21,9 @@ Dependencies
libdb4.8 Berkeley DB Blockchain & wallet storage
libboost Boost C++ Library
miniupnpc UPnP Support Optional firewall-jumping support
+ qt GUI GUI toolkit
+ protobuf Payments in GUI Data interchange format used for payment protocol
+ libqrencode QR codes in GUI Optional for generating QR codes
[miniupnpc](http://miniupnp.free.fr/) may be used for UPnP port mapping. It can be downloaded from [here](
http://miniupnp.tuxfamily.org/files/). UPnP support is compiled in and
@@ -46,21 +49,25 @@ Licenses of statically linked libraries:
- Berkeley DB 4.8.30.NC
- Boost 1.37
- miniupnpc 1.6
+- qt 4.8.3
+- protobuf 2.5.0
+- libqrencode 3.2.0
Dependency Build Instructions: Ubuntu & Debian
----------------------------------------------
Build requirements:
sudo apt-get install build-essential
+ sudo apt-get install libtool autotools-dev
sudo apt-get install libssl-dev
-for Ubuntu 12.04:
+for Ubuntu 12.04 and later:
sudo apt-get install libboost-all-dev
db4.8 packages are available [here](https://launchpad.net/~bitcoin/+archive/bitcoin).
- Ubuntu precise has packages for libdb5.1-dev and libdb5.1++-dev,
+ Ubuntu 12.04 and later have packages for libdb5.1-dev and libdb5.1++-dev,
but using these will break binary wallet compatibility, and is not recommended.
for other Ubuntu & Debian:
@@ -74,6 +81,22 @@ Optional:
sudo apt-get install libminiupnpc-dev (see --with-miniupnpc and --enable-upnp-default)
+Dependencies for the GUI: Ubuntu & Debian
+-----------------------------------------
+
+If you want to build Bitcoin-Qt, make sure that the required packages for Qt development
+are installed. Qt 4 is currently necessary to build the GUI.
+
+To build with Qt 4 you need the following:
+
+ apt-get install libqt4-dev libprotobuf-dev
+
+libqrencode (optional) can be installed with:
+
+ apt-get install libqrencode-dev
+
+Once these are installed, they will be found by configure and a bitcoin-qt executable will be
+built by default.
Notes
-----
diff --git a/doc/readme-qt.md b/doc/readme-qt.md
deleted file mode 100644
index 5aa849af10..0000000000
--- a/doc/readme-qt.md
+++ /dev/null
@@ -1,101 +0,0 @@
-Bitcoin-Qt Readme
-===============================
-Contains build and configuration instructions for Bitcoin-Qt (Qt4 GUI for Bitcoin).
-
-Build Instructions
----------------------
-
-### Debian
-
-
-First, make sure that the required packages for Qt4 development of your
-distribution are installed, these are
-
-
-
-for Debian and Ubuntu <= 11.10 :
-
-
- apt-get install qt4-qmake libqt4-dev build-essential libboost-dev libboost-system-dev \
- libboost-filesystem-dev libboost-program-options-dev libboost-thread-dev \
- libssl-dev libdb4.8++-dev libprotobuf-dev protobuf-compiler
-
-for Ubuntu >= 12.04 (please read the 'Berkely DB version warning' below):
-
- apt-get install qt4-qmake libqt4-dev build-essential libboost-dev libboost-system-dev \
- libboost-filesystem-dev libboost-program-options-dev libboost-thread-dev \
- libssl-dev libdb++-dev libminiupnpc-dev libprotobuf-dev protobuf-compiler
-
-For Qt 5 you need the following, otherwise you get an error with lrelease when running qmake:
-
-
- apt-get install qt5-qmake libqt5gui5 libqt5core5 libqt5dbus5 qttools5-dev-tools
-
-Once these are installed, they will be found by configure and bitcoin-qt will be
-built by default.
-
-
-### Mac OS X
-
-* Download and install the [Qt Mac OS X SDK](https://qt-project.org/downloads). It is recommended to also install Apple's Xcode with UNIX tools.
-* Download and install either [MacPorts](https://www.macports.org/) or [HomeBrew](http://mxcl.github.io/homebrew/).
-* Execute the following commands in a terminal to get the dependencies using MacPorts
-
- sudo port selfupdate
- sudo port install boost db48 miniupnpc protobuf-cpp
-
-* Execute the following commands in a terminal to get the dependencies using HomeBrew:
-
- brew update
- brew install boost miniupnpc openssl berkeley-db4 protobuf
-
-Build Configuration Options
----------------------
-
-### UPnP port forwarding
-
-UPnP support is compiled in when possible and turned off by default. See the
-configure options for upnp behavior desired:
-
- --with-miniupnpc No UPnP support miniupnp not required
- --disable-upnp-default (the default) UPnP support turned off by default at runtime
- --enable-upnp-default UPnP support turned on by default at runtime
-
-### Notification support for recent (k)ubuntu versions
-
-DBUS support is enabled by default if dependencies are met.
-
-See the --with-qtdbus configure option.
-
-### Generation of QR codes
-
-[libqrencode](http://fukuchi.org/works/qrencode/) may be used to generate QRCode images for payment requests.
-
-QR code support is enabled by default if dependencies are met.
-
-See the --with-qrencode configure option.
-
-Warnings
----------------------
-
-### Berkely DB Version Warning
-
-
-A warning for people using the *static binary* version of Bitcoin on a Linux/UNIX-ish system (tl;dr: **Berkely DB databases are not forward compatible**).
-
-The static binary version of Bitcoin is linked against libdb4.8 (see also [this Debian issue](http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=621425)).
-
-Now the nasty thing is that databases from 5.X are not compatible with 4.X.
-
-If the globally installed development package of Berkely DB installed on your system is 5.X, any source you build yourself will be linked against that. The first time you run with a 5.X version the database will be upgraded, and 4.X cannot open the new format. This means that you cannot go back to the old statically linked version without significant hassle!
-
-### Ubuntu 11.10 Warning
-
-
-Ubuntu 11.10 has a package called 'qt-at-spi' installed by default. At the time of writing, having that package installed causes bitcoin-qt to crash intermittently. The issue has been reported as [launchpad bug 857790](https://bugs.launchpad.net/ubuntu/+source/qt-at-spi/+bug/857790), but
-isn't yet fixed.
-
-Until the bug is fixed, you can remove the qt-at-spi package to work around the problem, though this will presumably disable screen reader functionality for Qt apps:
-
- sudo apt-get remove qt-at-spi
-
diff --git a/doc/release-process.md b/doc/release-process.md
index 57a3c9d91f..9e0b860a8c 100644
--- a/doc/release-process.md
+++ b/doc/release-process.md
@@ -31,29 +31,34 @@ Release Process
export SIGNER=(your gitian key, ie bluematt, sipa, etc)
export VERSION=(new version, e.g. 0.8.0)
+ pushd ./bitcoin
+ git checkout v${VERSION}
+ popd
pushd ./gitian-builder
Fetch and build inputs: (first time, or when dependency versions change)
mkdir -p inputs; cd inputs/
wget 'http://miniupnp.free.fr/files/download.php?file=miniupnpc-1.6.tar.gz' -O miniupnpc-1.6.tar.gz
- wget 'http://www.openssl.org/source/openssl-1.0.1c.tar.gz'
+ wget 'https://www.openssl.org/source/openssl-1.0.1c.tar.gz'
wget 'http://download.oracle.com/berkeley-db/db-4.8.30.NC.tar.gz'
- wget 'http://zlib.net/zlib-1.2.6.tar.gz'
- wget 'ftp://ftp.simplesystems.org/pub/libpng/png/src/libpng-1.5.9.tar.gz'
- wget 'http://fukuchi.org/works/qrencode/qrencode-3.2.0.tar.bz2'
- wget 'http://downloads.sourceforge.net/project/boost/boost/1.50.0/boost_1_50_0.tar.bz2'
- wget 'http://releases.qt-project.org/qt4/source/qt-everywhere-opensource-src-4.8.3.tar.gz'
- wget 'http://protobuf.googlecode.com/files/protobuf-2.5.0.tar.bz2'
+ wget 'ftp://ftp.simplesystems.org/pub/libpng/png/src/history/zlib/zlib-1.2.6.tar.gz'
+ wget 'ftp://ftp.simplesystems.org/pub/libpng/png/src/history/libpng15/libpng-1.5.9.tar.gz'
+ wget 'https://fukuchi.org/works/qrencode/qrencode-3.2.0.tar.bz2'
+ wget 'https://downloads.sourceforge.net/project/boost/boost/1.54.0/boost_1_54_0.tar.bz2'
+ wget 'https://svn.boost.org/trac/boost/raw-attachment/ticket/7262/boost-mingw.patch' -O \
+ boost-mingw-gas-cross-compile-2013-03-03.patch
+ wget 'https://download.qt-project.org/archive/qt/4.8/4.8.3/qt-everywhere-opensource-src-4.8.3.tar.gz'
+ wget 'https://protobuf.googlecode.com/files/protobuf-2.5.0.tar.bz2'
cd ..
./bin/gbuild ../bitcoin/contrib/gitian-descriptors/boost-win32.yml
- mv build/out/boost-win32-1.50.0-gitian2.zip inputs/
- ./bin/gbuild ../bitcoin/contrib/gitian-descriptors/qt-win32.yml
- mv build/out/qt-win32-4.8.3-gitian-r2.zip inputs/
+ mv build/out/boost-win32-*.zip inputs/
./bin/gbuild ../bitcoin/contrib/gitian-descriptors/deps-win32.yml
- mv build/out/bitcoin-deps-0.0.5.zip inputs/
+ mv build/out/bitcoin-deps-*.zip inputs/
+ ./bin/gbuild ../bitcoin/contrib/gitian-descriptors/qt-win32.yml
+ mv build/out/qt-win32-*.zip inputs/
./bin/gbuild ../bitcoin/contrib/gitian-descriptors/protobuf-win32.yml
- mv build/out/protobuf-win32-2.5.0-gitian-r1.zip inputs/
+ mv build/out/protobuf-win32-*.zip inputs/
Build bitcoind and bitcoin-qt on Linux32, Linux64, and Win32:
diff --git a/doc/tor.md b/doc/tor.md
index 86d56cffd5..6057801d34 100644
--- a/doc/tor.md
+++ b/doc/tor.md
@@ -48,6 +48,7 @@ config file):
HiddenServiceDir /var/lib/tor/bitcoin-service/
HiddenServicePort 8333 127.0.0.1:8333
+ HiddenServicePort 18333 127.0.0.1:18333
The directory can be different of course, but (both) port numbers should be equal to
your bitcoind's P2P listen port (8333 by default).
diff --git a/qa/pull-tester/build-tests.sh.in b/qa/pull-tester/build-tests.sh.in
index b353c57909..461e7be048 100755
--- a/qa/pull-tester/build-tests.sh.in
+++ b/qa/pull-tester/build-tests.sh.in
@@ -3,43 +3,72 @@
# Param2: Path to java comparison tool
# Param3: Number of make jobs. Defaults to 1.
+# Exit immediately if anything fails:
set -e
set -o xtrace
MINGWPREFIX=$1
JAVA_COMPARISON_TOOL=$2
JOBS=${3-1}
+OUT_DIR=${4-}
if [ $# -lt 2 ]; then
- echo "Usage: $0 [mingw-prefix] [java-comparison-tool] <make jobs>"
+ echo "Usage: $0 [mingw-prefix] [java-comparison-tool] <make jobs> <save output dir>"
exit 1
fi
DISTDIR=@PACKAGE@-@VERSION@
+# Cross-compile for windows first (breaking the mingw/windows build is most common)
cd @abs_top_srcdir@
make distdir
-mv $DISTDIR linux-build
-cd linux-build
-./configure --with-comparison-tool="$JAVA_COMPARISON_TOOL"
+mv $DISTDIR win32-build
+cd win32-build
+./configure --disable-silent-rules --disable-ccache --prefix=$MINGWPREFIX --host=i586-mingw32msvc --with-qt-bindir=$MINGWPREFIX/host/bin --with-qt-plugindir=$MINGWPREFIX/plugins --with-qt-incdir=$MINGWPREFIX/include --with-boost=$MINGWPREFIX --with-protoc-bindir=$MINGWPREFIX/host/bin CPPFLAGS=-I$MINGWPREFIX/include LDFLAGS=-L$MINGWPREFIX/lib
make -j$JOBS
-make check
-#Test code coverage
+# And compile for Linux:
cd @abs_top_srcdir@
make distdir
-mv $DISTDIR linux-coverage-build
-cd linux-coverage-build
-./configure --enable-lcov --with-comparison-tool="$JAVA_COMPARISON_TOOL"
+mv $DISTDIR linux-build
+cd linux-build
+# TODO: re-enable blockchain tester tool, as of 11 Oct 2013 is it not working properly
+# on the pull-tester machine.
+#./configure --disable-silent-rules --disable-ccache --with-comparison-tool="$JAVA_COMPARISON_TOOL"
+./configure --disable-silent-rules --disable-ccache
make -j$JOBS
-make cov
-
-# win32 build disabled until pull-tester has updated dependencies
-##Test win32 build
-#cd @abs_top_srcdir@
-#make distdir
-#mv $DISTDIR win32-build
-#cd win32-build
-#./configure --prefix=$MINGWPREFIX --host=i586-mingw32msvc --with-qt-bindir=$MINGWPREFIX/host/bin --with-qt-plugindir=$MINGWPREFIX/plugins --with-qt-incdir=$MINGWPREFIX/include --with-boost=$MINGWPREFIX --with-protoc-bindir=$MINGWPREFIX/host/bin --with-comparison-tool="$JAVA_COMPARISON_TOOL" CPPFLAGS=-I$MINGWPREFIX/include LDFLAGS=-L$MINGWPREFIX/lib
-#make -j$JOBS
-#make check
+
+# link interesting binaries to parent out/ directory, if it exists. Do this before
+# running unit tests (we want bad binaries to be easy to find)
+if [ -d "$OUT_DIR" -a -w "$OUT_DIR" ]; then
+ set +e
+ # Windows:
+ cp @abs_top_srcdir@/win32-build/src/bitcoind.exe $OUT_DIR/bitcoind.exe
+ cp @abs_top_srcdir@/win32-build/src/test/test_bitcoin.exe $OUT_DIR/test_bitcoin.exe
+ cp @abs_top_srcdir@/win32-build/src/qt/bitcoind-qt.exe $OUT_DIR/bitcoin-qt.exe
+ # Linux:
+ cp @abs_top_srcdir@/linux-build/src/bitcoind $OUT_DIR/bitcoind
+ cp @abs_top_srcdir@/linux-build/src/test/test_bitcoin $OUT_DIR/test_bitcoin
+ cp @abs_top_srcdir@/linux-build/src/qt/bitcoind-qt $OUT_DIR/bitcoin-qt
+ set -e
+fi
+
+# Run unit tests and blockchain-tester on Linux:
+cd @abs_top_srcdir@/linux-build
+make check
+
+# Clean up builds (pull-tester machine doesn't have infinite disk space)
+cd @abs_top_srcdir@/linux-build
+make clean
+cd @abs_top_srcdir@/win32-build
+make clean
+
+# TODO: Fix code coverage builds on pull-tester machine
+# # Test code coverage
+# cd @abs_top_srcdir@
+# make distdir
+# mv $DISTDIR linux-coverage-build
+# cd linux-coverage-build
+# ./configure --enable-lcov --disable-silent-rules --disable-ccache --with-comparison-tool="$JAVA_COMPARISON_TOOL"
+# make -j$JOBS
+# make cov
diff --git a/qa/pull-tester/pull-tester.py b/qa/pull-tester/pull-tester.py
index fe50177a24..34dd74c7e0 100755
--- a/qa/pull-tester/pull-tester.py
+++ b/qa/pull-tester/pull-tester.py
@@ -38,7 +38,7 @@ def checkout_pull(clone_url, commit, out):
# Init
build_dir=os.environ["BUILD_DIR"]
run("umount ${CHROOT_COPY}/proc", fail_hard=False)
- run("rsync --delete -apv ${CHROOT_MASTER} ${CHROOT_COPY}")
+ run("rsync --delete -apv ${CHROOT_MASTER}/ ${CHROOT_COPY}")
run("rm -rf ${CHROOT_COPY}${SCRIPTS_DIR}")
run("cp -a ${SCRIPTS_DIR} ${CHROOT_COPY}${SCRIPTS_DIR}")
# Merge onto upstream/master
@@ -108,17 +108,18 @@ def testpull(number, comment_url, clone_url, commit):
open(os.environ["TESTED_DB"], "a").write(commit + "\n")
return
- # New: pull-tester.sh script(s) are in the tree:
+ run("rm -rf ${CHROOT_COPY}/${OUT_DIR}", fail_hard=False);
+ run("mkdir -p ${CHROOT_COPY}/${OUT_DIR}", fail_hard=False);
+ run("chown -R ${BUILD_USER}:${BUILD_GROUP} ${CHROOT_COPY}/${OUT_DIR}", fail_hard=False)
+
script = os.environ["BUILD_PATH"]+"/qa/pull-tester/pull-tester.sh"
- script += " ${BUILD_PATH} ${MINGW_DEPS_DIR} ${SCRIPTS_DIR}/BitcoindComparisonTool.jar 1"
+ script += " ${BUILD_PATH} ${MINGW_DEPS_DIR} ${SCRIPTS_DIR}/BitcoindComparisonTool.jar 6 ${OUT_DIR}"
returncode = run("chroot ${CHROOT_COPY} sudo -u ${BUILD_USER} -H timeout ${TEST_TIMEOUT} "+script,
fail_hard=False, stdout=out, stderr=out)
+ run("mv ${CHROOT_COPY}/${OUT_DIR} " + dir)
run("mv ${BUILD_DIR} " + dir)
- # TODO: FIXME
- # Idea: have run-script save interesting output...
- # run("cp /mnt/chroot-tmp/home/ubuntu/.bitcoin/regtest/debug.log " + dir)
- # os.system("chmod +r " + dir + "/debug.log")
+
if returncode == 42:
print("Successfully tested pull (needs tests) - sending comment to: " + comment_url)
commentOn(comment_url, True, False, True, resultsurl)
@@ -147,6 +148,7 @@ environ_default("MINGW_DEPS_DIR", "/mnt/w32deps")
environ_default("SCRIPTS_DIR", "/mnt/test-scripts")
environ_default("CHROOT_COPY", "/mnt/chroot-tmp")
environ_default("CHROOT_MASTER", "/mnt/chroot")
+environ_default("OUT_DIR", "/mnt/out")
environ_default("BUILD_PATH", "/mnt/bitcoin")
os.environ["BUILD_DIR"] = os.environ["CHROOT_COPY"] + os.environ["BUILD_PATH"]
environ_default("RESULTS_DIR", "/mnt/www/pull-tester")
diff --git a/src/Makefile.am b/src/Makefile.am
index 3b0f096744..49249fedc7 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,6 +1,7 @@
+include Makefile.include
AM_CPPFLAGS = $(INCLUDES) -I$(top_builddir)/src/obj \
-I$(top_srcdir)/src/leveldb/include -I$(top_srcdir)/src/leveldb/helpers \
- -I$(builddir) $(BOOST_INCLUDES)
+ -I$(builddir) $(BOOST_INCLUDES) $(BDB_CPPFLAGS)
AM_LDFLAGS = $(PTHREAD_CFLAGS)
noinst_LIBRARIES = libbitcoin.a
@@ -30,7 +31,7 @@ obj/build.h: FORCE
$(abs_top_srcdir)
version.o: obj/build.h
-libbitcoin_a_SOURCES = addrman.cpp alert.cpp bitcoinrpc.cpp bloom.cpp \
+libbitcoin_a_SOURCES = addrman.cpp alert.cpp allocators.cpp bitcoinrpc.cpp bloom.cpp \
chainparams.cpp checkpoints.cpp core.cpp crypter.cpp db.cpp hash.cpp \
init.cpp key.cpp keystore.cpp leveldb.cpp main.cpp miner.cpp \
netbase.cpp net.cpp noui.cpp protocol.cpp rpcblockchain.cpp rpcdump.cpp \
@@ -47,6 +48,10 @@ bitcoind_LDADD = libbitcoin.a leveldb/libleveldb.a leveldb/libmemenv.a \
bitcoind_SOURCES = bitcoind.cpp
#
+if TARGET_WINDOWS
+bitcoind_SOURCES += bitcoind-res.rc
+endif
+
AM_CPPFLAGS += $(BDB_CPPFLAGS)
bitcoind_LDADD += $(BDB_LIBS)
diff --git a/src/Makefile.include b/src/Makefile.include
index d002e8ed6f..352471061d 100644
--- a/src/Makefile.include
+++ b/src/Makefile.include
@@ -1,13 +1,11 @@
-.PHONY: FORCE
+# Helper for rules and subdir Makefiles to find parent targets.
+# Flags and other non-target variables should not be set here.
LIBBITCOIN=$(top_builddir)/src/libbitcoin.a
LIBLEVELDB=$(top_builddir)/src/leveldb/libleveldb.a
LIBMEMENV=$(top_builddir)/src/leveldb/libmemenv.a
LIBBITCOINQT=$(top_builddir)/src/qt/libbitcoinqt.a
-INCLUDES += $(BDB_CPPFLAGS)
-LIBBITCOIN += $(BDB_LIBS)
-
$(LIBBITCOIN):
$(MAKE) -C $(top_builddir)/src $(@F)
diff --git a/src/allocators.cpp b/src/allocators.cpp
new file mode 100644
index 0000000000..b239b623d8
--- /dev/null
+++ b/src/allocators.cpp
@@ -0,0 +1,64 @@
+// Copyright (c) 2009-2013 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 "allocators.h"
+
+#ifdef WIN32
+#ifdef _WIN32_WINNT
+#undef _WIN32_WINNT
+#endif
+#define _WIN32_WINNT 0x0501
+#define WIN32_LEAN_AND_MEAN 1
+#ifndef NOMINMAX
+#define NOMINMAX
+#endif
+#include <windows.h>
+// This is used to attempt to keep keying material out of swap
+// Note that VirtualLock does not provide this as a guarantee on Windows,
+// but, in practice, memory that has been VirtualLock'd almost never gets written to
+// the pagefile except in rare circumstances where memory is extremely low.
+#else
+#include <sys/mman.h>
+#include <limits.h> // for PAGESIZE
+#include <unistd.h> // for sysconf
+#endif
+
+/** Determine system page size in bytes */
+static inline size_t GetSystemPageSize()
+{
+ size_t page_size;
+#if defined(WIN32)
+ SYSTEM_INFO sSysInfo;
+ GetSystemInfo(&sSysInfo);
+ page_size = sSysInfo.dwPageSize;
+#elif defined(PAGESIZE) // defined in limits.h
+ page_size = PAGESIZE;
+#else // assume some POSIX OS
+ page_size = sysconf(_SC_PAGESIZE);
+#endif
+ return page_size;
+}
+
+bool MemoryPageLocker::Lock(const void *addr, size_t len)
+{
+#ifdef WIN32
+ return VirtualLock(const_cast<void*>(addr), len);
+#else
+ return mlock(addr, len) == 0;
+#endif
+}
+
+bool MemoryPageLocker::Unlock(const void *addr, size_t len)
+{
+#ifdef WIN32
+ return VirtualUnlock(const_cast<void*>(addr), len);
+#else
+ return munlock(addr, len) == 0;
+#endif
+}
+
+LockedPageManager::LockedPageManager() : LockedPageManagerBase<MemoryPageLocker>(GetSystemPageSize())
+{
+}
+
diff --git a/src/allocators.h b/src/allocators.h
index 85af8fe376..fd6f51b27e 100644
--- a/src/allocators.h
+++ b/src/allocators.h
@@ -11,25 +11,6 @@
#include <map>
#include <openssl/crypto.h> // for OPENSSL_cleanse()
-#ifdef WIN32
-#ifdef _WIN32_WINNT
-#undef _WIN32_WINNT
-#endif
-#define _WIN32_WINNT 0x0501
-#define WIN32_LEAN_AND_MEAN 1
-#ifndef NOMINMAX
-#define NOMINMAX
-#endif
-#include <windows.h>
-// This is used to attempt to keep keying material out of swap
-// Note that VirtualLock does not provide this as a guarantee on Windows,
-// but, in practice, memory that has been VirtualLock'd almost never gets written to
-// the pagefile except in rare circumstances where memory is extremely low.
-#else
-#include <sys/mman.h>
-#include <limits.h> // for PAGESIZE
-#include <unistd.h> // for sysconf
-#endif
/**
* Thread-safe class to keep track of locked (ie, non-swappable) memory pages.
@@ -115,21 +96,6 @@ private:
Histogram histogram;
};
-/** Determine system page size in bytes */
-static inline size_t GetSystemPageSize()
-{
- size_t page_size;
-#if defined(WIN32)
- SYSTEM_INFO sSysInfo;
- GetSystemInfo(&sSysInfo);
- page_size = sSysInfo.dwPageSize;
-#elif defined(PAGESIZE) // defined in limits.h
- page_size = PAGESIZE;
-#else // assume some POSIX OS
- page_size = sysconf(_SC_PAGESIZE);
-#endif
- return page_size;
-}
/**
* OS-dependent memory page locking/unlocking.
@@ -141,25 +107,11 @@ public:
/** Lock memory pages.
* addr and len must be a multiple of the system page size
*/
- bool Lock(const void *addr, size_t len)
- {
-#ifdef WIN32
- return VirtualLock(const_cast<void*>(addr), len);
-#else
- return mlock(addr, len) == 0;
-#endif
- }
+ bool Lock(const void *addr, size_t len);
/** Unlock memory pages.
* addr and len must be a multiple of the system page size
*/
- bool Unlock(const void *addr, size_t len)
- {
-#ifdef WIN32
- return VirtualUnlock(const_cast<void*>(addr), len);
-#else
- return munlock(addr, len) == 0;
-#endif
- }
+ bool Unlock(const void *addr, size_t len);
};
/**
@@ -171,9 +123,7 @@ class LockedPageManager: public LockedPageManagerBase<MemoryPageLocker>
public:
static LockedPageManager instance; // instantiated in util.cpp
private:
- LockedPageManager():
- LockedPageManagerBase<MemoryPageLocker>(GetSystemPageSize())
- {}
+ LockedPageManager();
};
//
diff --git a/src/bitcoind-res.rc b/src/bitcoind-res.rc
new file mode 100644
index 0000000000..202b7ab352
--- /dev/null
+++ b/src/bitcoind-res.rc
@@ -0,0 +1,36 @@
+#include <windows.h> // needed for VERSIONINFO
+#include "clientversion.h" // holds the needed client version information
+
+#define VER_PRODUCTVERSION CLIENT_VERSION_MAJOR,CLIENT_VERSION_MINOR,CLIENT_VERSION_REVISION,CLIENT_VERSION_BUILD
+#define VER_PRODUCTVERSION_STR STRINGIZE(CLIENT_VERSION_MAJOR) "." STRINGIZE(CLIENT_VERSION_MINOR) "." STRINGIZE(CLIENT_VERSION_REVISION) "." STRINGIZE(CLIENT_VERSION_BUILD)
+#define VER_FILEVERSION VER_PRODUCTVERSION
+#define VER_FILEVERSION_STR VER_PRODUCTVERSION_STR
+#define COPYRIGHT_STR "2009-" STRINGIZE(COPYRIGHT_YEAR) " The Bitcoin developers"
+
+VS_VERSION_INFO VERSIONINFO
+FILEVERSION VER_FILEVERSION
+PRODUCTVERSION VER_PRODUCTVERSION
+FILEOS VOS_NT_WINDOWS32
+FILETYPE VFT_APP
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904E4" // U.S. English - multilingual (hex)
+ BEGIN
+ VALUE "CompanyName", "Bitcoin"
+ VALUE "FileDescription", "Bitcoind (OSS daemon/client for Bitcoin)"
+ VALUE "FileVersion", VER_FILEVERSION_STR
+ VALUE "InternalName", "bitcoind"
+ VALUE "LegalCopyright", COPYRIGHT_STR
+ VALUE "LegalTrademarks1", "Distributed under the MIT/X11 software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php."
+ VALUE "OriginalFilename", "bitcoind.exe"
+ VALUE "ProductName", "Bitcoind"
+ VALUE "ProductVersion", VER_PRODUCTVERSION_STR
+ END
+ END
+
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x0, 1252 // language neutral - multilingual (decimal)
+ END
+END
diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp
index 02e4e7d6e7..add3b4e1f0 100644
--- a/src/bitcoind.cpp
+++ b/src/bitcoind.cpp
@@ -9,15 +9,18 @@
void DetectShutdownThread(boost::thread_group* threadGroup)
{
- bool shutdown = ShutdownRequested();
+ bool fShutdown = ShutdownRequested();
// Tell the main threads to shutdown.
- while (!shutdown)
+ while (!fShutdown)
{
MilliSleep(200);
- shutdown = ShutdownRequested();
+ fShutdown = ShutdownRequested();
}
if (threadGroup)
+ {
threadGroup->interrupt_all();
+ threadGroup->join_all();
+ }
}
//////////////////////////////////////////////////////////////////////////////
@@ -66,6 +69,7 @@ bool AppInit(int argc, char* argv[])
}
// Command-line RPC
+ bool fCommandLine = false;
for (int i = 1; i < argc; i++)
if (!IsSwitchChar(argv[i][0]) && !boost::algorithm::istarts_with(argv[i], "bitcoin:"))
fCommandLine = true;
@@ -107,10 +111,16 @@ bool AppInit(int argc, char* argv[])
} catch (...) {
PrintExceptionContinue(NULL, "AppInit()");
}
- if (!fRet) {
+
+ if (!fRet)
+ {
if (detectShutdownThread)
detectShutdownThread->interrupt();
+
threadGroup.interrupt_all();
+ // threadGroup.join_all(); was left out intentionally here, because we didn't re-test all of
+ // the startup-failure cases to make sure they don't result in a hang due to some
+ // thread-blocking-waiting-for-another-thread-during-startup case
}
if (detectShutdownThread)
diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp
index f9e0c476f6..798660dff3 100644
--- a/src/bitcoinrpc.cpp
+++ b/src/bitcoinrpc.cpp
@@ -160,6 +160,9 @@ string CRPCTable::help(string strCommand) const
continue;
if (strCommand != "" && strMethod != strCommand)
continue;
+ if (pcmd->reqWallet && !pwalletMain)
+ continue;
+
try
{
Array params;
@@ -218,76 +221,79 @@ Value stop(const Array& params, bool fHelp)
static const CRPCCommand vRPCCommands[] =
-{ // name actor (function) okSafeMode threadSafe
- // ------------------------ ----------------------- ---------- ----------
- { "help", &help, true, true },
- { "stop", &stop, true, true },
- { "getblockcount", &getblockcount, true, false },
- { "getbestblockhash", &getbestblockhash, true, false },
- { "getconnectioncount", &getconnectioncount, true, false },
- { "getpeerinfo", &getpeerinfo, true, false },
- { "addnode", &addnode, true, true },
- { "getaddednodeinfo", &getaddednodeinfo, true, true },
- { "getdifficulty", &getdifficulty, true, false },
- { "getgenerate", &getgenerate, true, false },
- { "setgenerate", &setgenerate, true, false },
- { "gethashespersec", &gethashespersec, true, false },
- { "getinfo", &getinfo, true, false },
- { "getmininginfo", &getmininginfo, true, false },
- { "getnewaddress", &getnewaddress, true, false },
- { "getaccountaddress", &getaccountaddress, true, false },
- { "getrawchangeaddress", &getrawchangeaddress, true, false },
- { "setaccount", &setaccount, true, false },
- { "getaccount", &getaccount, false, false },
- { "getaddressesbyaccount", &getaddressesbyaccount, true, false },
- { "sendtoaddress", &sendtoaddress, false, false },
- { "getreceivedbyaddress", &getreceivedbyaddress, false, false },
- { "getreceivedbyaccount", &getreceivedbyaccount, false, false },
- { "listreceivedbyaddress", &listreceivedbyaddress, false, false },
- { "listreceivedbyaccount", &listreceivedbyaccount, false, false },
- { "backupwallet", &backupwallet, true, false },
- { "keypoolrefill", &keypoolrefill, true, false },
- { "walletpassphrase", &walletpassphrase, true, false },
- { "walletpassphrasechange", &walletpassphrasechange, false, false },
- { "walletlock", &walletlock, true, false },
- { "encryptwallet", &encryptwallet, false, false },
- { "validateaddress", &validateaddress, true, false },
- { "getbalance", &getbalance, false, false },
- { "move", &movecmd, false, false },
- { "sendfrom", &sendfrom, false, false },
- { "sendmany", &sendmany, false, false },
- { "addmultisigaddress", &addmultisigaddress, false, false },
- { "createmultisig", &createmultisig, true, true },
- { "getrawmempool", &getrawmempool, true, false },
- { "getblock", &getblock, false, false },
- { "getblockhash", &getblockhash, false, false },
- { "gettransaction", &gettransaction, false, false },
- { "listtransactions", &listtransactions, false, false },
- { "listaddressgroupings", &listaddressgroupings, false, false },
- { "signmessage", &signmessage, false, false },
- { "verifymessage", &verifymessage, false, false },
- { "getwork", &getwork, true, false },
- { "listaccounts", &listaccounts, false, false },
- { "settxfee", &settxfee, false, false },
- { "getblocktemplate", &getblocktemplate, true, false },
- { "submitblock", &submitblock, false, false },
- { "listsinceblock", &listsinceblock, false, false },
- { "dumpprivkey", &dumpprivkey, true, false },
- { "dumpwallet", &dumpwallet, true, false },
- { "importprivkey", &importprivkey, false, false },
- { "importwallet", &importwallet, false, false },
- { "listunspent", &listunspent, false, false },
- { "getrawtransaction", &getrawtransaction, false, false },
- { "createrawtransaction", &createrawtransaction, false, false },
- { "decoderawtransaction", &decoderawtransaction, false, false },
- { "decodescript", &decodescript, false, false },
- { "signrawtransaction", &signrawtransaction, false, false },
- { "sendrawtransaction", &sendrawtransaction, false, false },
- { "gettxoutsetinfo", &gettxoutsetinfo, true, false },
- { "gettxout", &gettxout, true, false },
- { "lockunspent", &lockunspent, false, false },
- { "listlockunspent", &listlockunspent, false, false },
- { "verifychain", &verifychain, true, false },
+{ // name actor (function) okSafeMode threadSafe reqWallet
+ // ------------------------ ----------------------- ---------- ---------- ---------
+ { "help", &help, true, true, false },
+ { "stop", &stop, true, true, false },
+ { "getblockcount", &getblockcount, true, false, false },
+ { "getbestblockhash", &getbestblockhash, true, false, false },
+ { "getconnectioncount", &getconnectioncount, true, false, false },
+ { "getpeerinfo", &getpeerinfo, true, false, false },
+ { "ping", &ping, true, false, false },
+ { "addnode", &addnode, true, true, false },
+ { "getaddednodeinfo", &getaddednodeinfo, true, true, false },
+ { "getnettotals", &getnettotals, true, true, false },
+ { "getdifficulty", &getdifficulty, true, false, false },
+ { "getnetworkhashps", &getnetworkhashps, true, false, false },
+ { "getgenerate", &getgenerate, true, false, false },
+ { "setgenerate", &setgenerate, true, false, true },
+ { "gethashespersec", &gethashespersec, true, false, false },
+ { "getinfo", &getinfo, true, false, false },
+ { "getmininginfo", &getmininginfo, true, false, false },
+ { "getnewaddress", &getnewaddress, true, false, true },
+ { "getaccountaddress", &getaccountaddress, true, false, true },
+ { "getrawchangeaddress", &getrawchangeaddress, true, false, true },
+ { "setaccount", &setaccount, true, false, true },
+ { "getaccount", &getaccount, false, false, true },
+ { "getaddressesbyaccount", &getaddressesbyaccount, true, false, true },
+ { "sendtoaddress", &sendtoaddress, false, false, true },
+ { "getreceivedbyaddress", &getreceivedbyaddress, false, false, true },
+ { "getreceivedbyaccount", &getreceivedbyaccount, false, false, true },
+ { "listreceivedbyaddress", &listreceivedbyaddress, false, false, true },
+ { "listreceivedbyaccount", &listreceivedbyaccount, false, false, true },
+ { "backupwallet", &backupwallet, true, false, true },
+ { "keypoolrefill", &keypoolrefill, true, false, true },
+ { "walletpassphrase", &walletpassphrase, true, false, true },
+ { "walletpassphrasechange", &walletpassphrasechange, false, false, true },
+ { "walletlock", &walletlock, true, false, true },
+ { "encryptwallet", &encryptwallet, false, false, true },
+ { "validateaddress", &validateaddress, true, false, false },
+ { "getbalance", &getbalance, false, false, true },
+ { "move", &movecmd, false, false, true },
+ { "sendfrom", &sendfrom, false, false, true },
+ { "sendmany", &sendmany, false, false, true },
+ { "addmultisigaddress", &addmultisigaddress, false, false, true },
+ { "createmultisig", &createmultisig, true, true , false },
+ { "getrawmempool", &getrawmempool, true, false, false },
+ { "getblock", &getblock, false, false, false },
+ { "getblockhash", &getblockhash, false, false, false },
+ { "gettransaction", &gettransaction, false, false, true },
+ { "listtransactions", &listtransactions, false, false, true },
+ { "listaddressgroupings", &listaddressgroupings, false, false, true },
+ { "signmessage", &signmessage, false, false, true },
+ { "verifymessage", &verifymessage, false, false, false },
+ { "getwork", &getwork, true, false, true },
+ { "listaccounts", &listaccounts, false, false, true },
+ { "settxfee", &settxfee, false, false, true },
+ { "getblocktemplate", &getblocktemplate, true, false, false },
+ { "submitblock", &submitblock, false, false, false },
+ { "listsinceblock", &listsinceblock, false, false, true },
+ { "dumpprivkey", &dumpprivkey, true, false, true },
+ { "dumpwallet", &dumpwallet, true, false, true },
+ { "importprivkey", &importprivkey, false, false, true },
+ { "importwallet", &importwallet, false, false, true },
+ { "listunspent", &listunspent, false, false, true },
+ { "getrawtransaction", &getrawtransaction, false, false, false },
+ { "createrawtransaction", &createrawtransaction, false, false, false },
+ { "decoderawtransaction", &decoderawtransaction, false, false, false },
+ { "decodescript", &decodescript, false, false, false },
+ { "signrawtransaction", &signrawtransaction, false, false, false },
+ { "sendrawtransaction", &sendrawtransaction, false, false, false },
+ { "gettxoutsetinfo", &gettxoutsetinfo, true, false, false },
+ { "gettxout", &gettxout, true, false, false },
+ { "lockunspent", &lockunspent, false, false, true },
+ { "listlockunspent", &listlockunspent, false, false, true },
+ { "verifychain", &verifychain, true, false, false },
};
CRPCTable::CRPCTable()
@@ -876,7 +882,8 @@ void StopRPCThreads()
deadlineTimers.clear();
rpc_io_service->stop();
- rpc_worker_group->join_all();
+ if (rpc_worker_group != NULL)
+ rpc_worker_group->join_all();
delete rpc_worker_group; rpc_worker_group = NULL;
delete rpc_ssl_context; rpc_ssl_context = NULL;
delete rpc_io_service; rpc_io_service = NULL;
@@ -1007,8 +1014,8 @@ void ServiceConnection(AcceptedConnection *conn)
{
LogPrintf("ThreadRPCServer incorrect password attempt from %s\n", conn->peer_address_to_string().c_str());
/* Deter brute-forcing short passwords.
- If this results in a DOS the user really
- shouldn't have their RPC port exposed.*/
+ If this results in a DoS the user really
+ shouldn't have their RPC port exposed. */
if (mapArgs["-rpcpassword"].size() < 20)
MilliSleep(250);
@@ -1064,6 +1071,8 @@ json_spirit::Value CRPCTable::execute(const std::string &strMethod, const json_s
const CRPCCommand *pcmd = tableRPC[strMethod];
if (!pcmd)
throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found");
+ if (pcmd->reqWallet && !pwalletMain)
+ throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found (disabled)");
// Observe safe mode
string strWarning = GetWarnings("rpc");
@@ -1078,7 +1087,10 @@ json_spirit::Value CRPCTable::execute(const std::string &strMethod, const json_s
{
if (pcmd->threadSafe)
result = pcmd->actor(params, false);
- else {
+ else if (!pwalletMain) {
+ LOCK(cs_main);
+ result = pcmd->actor(params, false);
+ } else {
LOCK2(cs_main, pwalletMain->cs_wallet);
result = pcmd->actor(params, false);
}
@@ -1188,6 +1200,8 @@ Array RPCConvertValues(const std::string &strMethod, const std::vector<std::stri
if (strMethod == "getaddednodeinfo" && n > 0) ConvertTo<bool>(params[0]);
if (strMethod == "setgenerate" && n > 0) ConvertTo<bool>(params[0]);
if (strMethod == "setgenerate" && n > 1) ConvertTo<boost::int64_t>(params[1]);
+ if (strMethod == "getnetworkhashps" && n > 0) ConvertTo<boost::int64_t>(params[0]);
+ if (strMethod == "getnetworkhashps" && n > 1) ConvertTo<boost::int64_t>(params[1]);
if (strMethod == "sendtoaddress" && n > 1) ConvertTo<double>(params[1]);
if (strMethod == "settxfee" && n > 0) ConvertTo<double>(params[0]);
if (strMethod == "getreceivedbyaddress" && n > 1) ConvertTo<boost::int64_t>(params[1]);
diff --git a/src/bitcoinrpc.h b/src/bitcoinrpc.h
index ab0a0bc968..1cad12f14a 100644
--- a/src/bitcoinrpc.h
+++ b/src/bitcoinrpc.h
@@ -104,6 +104,7 @@ public:
rpcfn_type actor;
bool okSafeMode;
bool threadSafe;
+ bool reqWallet;
};
/**
@@ -152,8 +153,10 @@ extern void EnsureWalletIsUnlocked();
extern json_spirit::Value getconnectioncount(const json_spirit::Array& params, bool fHelp); // in rpcnet.cpp
extern json_spirit::Value getpeerinfo(const json_spirit::Array& params, bool fHelp);
+extern json_spirit::Value ping(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value addnode(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value getaddednodeinfo(const json_spirit::Array& params, bool fHelp);
+extern json_spirit::Value getnettotals(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value dumpprivkey(const json_spirit::Array& params, bool fHelp); // in rpcdump.cpp
extern json_spirit::Value importprivkey(const json_spirit::Array& params, bool fHelp);
@@ -162,6 +165,7 @@ extern json_spirit::Value importwallet(const json_spirit::Array& params, bool fH
extern json_spirit::Value getgenerate(const json_spirit::Array& params, bool fHelp); // in rpcmining.cpp
extern json_spirit::Value setgenerate(const json_spirit::Array& params, bool fHelp);
+extern json_spirit::Value getnetworkhashps(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value gethashespersec(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value getmininginfo(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value getwork(const json_spirit::Array& params, bool fHelp);
diff --git a/src/chainparams.h b/src/chainparams.h
index ce3c14306d..3f99b7eb06 100644
--- a/src/chainparams.h
+++ b/src/chainparams.h
@@ -68,7 +68,7 @@ public:
virtual const vector<CAddress>& FixedSeeds() const = 0;
int RPCPort() const { return nRPCPort; }
protected:
- CChainParams() {};
+ CChainParams() {}
uint256 hashGenesisBlock;
MessageStartChars pchMessageStart;
diff --git a/src/compat.h b/src/compat.h
index 9caf5e4810..b126df901a 100644
--- a/src/compat.h
+++ b/src/compat.h
@@ -6,11 +6,17 @@
#define _BITCOIN_COMPAT_H
#ifdef WIN32
+#ifdef _WIN32_WINNT
+#undef _WIN32_WINNT
+#endif
#define _WIN32_WINNT 0x0501
#define WIN32_LEAN_AND_MEAN 1
#ifndef NOMINMAX
#define NOMINMAX
#endif
+#ifdef FD_SETSIZE
+#undef FD_SETSIZE // prevent redefinition compiler warning
+#endif
#define FD_SETSIZE 1024 // max number of fds in fd_set
#include <winsock2.h>
#include <ws2tcpip.h>
diff --git a/src/core.h b/src/core.h
index ce21acd59e..9ee8b2edce 100644
--- a/src/core.h
+++ b/src/core.h
@@ -661,4 +661,38 @@ public:
void print() const;
};
+
+/** Describes a place in the block chain to another node such that if the
+ * other node doesn't have the same branch, it can find a recent common trunk.
+ * The further back it is, the further before the fork it may be.
+ */
+struct CBlockLocator
+{
+ std::vector<uint256> vHave;
+
+ CBlockLocator() {}
+
+ CBlockLocator(const std::vector<uint256>& vHaveIn)
+ {
+ vHave = vHaveIn;
+ }
+
+ IMPLEMENT_SERIALIZE
+ (
+ if (!(nType & SER_GETHASH))
+ READWRITE(nVersion);
+ READWRITE(vHave);
+ )
+
+ void SetNull()
+ {
+ vHave.clear();
+ }
+
+ bool IsNull()
+ {
+ return vHave.empty();
+ }
+};
+
#endif
diff --git a/src/db.h b/src/db.h
index b3f269f3da..8736031da4 100644
--- a/src/db.h
+++ b/src/db.h
@@ -16,7 +16,7 @@
#include <db_cxx.h>
class CAddrMan;
-class CBlockLocator;
+struct CBlockLocator;
class CDiskBlockIndex;
class CMasterKey;
class COutPoint;
diff --git a/src/init.cpp b/src/init.cpp
index fb03e7b663..fce5992255 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -100,6 +100,7 @@ static CCoinsViewDB *pcoinsdbview;
void Shutdown()
{
+ LogPrintf("Shutdown : In progress...\n");
static CCriticalSection cs_Shutdown;
TRY_LOCK(cs_Shutdown, lockShutdown);
if (!lockShutdown) return;
@@ -108,13 +109,14 @@ void Shutdown()
nTransactionsUpdated++;
StopRPCThreads();
ShutdownRPCMining();
- bitdb.Flush(false);
+ if (pwalletMain)
+ bitdb.Flush(false);
GenerateBitcoins(false, NULL);
StopNode();
{
LOCK(cs_main);
if (pwalletMain)
- pwalletMain->SetBestChain(CBlockLocator(pindexBest));
+ pwalletMain->SetBestChain(chainActive.GetLocator());
if (pblocktree)
pblocktree->Flush();
if (pcoinsTip)
@@ -123,10 +125,13 @@ void Shutdown()
delete pcoinsdbview; pcoinsdbview = NULL;
delete pblocktree; pblocktree = NULL;
}
- bitdb.Flush(true);
+ if (pwalletMain)
+ bitdb.Flush(true);
boost::filesystem::remove(GetPidFile());
UnregisterAllWallets();
- delete pwalletMain;
+ if (pwalletMain)
+ delete pwalletMain;
+ LogPrintf("Shutdown : done\n");
}
//
@@ -339,8 +344,8 @@ bool AppInit2(boost::thread_group& threadGroup)
// Minimum supported OS versions: WinXP SP3, WinVista >= SP1, Win Server 2008
// A failure is non-critical and needs no further attention!
#ifndef PROCESS_DEP_ENABLE
-// We define this here, because GCCs winbase.h limits this to _WIN32_WINNT >= 0x0601 (Windows 7),
-// which is not correct. Can be removed, when GCCs winbase.h is fixed!
+ // We define this here, because GCCs winbase.h limits this to _WIN32_WINNT >= 0x0601 (Windows 7),
+ // which is not correct. Can be removed, when GCCs winbase.h is fixed!
#define PROCESS_DEP_ENABLE 0x00000001
#endif
typedef BOOL (WINAPI *PSETPROCDEPPOL)(DWORD);
@@ -761,7 +766,7 @@ bool AppInit2(boost::thread_group& threadGroup)
// If the loaded chain has a wrong genesis, bail out immediately
// (we're likely using a testnet datadir, or the other way around).
- if (!mapBlockIndex.empty() && pindexGenesisBlock == NULL)
+ if (!mapBlockIndex.empty() && chainActive.Genesis() == NULL)
return InitError(_("Incorrect or no genesis block found. Wrong datadir for network?"));
// Initialize the block index (no-op if non-empty database was already loaded)
@@ -907,7 +912,7 @@ bool AppInit2(boost::thread_group& threadGroup)
strErrors << _("Cannot write default address") << "\n";
}
- pwalletMain->SetBestChain(CBlockLocator(pindexBest));
+ pwalletMain->SetBestChain(chainActive.GetLocator());
}
LogPrintf("%s", strErrors.str().c_str());
@@ -915,26 +920,26 @@ bool AppInit2(boost::thread_group& threadGroup)
RegisterWallet(pwalletMain);
- CBlockIndex *pindexRescan = pindexBest;
+ CBlockIndex *pindexRescan = chainActive.Tip();
if (GetBoolArg("-rescan", false))
- pindexRescan = pindexGenesisBlock;
+ pindexRescan = chainActive.Genesis();
else
{
CWalletDB walletdb(strWalletFile);
CBlockLocator locator;
if (walletdb.ReadBestBlock(locator))
- pindexRescan = locator.GetBlockIndex();
+ pindexRescan = chainActive.FindFork(locator);
else
- pindexRescan = pindexGenesisBlock;
+ pindexRescan = chainActive.Genesis();
}
- if (pindexBest && pindexBest != pindexRescan)
+ if (chainActive.Tip() && chainActive.Tip() != pindexRescan)
{
uiInterface.InitMessage(_("Rescanning..."));
- LogPrintf("Rescanning last %i blocks (from block %i)...\n", pindexBest->nHeight - pindexRescan->nHeight, pindexRescan->nHeight);
+ LogPrintf("Rescanning last %i blocks (from block %i)...\n", chainActive.Height() - pindexRescan->nHeight, pindexRescan->nHeight);
nStart = GetTimeMillis();
pwalletMain->ScanForWalletTransactions(pindexRescan, true);
LogPrintf(" rescan %15"PRI64d"ms\n", GetTimeMillis() - nStart);
- pwalletMain->SetBestChain(CBlockLocator(pindexBest));
+ pwalletMain->SetBestChain(chainActive.GetLocator());
nWalletDBUpdated++;
}
@@ -980,10 +985,10 @@ bool AppInit2(boost::thread_group& threadGroup)
//// debug print
LogPrintf("mapBlockIndex.size() = %"PRIszu"\n", mapBlockIndex.size());
- LogPrintf("nBestHeight = %d\n", nBestHeight);
- LogPrintf("setKeyPool.size() = %"PRIszu"\n", pwalletMain->setKeyPool.size());
- LogPrintf("mapWallet.size() = %"PRIszu"\n", pwalletMain->mapWallet.size());
- LogPrintf("mapAddressBook.size() = %"PRIszu"\n", pwalletMain->mapAddressBook.size());
+ LogPrintf("nBestHeight = %d\n", chainActive.Height());
+ LogPrintf("setKeyPool.size() = %"PRIszu"\n", pwalletMain ? pwalletMain->setKeyPool.size() : 0);
+ LogPrintf("mapWallet.size() = %"PRIszu"\n", pwalletMain ? pwalletMain->mapWallet.size() : 0);
+ LogPrintf("mapAddressBook.size() = %"PRIszu"\n", pwalletMain ? pwalletMain->mapAddressBook.size() : 0);
StartNode(threadGroup);
@@ -993,17 +998,20 @@ bool AppInit2(boost::thread_group& threadGroup)
StartRPCThreads();
// Generate coins in the background
- GenerateBitcoins(GetBoolArg("-gen", false), pwalletMain);
+ if (pwalletMain)
+ GenerateBitcoins(GetBoolArg("-gen", false), pwalletMain);
// ********************************************************* Step 12: finished
uiInterface.InitMessage(_("Done loading"));
- // Add wallet transactions that aren't already in a block to mapTransactions
- pwalletMain->ReacceptWalletTransactions();
+ if (pwalletMain) {
+ // Add wallet transactions that aren't already in a block to mapTransactions
+ pwalletMain->ReacceptWalletTransactions();
- // Run a thread to flush wallet periodically
- threadGroup.create_thread(boost::bind(&ThreadFlushWalletDB, boost::ref(pwalletMain->strWalletFile)));
+ // Run a thread to flush wallet periodically
+ threadGroup.create_thread(boost::bind(&ThreadFlushWalletDB, boost::ref(pwalletMain->strWalletFile)));
+ }
return !fRequestShutdown;
}
diff --git a/src/leveldb/Makefile b/src/leveldb/Makefile
index 96af7765be..20c9c4f287 100644
--- a/src/leveldb/Makefile
+++ b/src/leveldb/Makefile
@@ -31,6 +31,7 @@ TESTHARNESS = ./util/testharness.o $(TESTUTIL)
TESTS = \
arena_test \
+ autocompact_test \
bloom_test \
c_test \
cache_test \
@@ -70,7 +71,7 @@ SHARED = $(SHARED1)
else
# Update db.h if you change these.
SHARED_MAJOR = 1
-SHARED_MINOR = 12
+SHARED_MINOR = 13
SHARED1 = libleveldb.$(PLATFORM_SHARED_EXT)
SHARED2 = $(SHARED1).$(SHARED_MAJOR)
SHARED3 = $(SHARED1).$(SHARED_MAJOR).$(SHARED_MINOR)
@@ -114,6 +115,9 @@ leveldbutil: db/leveldb_main.o $(LIBOBJECTS)
arena_test: util/arena_test.o $(LIBOBJECTS) $(TESTHARNESS)
$(CXX) $(LDFLAGS) util/arena_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS)
+autocompact_test: db/autocompact_test.o $(LIBOBJECTS) $(TESTHARNESS)
+ $(CXX) $(LDFLAGS) db/autocompact_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS)
+
bloom_test: util/bloom_test.o $(LIBOBJECTS) $(TESTHARNESS)
$(CXX) $(LDFLAGS) util/bloom_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS)
diff --git a/src/leveldb/db/autocompact_test.cc b/src/leveldb/db/autocompact_test.cc
new file mode 100644
index 0000000000..d20a2362c3
--- /dev/null
+++ b/src/leveldb/db/autocompact_test.cc
@@ -0,0 +1,118 @@
+// Copyright (c) 2013 The LevelDB Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file. See the AUTHORS file for names of contributors.
+
+#include "leveldb/db.h"
+#include "db/db_impl.h"
+#include "leveldb/cache.h"
+#include "util/testharness.h"
+#include "util/testutil.h"
+
+namespace leveldb {
+
+class AutoCompactTest {
+ public:
+ std::string dbname_;
+ Cache* tiny_cache_;
+ Options options_;
+ DB* db_;
+
+ AutoCompactTest() {
+ dbname_ = test::TmpDir() + "/autocompact_test";
+ tiny_cache_ = NewLRUCache(100);
+ options_.block_cache = tiny_cache_;
+ DestroyDB(dbname_, options_);
+ options_.create_if_missing = true;
+ options_.compression = kNoCompression;
+ ASSERT_OK(DB::Open(options_, dbname_, &db_));
+ }
+
+ ~AutoCompactTest() {
+ delete db_;
+ DestroyDB(dbname_, Options());
+ delete tiny_cache_;
+ }
+
+ std::string Key(int i) {
+ char buf[100];
+ snprintf(buf, sizeof(buf), "key%06d", i);
+ return std::string(buf);
+ }
+
+ uint64_t Size(const Slice& start, const Slice& limit) {
+ Range r(start, limit);
+ uint64_t size;
+ db_->GetApproximateSizes(&r, 1, &size);
+ return size;
+ }
+
+ void DoReads(int n);
+};
+
+static const int kValueSize = 200 * 1024;
+static const int kTotalSize = 100 * 1024 * 1024;
+static const int kCount = kTotalSize / kValueSize;
+
+// Read through the first n keys repeatedly and check that they get
+// compacted (verified by checking the size of the key space).
+void AutoCompactTest::DoReads(int n) {
+ std::string value(kValueSize, 'x');
+ DBImpl* dbi = reinterpret_cast<DBImpl*>(db_);
+
+ // Fill database
+ for (int i = 0; i < kCount; i++) {
+ ASSERT_OK(db_->Put(WriteOptions(), Key(i), value));
+ }
+ ASSERT_OK(dbi->TEST_CompactMemTable());
+
+ // Delete everything
+ for (int i = 0; i < kCount; i++) {
+ ASSERT_OK(db_->Delete(WriteOptions(), Key(i)));
+ }
+ ASSERT_OK(dbi->TEST_CompactMemTable());
+
+ // Get initial measurement of the space we will be reading.
+ const int64_t initial_size = Size(Key(0), Key(n));
+ const int64_t initial_other_size = Size(Key(n), Key(kCount));
+
+ // Read until size drops significantly.
+ std::string limit_key = Key(n);
+ for (int read = 0; true; read++) {
+ ASSERT_LT(read, 100) << "Taking too long to compact";
+ Iterator* iter = db_->NewIterator(ReadOptions());
+ for (iter->SeekToFirst();
+ iter->Valid() && iter->key().ToString() < limit_key;
+ iter->Next()) {
+ // Drop data
+ }
+ delete iter;
+ // Wait a little bit to allow any triggered compactions to complete.
+ Env::Default()->SleepForMicroseconds(1000000);
+ uint64_t size = Size(Key(0), Key(n));
+ fprintf(stderr, "iter %3d => %7.3f MB [other %7.3f MB]\n",
+ read+1, size/1048576.0, Size(Key(n), Key(kCount))/1048576.0);
+ if (size <= initial_size/10) {
+ break;
+ }
+ }
+
+ // Verify that the size of the key space not touched by the reads
+ // is pretty much unchanged.
+ const int64_t final_other_size = Size(Key(n), Key(kCount));
+ ASSERT_LE(final_other_size, initial_other_size + 1048576);
+ ASSERT_GE(final_other_size, initial_other_size/5 - 1048576);
+}
+
+TEST(AutoCompactTest, ReadAll) {
+ DoReads(kCount);
+}
+
+TEST(AutoCompactTest, ReadHalf) {
+ DoReads(kCount/2);
+}
+
+} // namespace leveldb
+
+int main(int argc, char** argv) {
+ return leveldb::test::RunAllTests();
+}
diff --git a/src/leveldb/db/corruption_test.cc b/src/leveldb/db/corruption_test.cc
index 31b2d5f416..b37ffdfe64 100644
--- a/src/leveldb/db/corruption_test.cc
+++ b/src/leveldb/db/corruption_test.cc
@@ -35,6 +35,7 @@ class CorruptionTest {
CorruptionTest() {
tiny_cache_ = NewLRUCache(100);
options_.env = &env_;
+ options_.block_cache = tiny_cache_;
dbname_ = test::TmpDir() + "/db_test";
DestroyDB(dbname_, options_);
@@ -50,17 +51,14 @@ class CorruptionTest {
delete tiny_cache_;
}
- Status TryReopen(Options* options = NULL) {
+ Status TryReopen() {
delete db_;
db_ = NULL;
- Options opt = (options ? *options : options_);
- opt.env = &env_;
- opt.block_cache = tiny_cache_;
- return DB::Open(opt, dbname_, &db_);
+ return DB::Open(options_, dbname_, &db_);
}
- void Reopen(Options* options = NULL) {
- ASSERT_OK(TryReopen(options));
+ void Reopen() {
+ ASSERT_OK(TryReopen());
}
void RepairDB() {
@@ -92,6 +90,10 @@ class CorruptionTest {
for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {
uint64_t key;
Slice in(iter->key());
+ if (in == "" || in == "~") {
+ // Ignore boundary keys.
+ continue;
+ }
if (!ConsumeDecimalNumber(&in, &key) ||
!in.empty() ||
key < next_expected) {
@@ -233,7 +235,7 @@ TEST(CorruptionTest, TableFile) {
dbi->TEST_CompactRange(1, NULL, NULL);
Corrupt(kTableFile, 100, 1);
- Check(99, 99);
+ Check(90, 99);
}
TEST(CorruptionTest, TableFileIndexData) {
@@ -299,7 +301,7 @@ TEST(CorruptionTest, CompactionInputError) {
ASSERT_EQ(1, Property("leveldb.num-files-at-level" + NumberToString(last)));
Corrupt(kTableFile, 100, 1);
- Check(9, 9);
+ Check(5, 9);
// Force compactions by writing lots of values
Build(10000);
@@ -307,32 +309,23 @@ TEST(CorruptionTest, CompactionInputError) {
}
TEST(CorruptionTest, CompactionInputErrorParanoid) {
- Options options;
- options.paranoid_checks = true;
- options.write_buffer_size = 1048576;
- Reopen(&options);
+ options_.paranoid_checks = true;
+ options_.write_buffer_size = 512 << 10;
+ Reopen();
DBImpl* dbi = reinterpret_cast<DBImpl*>(db_);
- // Fill levels >= 1 so memtable compaction outputs to level 1
- for (int level = 1; level < config::kNumLevels; level++) {
- dbi->Put(WriteOptions(), "", "begin");
- dbi->Put(WriteOptions(), "~", "end");
+ // Make multiple inputs so we need to compact.
+ for (int i = 0; i < 2; i++) {
+ Build(10);
dbi->TEST_CompactMemTable();
+ Corrupt(kTableFile, 100, 1);
+ env_.SleepForMicroseconds(100000);
}
+ dbi->CompactRange(NULL, NULL);
- Build(10);
- dbi->TEST_CompactMemTable();
- ASSERT_EQ(1, Property("leveldb.num-files-at-level0"));
-
- Corrupt(kTableFile, 100, 1);
- Check(9, 9);
-
- // Write must eventually fail because of corrupted table
- Status s;
+ // Write must fail because of corrupted table
std::string tmp1, tmp2;
- for (int i = 0; i < 10000 && s.ok(); i++) {
- s = db_->Put(WriteOptions(), Key(i, &tmp1), Value(i, &tmp2));
- }
+ Status s = db_->Put(WriteOptions(), Key(5, &tmp1), Value(5, &tmp2));
ASSERT_TRUE(!s.ok()) << "write did not fail in corrupted paranoid db";
}
diff --git a/src/leveldb/db/db_impl.cc b/src/leveldb/db/db_impl.cc
index 395d3172ad..fa1351038b 100644
--- a/src/leveldb/db/db_impl.cc
+++ b/src/leveldb/db/db_impl.cc
@@ -113,14 +113,14 @@ Options SanitizeOptions(const std::string& dbname,
return result;
}
-DBImpl::DBImpl(const Options& options, const std::string& dbname)
- : env_(options.env),
- internal_comparator_(options.comparator),
- internal_filter_policy_(options.filter_policy),
- options_(SanitizeOptions(
- dbname, &internal_comparator_, &internal_filter_policy_, options)),
- owns_info_log_(options_.info_log != options.info_log),
- owns_cache_(options_.block_cache != options.block_cache),
+DBImpl::DBImpl(const Options& raw_options, const std::string& dbname)
+ : env_(raw_options.env),
+ internal_comparator_(raw_options.comparator),
+ internal_filter_policy_(raw_options.filter_policy),
+ options_(SanitizeOptions(dbname, &internal_comparator_,
+ &internal_filter_policy_, raw_options)),
+ owns_info_log_(options_.info_log != raw_options.info_log),
+ owns_cache_(options_.block_cache != raw_options.block_cache),
dbname_(dbname),
db_lock_(NULL),
shutting_down_(NULL),
@@ -130,6 +130,7 @@ DBImpl::DBImpl(const Options& options, const std::string& dbname)
logfile_(NULL),
logfile_number_(0),
log_(NULL),
+ seed_(0),
tmp_batch_(new WriteBatch),
bg_compaction_scheduled_(false),
manual_compaction_(NULL),
@@ -138,7 +139,7 @@ DBImpl::DBImpl(const Options& options, const std::string& dbname)
has_imm_.Release_Store(NULL);
// Reserve ten files or so for other uses and give the rest to TableCache.
- const int table_cache_size = options.max_open_files - kNumNonTableCacheFiles;
+ const int table_cache_size = options_.max_open_files - kNumNonTableCacheFiles;
table_cache_ = new TableCache(dbname_, &options_, table_cache_size);
versions_ = new VersionSet(dbname_, &options_, table_cache_,
@@ -1027,7 +1028,8 @@ static void CleanupIteratorState(void* arg1, void* arg2) {
} // namespace
Iterator* DBImpl::NewInternalIterator(const ReadOptions& options,
- SequenceNumber* latest_snapshot) {
+ SequenceNumber* latest_snapshot,
+ uint32_t* seed) {
IterState* cleanup = new IterState;
mutex_.Lock();
*latest_snapshot = versions_->LastSequence();
@@ -1051,13 +1053,15 @@ Iterator* DBImpl::NewInternalIterator(const ReadOptions& options,
cleanup->version = versions_->current();
internal_iter->RegisterCleanup(CleanupIteratorState, cleanup, NULL);
+ *seed = ++seed_;
mutex_.Unlock();
return internal_iter;
}
Iterator* DBImpl::TEST_NewInternalIterator() {
SequenceNumber ignored;
- return NewInternalIterator(ReadOptions(), &ignored);
+ uint32_t ignored_seed;
+ return NewInternalIterator(ReadOptions(), &ignored, &ignored_seed);
}
int64_t DBImpl::TEST_MaxNextLevelOverlappingBytes() {
@@ -1114,12 +1118,21 @@ Status DBImpl::Get(const ReadOptions& options,
Iterator* DBImpl::NewIterator(const ReadOptions& options) {
SequenceNumber latest_snapshot;
- Iterator* internal_iter = NewInternalIterator(options, &latest_snapshot);
+ uint32_t seed;
+ Iterator* iter = NewInternalIterator(options, &latest_snapshot, &seed);
return NewDBIterator(
- &dbname_, env_, user_comparator(), internal_iter,
+ this, user_comparator(), iter,
(options.snapshot != NULL
? reinterpret_cast<const SnapshotImpl*>(options.snapshot)->number_
- : latest_snapshot));
+ : latest_snapshot),
+ seed);
+}
+
+void DBImpl::RecordReadSample(Slice key) {
+ MutexLock l(&mutex_);
+ if (versions_->current()->RecordReadSample(key)) {
+ MaybeScheduleCompaction();
+ }
}
const Snapshot* DBImpl::GetSnapshot() {
diff --git a/src/leveldb/db/db_impl.h b/src/leveldb/db/db_impl.h
index 3c8d711ae0..75fd30abe9 100644
--- a/src/leveldb/db/db_impl.h
+++ b/src/leveldb/db/db_impl.h
@@ -59,13 +59,19 @@ class DBImpl : public DB {
// file at a level >= 1.
int64_t TEST_MaxNextLevelOverlappingBytes();
+ // Record a sample of bytes read at the specified internal key.
+ // Samples are taken approximately once every config::kReadBytesPeriod
+ // bytes.
+ void RecordReadSample(Slice key);
+
private:
friend class DB;
struct CompactionState;
struct Writer;
Iterator* NewInternalIterator(const ReadOptions&,
- SequenceNumber* latest_snapshot);
+ SequenceNumber* latest_snapshot,
+ uint32_t* seed);
Status NewDB();
@@ -135,6 +141,7 @@ class DBImpl : public DB {
WritableFile* logfile_;
uint64_t logfile_number_;
log::Writer* log_;
+ uint32_t seed_; // For sampling.
// Queue of writers.
std::deque<Writer*> writers_;
diff --git a/src/leveldb/db/db_iter.cc b/src/leveldb/db/db_iter.cc
index 87dca2ded4..071a54e3f4 100644
--- a/src/leveldb/db/db_iter.cc
+++ b/src/leveldb/db/db_iter.cc
@@ -5,12 +5,14 @@
#include "db/db_iter.h"
#include "db/filename.h"
+#include "db/db_impl.h"
#include "db/dbformat.h"
#include "leveldb/env.h"
#include "leveldb/iterator.h"
#include "port/port.h"
#include "util/logging.h"
#include "util/mutexlock.h"
+#include "util/random.h"
namespace leveldb {
@@ -46,15 +48,16 @@ class DBIter: public Iterator {
kReverse
};
- DBIter(const std::string* dbname, Env* env,
- const Comparator* cmp, Iterator* iter, SequenceNumber s)
- : dbname_(dbname),
- env_(env),
+ DBIter(DBImpl* db, const Comparator* cmp, Iterator* iter, SequenceNumber s,
+ uint32_t seed)
+ : db_(db),
user_comparator_(cmp),
iter_(iter),
sequence_(s),
direction_(kForward),
- valid_(false) {
+ valid_(false),
+ rnd_(seed),
+ bytes_counter_(RandomPeriod()) {
}
virtual ~DBIter() {
delete iter_;
@@ -100,8 +103,12 @@ class DBIter: public Iterator {
}
}
- const std::string* const dbname_;
- Env* const env_;
+ // Pick next gap with average value of config::kReadBytesPeriod.
+ ssize_t RandomPeriod() {
+ return rnd_.Uniform(2*config::kReadBytesPeriod);
+ }
+
+ DBImpl* db_;
const Comparator* const user_comparator_;
Iterator* const iter_;
SequenceNumber const sequence_;
@@ -112,13 +119,23 @@ class DBIter: public Iterator {
Direction direction_;
bool valid_;
+ Random rnd_;
+ ssize_t bytes_counter_;
+
// No copying allowed
DBIter(const DBIter&);
void operator=(const DBIter&);
};
inline bool DBIter::ParseKey(ParsedInternalKey* ikey) {
- if (!ParseInternalKey(iter_->key(), ikey)) {
+ Slice k = iter_->key();
+ ssize_t n = k.size() + iter_->value().size();
+ bytes_counter_ -= n;
+ while (bytes_counter_ < 0) {
+ bytes_counter_ += RandomPeriod();
+ db_->RecordReadSample(k);
+ }
+ if (!ParseInternalKey(k, ikey)) {
status_ = Status::Corruption("corrupted internal key in DBIter");
return false;
} else {
@@ -288,12 +305,12 @@ void DBIter::SeekToLast() {
} // anonymous namespace
Iterator* NewDBIterator(
- const std::string* dbname,
- Env* env,
+ DBImpl* db,
const Comparator* user_key_comparator,
Iterator* internal_iter,
- const SequenceNumber& sequence) {
- return new DBIter(dbname, env, user_key_comparator, internal_iter, sequence);
+ SequenceNumber sequence,
+ uint32_t seed) {
+ return new DBIter(db, user_key_comparator, internal_iter, sequence, seed);
}
} // namespace leveldb
diff --git a/src/leveldb/db/db_iter.h b/src/leveldb/db/db_iter.h
index d9e1b174ab..04927e937b 100644
--- a/src/leveldb/db/db_iter.h
+++ b/src/leveldb/db/db_iter.h
@@ -11,15 +11,17 @@
namespace leveldb {
+class DBImpl;
+
// Return a new iterator that converts internal keys (yielded by
// "*internal_iter") that were live at the specified "sequence" number
// into appropriate user keys.
extern Iterator* NewDBIterator(
- const std::string* dbname,
- Env* env,
+ DBImpl* db,
const Comparator* user_key_comparator,
Iterator* internal_iter,
- const SequenceNumber& sequence);
+ SequenceNumber sequence,
+ uint32_t seed);
} // namespace leveldb
diff --git a/src/leveldb/db/dbformat.h b/src/leveldb/db/dbformat.h
index f7f64dafb6..5d8a032bd3 100644
--- a/src/leveldb/db/dbformat.h
+++ b/src/leveldb/db/dbformat.h
@@ -38,6 +38,9 @@ static const int kL0_StopWritesTrigger = 12;
// space if the same key space is being repeatedly overwritten.
static const int kMaxMemCompactLevel = 2;
+// Approximate gap in bytes between samples of data read during iteration.
+static const int kReadBytesPeriod = 1048576;
+
} // namespace config
class InternalKey;
diff --git a/src/leveldb/db/version_set.cc b/src/leveldb/db/version_set.cc
index 4fd1ddef21..66d73be71f 100644
--- a/src/leveldb/db/version_set.cc
+++ b/src/leveldb/db/version_set.cc
@@ -289,6 +289,51 @@ static bool NewestFirst(FileMetaData* a, FileMetaData* b) {
return a->number > b->number;
}
+void Version::ForEachOverlapping(Slice user_key, Slice internal_key,
+ void* arg,
+ bool (*func)(void*, int, FileMetaData*)) {
+ // TODO(sanjay): Change Version::Get() to use this function.
+ const Comparator* ucmp = vset_->icmp_.user_comparator();
+
+ // Search level-0 in order from newest to oldest.
+ std::vector<FileMetaData*> tmp;
+ tmp.reserve(files_[0].size());
+ for (uint32_t i = 0; i < files_[0].size(); i++) {
+ FileMetaData* f = files_[0][i];
+ if (ucmp->Compare(user_key, f->smallest.user_key()) >= 0 &&
+ ucmp->Compare(user_key, f->largest.user_key()) <= 0) {
+ tmp.push_back(f);
+ }
+ }
+ if (!tmp.empty()) {
+ std::sort(tmp.begin(), tmp.end(), NewestFirst);
+ for (uint32_t i = 0; i < tmp.size(); i++) {
+ if (!(*func)(arg, 0, tmp[i])) {
+ return;
+ }
+ }
+ }
+
+ // Search other levels.
+ for (int level = 1; level < config::kNumLevels; level++) {
+ size_t num_files = files_[level].size();
+ if (num_files == 0) continue;
+
+ // Binary search to find earliest index whose largest key >= internal_key.
+ uint32_t index = FindFile(vset_->icmp_, files_[level], internal_key);
+ if (index < num_files) {
+ FileMetaData* f = files_[level][index];
+ if (ucmp->Compare(user_key, f->smallest.user_key()) < 0) {
+ // All of "f" is past any data for user_key
+ } else {
+ if (!(*func)(arg, level, f)) {
+ return;
+ }
+ }
+ }
+ }
+}
+
Status Version::Get(const ReadOptions& options,
const LookupKey& k,
std::string* value,
@@ -401,6 +446,44 @@ bool Version::UpdateStats(const GetStats& stats) {
return false;
}
+bool Version::RecordReadSample(Slice internal_key) {
+ ParsedInternalKey ikey;
+ if (!ParseInternalKey(internal_key, &ikey)) {
+ return false;
+ }
+
+ struct State {
+ GetStats stats; // Holds first matching file
+ int matches;
+
+ static bool Match(void* arg, int level, FileMetaData* f) {
+ State* state = reinterpret_cast<State*>(arg);
+ state->matches++;
+ if (state->matches == 1) {
+ // Remember first match.
+ state->stats.seek_file = f;
+ state->stats.seek_file_level = level;
+ }
+ // We can stop iterating once we have a second match.
+ return state->matches < 2;
+ }
+ };
+
+ State state;
+ state.matches = 0;
+ ForEachOverlapping(ikey.user_key, internal_key, &state, &State::Match);
+
+ // Must have at least two matches since we want to merge across
+ // files. But what if we have a single file that contains many
+ // overwrites and deletions? Should we have another mechanism for
+ // finding such files?
+ if (state.matches >= 2) {
+ // 1MB cost is about 1 seek (see comment in Builder::Apply).
+ return UpdateStats(state.stats);
+ }
+ return false;
+}
+
void Version::Ref() {
++refs_;
}
@@ -435,10 +518,13 @@ int Version::PickLevelForMemTableOutput(
if (OverlapInLevel(level + 1, &smallest_user_key, &largest_user_key)) {
break;
}
- GetOverlappingInputs(level + 2, &start, &limit, &overlaps);
- const int64_t sum = TotalFileSize(overlaps);
- if (sum > kMaxGrandParentOverlapBytes) {
- break;
+ if (level + 2 < config::kNumLevels) {
+ // Check that file does not overlap too many grandparent bytes.
+ GetOverlappingInputs(level + 2, &start, &limit, &overlaps);
+ const int64_t sum = TotalFileSize(overlaps);
+ if (sum > kMaxGrandParentOverlapBytes) {
+ break;
+ }
}
level++;
}
@@ -452,6 +538,8 @@ void Version::GetOverlappingInputs(
const InternalKey* begin,
const InternalKey* end,
std::vector<FileMetaData*>* inputs) {
+ assert(level >= 0);
+ assert(level < config::kNumLevels);
inputs->clear();
Slice user_begin, user_end;
if (begin != NULL) {
diff --git a/src/leveldb/db/version_set.h b/src/leveldb/db/version_set.h
index 9d084fdb7d..20de0e2629 100644
--- a/src/leveldb/db/version_set.h
+++ b/src/leveldb/db/version_set.h
@@ -78,6 +78,12 @@ class Version {
// REQUIRES: lock is held
bool UpdateStats(const GetStats& stats);
+ // Record a sample of bytes read at the specified internal key.
+ // Samples are taken approximately once every config::kReadBytesPeriod
+ // bytes. Returns true if a new compaction may need to be triggered.
+ // REQUIRES: lock is held
+ bool RecordReadSample(Slice key);
+
// Reference count management (so Versions do not disappear out from
// under live iterators)
void Ref();
@@ -114,6 +120,15 @@ class Version {
class LevelFileNumIterator;
Iterator* NewConcatenatingIterator(const ReadOptions&, int level) const;
+ // Call func(arg, level, f) for every file that overlaps user_key in
+ // order from newest to oldest. If an invocation of func returns
+ // false, makes no more calls.
+ //
+ // REQUIRES: user portion of internal_key == user_key.
+ void ForEachOverlapping(Slice user_key, Slice internal_key,
+ void* arg,
+ bool (*func)(void*, int, FileMetaData*));
+
VersionSet* vset_; // VersionSet to which this Version belongs
Version* next_; // Next version in linked list
Version* prev_; // Previous version in linked list
diff --git a/src/leveldb/include/leveldb/db.h b/src/leveldb/include/leveldb/db.h
index da8b11a8c0..57c00a5da0 100644
--- a/src/leveldb/include/leveldb/db.h
+++ b/src/leveldb/include/leveldb/db.h
@@ -14,7 +14,7 @@ namespace leveldb {
// Update Makefile if you change these
static const int kMajorVersion = 1;
-static const int kMinorVersion = 12;
+static const int kMinorVersion = 13;
struct Options;
struct ReadOptions;
diff --git a/src/leveldb/util/env_posix.cc b/src/leveldb/util/env_posix.cc
index 6badfdc230..0f5dcfac5a 100644
--- a/src/leveldb/util/env_posix.cc
+++ b/src/leveldb/util/env_posix.cc
@@ -320,8 +320,39 @@ class PosixMmapFile : public WritableFile {
return Status::OK();
}
- virtual Status Sync() {
+ Status SyncDirIfManifest() {
+ const char* f = filename_.c_str();
+ const char* sep = strrchr(f, '/');
+ Slice basename;
+ std::string dir;
+ if (sep == NULL) {
+ dir = ".";
+ basename = f;
+ } else {
+ dir = std::string(f, sep - f);
+ basename = sep + 1;
+ }
Status s;
+ if (basename.starts_with("MANIFEST")) {
+ int fd = open(dir.c_str(), O_RDONLY);
+ if (fd < 0) {
+ s = IOError(dir, errno);
+ } else {
+ if (fsync(fd) < 0) {
+ s = IOError(dir, errno);
+ }
+ close(fd);
+ }
+ }
+ return s;
+ }
+
+ virtual Status Sync() {
+ // Ensure new files referred to by the manifest are in the filesystem.
+ Status s = SyncDirIfManifest();
+ if (!s.ok()) {
+ return s;
+ }
if (pending_sync_) {
// Some unmapped data was not synced
diff --git a/src/leveldb/util/random.h b/src/leveldb/util/random.h
index 07538242ea..ddd51b1c7b 100644
--- a/src/leveldb/util/random.h
+++ b/src/leveldb/util/random.h
@@ -16,7 +16,12 @@ class Random {
private:
uint32_t seed_;
public:
- explicit Random(uint32_t s) : seed_(s & 0x7fffffffu) { }
+ explicit Random(uint32_t s) : seed_(s & 0x7fffffffu) {
+ // Avoid bad seeds.
+ if (seed_ == 0 || seed_ == 2147483647L) {
+ seed_ = 1;
+ }
+ }
uint32_t Next() {
static const uint32_t M = 2147483647L; // 2^31-1
static const uint64_t A = 16807; // bits 14, 8, 7, 5, 2, 1, 0
diff --git a/src/m4/bitcoin_subdir_to_include.m4 b/src/m4/bitcoin_subdir_to_include.m4
index 9b37a75ef0..66f106c7d4 100644
--- a/src/m4/bitcoin_subdir_to_include.m4
+++ b/src/m4/bitcoin_subdir_to_include.m4
@@ -5,8 +5,10 @@ AC_DEFUN([BITCOIN_SUBDIR_TO_INCLUDE],[
AC_MSG_RESULT([default])
else
echo "#include <$2$3.h>" >conftest.cpp
- newinclpath=`${CXXCPP} -M conftest.cpp 2>/dev/null | [ tr -d '\\n\\r\\\\' | sed -e 's/^.*[[:space:]:]\(\/[^[:space:]]*\)]$3[\.h[[:space:]].*$/\1/' -e t -e d`]
+ newinclpath=`${CXXCPP} ${CPPFLAGS} -M conftest.cpp 2>/dev/null | [ tr -d '\\n\\r\\\\' | sed -e 's/^.*[[:space:]:]\(\/[^[:space:]]*\)]$3[\.h[[:space:]].*$/\1/' -e t -e d`]
AC_MSG_RESULT([${newinclpath}])
- eval "$1=\"\$$1\"' -I${newinclpath}'"
+ if test "x${newinclpath}" != "x"; then
+ eval "$1=\"\$$1\"' -I${newinclpath}'"
+ fi
fi
])
diff --git a/src/main.cpp b/src/main.cpp
index dc690111e6..215a7ba620 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -32,13 +32,8 @@ CTxMemPool mempool;
unsigned int nTransactionsUpdated = 0;
map<uint256, CBlockIndex*> mapBlockIndex;
-std::vector<CBlockIndex*> vBlockIndexByHeight;
-CBlockIndex* pindexGenesisBlock = NULL;
-int nBestHeight = -1;
-uint256 nBestChainWork = 0;
+CChain chainActive;
uint256 nBestInvalidWork = 0;
-uint256 hashBestChain = 0;
-CBlockIndex* pindexBest = NULL;
set<CBlockIndex*, CBlockIndexWorkComparator> setBlockIndexValid; // may contain all CBlockIndex*'s that have validness >=BLOCK_VALID_TRANSACTIONS, and must contain those who aren't failed
int64 nTimeBestReceived = 0;
int nScriptCheckThreads = 0;
@@ -173,106 +168,83 @@ void static ResendWalletTransactions()
// Registration of network node signals.
//
+int static GetHeight()
+{
+ LOCK(cs_main);
+ return chainActive.Height();
+}
+
void RegisterNodeSignals(CNodeSignals& nodeSignals)
{
+ nodeSignals.GetHeight.connect(&GetHeight);
nodeSignals.ProcessMessages.connect(&ProcessMessages);
nodeSignals.SendMessages.connect(&SendMessages);
}
void UnregisterNodeSignals(CNodeSignals& nodeSignals)
{
+ nodeSignals.GetHeight.disconnect(&GetHeight);
nodeSignals.ProcessMessages.disconnect(&ProcessMessages);
nodeSignals.SendMessages.disconnect(&SendMessages);
}
//////////////////////////////////////////////////////////////////////////////
//
-// CBlockLocator implementation
+// CChain implementation
//
-CBlockLocator::CBlockLocator(uint256 hashBlock)
-{
- std::map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock);
- if (mi != mapBlockIndex.end())
- Set((*mi).second);
+CBlockIndex *CChain::SetTip(CBlockIndex *pindex) {
+ if (pindex == NULL) {
+ vChain.clear();
+ return NULL;
+ }
+ vChain.resize(pindex->nHeight + 1);
+ while (pindex && vChain[pindex->nHeight] != pindex) {
+ vChain[pindex->nHeight] = pindex;
+ pindex = pindex->pprev;
+ }
+ return pindex;
}
-void CBlockLocator::Set(const CBlockIndex* pindex)
-{
- vHave.clear();
+CBlockLocator CChain::GetLocator(const CBlockIndex *pindex) const {
int nStep = 1;
- while (pindex)
- {
- vHave.push_back(pindex->GetBlockHash());
+ std::vector<uint256> vHave;
+ vHave.reserve(32);
- // Exponentially larger steps back
- for (int i = 0; pindex && i < nStep; i++)
+ if (!pindex)
+ pindex = Tip();
+ while (pindex) {
+ vHave.push_back(pindex->GetBlockHash());
+ // Stop when we have added the genesis block.
+ if (pindex->nHeight == 0)
+ break;
+ // Exponentially larger steps back, plus the genesis block.
+ int nHeight = std::max(pindex->nHeight - nStep, 0);
+ // In case pindex is not in this chain, iterate pindex->pprev to find blocks.
+ while (pindex->nHeight > nHeight && !Contains(pindex))
pindex = pindex->pprev;
+ // If pindex is in this chain, use direct height-based access.
+ if (pindex->nHeight > nHeight)
+ pindex = (*this)[nHeight];
if (vHave.size() > 10)
nStep *= 2;
}
- vHave.push_back(Params().HashGenesisBlock());
-}
-int CBlockLocator::GetDistanceBack()
-{
- // Retrace how far back it was in the sender's branch
- int nDistance = 0;
- int nStep = 1;
- BOOST_FOREACH(const uint256& hash, vHave)
- {
- std::map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hash);
- if (mi != mapBlockIndex.end())
- {
- CBlockIndex* pindex = (*mi).second;
- if (pindex->IsInMainChain())
- return nDistance;
- }
- nDistance += nStep;
- if (nDistance > 10)
- nStep *= 2;
- }
- return nDistance;
+ return CBlockLocator(vHave);
}
-CBlockIndex *CBlockLocator::GetBlockIndex()
-{
+CBlockIndex *CChain::FindFork(const CBlockLocator &locator) const {
// Find the first block the caller has in the main chain
- BOOST_FOREACH(const uint256& hash, vHave)
- {
+ BOOST_FOREACH(const uint256& hash, locator.vHave) {
std::map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hash);
if (mi != mapBlockIndex.end())
{
CBlockIndex* pindex = (*mi).second;
- if (pindex->IsInMainChain())
+ if (Contains(pindex))
return pindex;
}
}
- return pindexGenesisBlock;
-}
-
-uint256 CBlockLocator::GetBlockHash()
-{
- // Find the first block the caller has in the main chain
- BOOST_FOREACH(const uint256& hash, vHave)
- {
- std::map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hash);
- if (mi != mapBlockIndex.end())
- {
- CBlockIndex* pindex = (*mi).second;
- if (pindex->IsInMainChain())
- return hash;
- }
- }
- return Params().HashGenesisBlock();
-}
-
-int CBlockLocator::GetHeight()
-{
- CBlockIndex* pindex = GetBlockIndex();
- if (!pindex)
- return 0;
- return pindex->nHeight;
+ return Genesis();
}
//////////////////////////////////////////////////////////////////////////////
@@ -517,7 +489,7 @@ bool IsFinalTx(const CTransaction &tx, int nBlockHeight, int64 nBlockTime)
if (tx.nLockTime == 0)
return true;
if (nBlockHeight == 0)
- nBlockHeight = nBestHeight;
+ nBlockHeight = chainActive.Height();
if (nBlockTime == 0)
nBlockTime = GetAdjustedTime();
if ((int64)tx.nLockTime < ((int64)tx.nLockTime < LOCKTIME_THRESHOLD ? (int64)nBlockHeight : nBlockTime))
@@ -644,7 +616,7 @@ int CMerkleTx::SetMerkleBranch(const CBlock* pblock)
if (pblock == NULL) {
CCoins coins;
if (pcoinsTip->GetCoins(GetHash(), coins)) {
- CBlockIndex *pindex = FindBlockByHeight(coins.nHeight);
+ CBlockIndex *pindex = chainActive[coins.nHeight];
if (pindex) {
if (!ReadBlockFromDisk(blockTmp, pindex))
return 0;
@@ -678,10 +650,10 @@ int CMerkleTx::SetMerkleBranch(const CBlock* pblock)
if (mi == mapBlockIndex.end())
return 0;
CBlockIndex* pindex = (*mi).second;
- if (!pindex || !pindex->IsInMainChain())
+ if (!pindex || !chainActive.Contains(pindex))
return 0;
- return pindexBest->nHeight - pindex->nHeight + 1;
+ return chainActive.Height() - pindex->nHeight + 1;
}
@@ -1078,7 +1050,7 @@ int CMerkleTx::GetDepthInMainChain(CBlockIndex* &pindexRet) const
if (mi == mapBlockIndex.end())
return 0;
CBlockIndex* pindex = (*mi).second;
- if (!pindex || !pindex->IsInMainChain())
+ if (!pindex || !chainActive.Contains(pindex))
return 0;
// Make sure the merkle branch connects to this block
@@ -1090,7 +1062,7 @@ int CMerkleTx::GetDepthInMainChain(CBlockIndex* &pindexRet) const
}
pindexRet = pindex;
- return pindexBest->nHeight - pindex->nHeight + 1;
+ return chainActive.Height() - pindex->nHeight + 1;
}
@@ -1098,7 +1070,7 @@ int CMerkleTx::GetBlocksToMaturity() const
{
if (!IsCoinBase())
return 0;
- return max(0, (COINBASE_MATURITY+20) - GetDepthInMainChain());
+ return max(0, (COINBASE_MATURITY+1) - GetDepthInMainChain());
}
@@ -1173,7 +1145,7 @@ bool GetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock
nHeight = coins.nHeight;
}
if (nHeight > 0)
- pindexSlow = FindBlockByHeight(nHeight);
+ pindexSlow = chainActive[nHeight];
}
}
@@ -1203,14 +1175,6 @@ bool GetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock
// CBlock and CBlockIndex
//
-static CBlockIndex* pblockindexFBBHLast;
-CBlockIndex* FindBlockByHeight(int nHeight)
-{
- if (nHeight >= (int)vBlockIndexByHeight.size())
- return NULL;
- return vBlockIndexByHeight[nHeight];
-}
-
bool WriteBlockToDisk(CBlock& block, CDiskBlockPos& pos)
{
// Open history file to append
@@ -1404,17 +1368,17 @@ int GetNumBlocksOfPeers()
bool IsInitialBlockDownload()
{
- if (pindexBest == NULL || fImporting || fReindex || nBestHeight < Checkpoints::GetTotalBlocksEstimate())
+ if (fImporting || fReindex || chainActive.Height() < Checkpoints::GetTotalBlocksEstimate())
return true;
static int64 nLastUpdate;
static CBlockIndex* pindexLastBest;
- if (pindexBest != pindexLastBest)
+ if (chainActive.Tip() != pindexLastBest)
{
- pindexLastBest = pindexBest;
+ pindexLastBest = chainActive.Tip();
nLastUpdate = GetTime();
}
return (GetTime() - nLastUpdate < 10 &&
- pindexBest->GetBlockTime() < GetTime() - 24 * 60 * 60);
+ chainActive.Tip()->GetBlockTime() < GetTime() - 24 * 60 * 60);
}
bool fLargeWorkForkFound = false;
@@ -1430,10 +1394,10 @@ void CheckForkWarningConditions()
// If our best fork is no longer within 72 blocks (+/- 12 hours if no one mines it)
// of our head, drop it
- if (pindexBestForkTip && nBestHeight - pindexBestForkTip->nHeight >= 72)
+ if (pindexBestForkTip && chainActive.Height() - pindexBestForkTip->nHeight >= 72)
pindexBestForkTip = NULL;
- if (pindexBestForkTip || nBestInvalidWork > nBestChainWork + (pindexBest->GetBlockWork() * 6).getuint256())
+ if (pindexBestForkTip || nBestInvalidWork > chainActive.Tip()->nChainWork + (chainActive.Tip()->GetBlockWork() * 6).getuint256())
{
if (!fLargeWorkForkFound)
{
@@ -1470,7 +1434,7 @@ void CheckForkWarningConditionsOnNewFork(CBlockIndex* pindexNewForkTip)
{
// If we are on a fork that is sufficiently large, set a warning flag
CBlockIndex* pfork = pindexNewForkTip;
- CBlockIndex* plonger = pindexBest;
+ CBlockIndex* plonger = chainActive.Tip();
while (pfork && pfork != plonger)
{
while (plonger && plonger->nHeight > pfork->nHeight)
@@ -1489,7 +1453,7 @@ void CheckForkWarningConditionsOnNewFork(CBlockIndex* pindexNewForkTip)
// the 7-block condition and from this always have the most-likely-to-cause-warning fork
if (pfork && (!pindexBestForkTip || (pindexBestForkTip && pindexNewForkTip->nHeight > pindexBestForkTip->nHeight)) &&
pindexNewForkTip->nChainWork - pfork->nChainWork > (pfork->GetBlockWork() * 7).getuint256() &&
- nBestHeight - pindexNewForkTip->nHeight < 72)
+ chainActive.Height() - pindexNewForkTip->nHeight < 72)
{
pindexBestForkTip = pindexNewForkTip;
pindexBestForkBase = pfork;
@@ -1511,8 +1475,8 @@ void static InvalidChainFound(CBlockIndex* pindexNew)
log(pindexNew->nChainWork.getdouble())/log(2.0), DateTimeStrFormat("%Y-%m-%d %H:%M:%S",
pindexNew->GetBlockTime()).c_str());
LogPrintf("InvalidChainFound: current best=%s height=%d log2_work=%.8g date=%s\n",
- hashBestChain.ToString().c_str(), nBestHeight, log(nBestChainWork.getdouble())/log(2.0),
- DateTimeStrFormat("%Y-%m-%d %H:%M:%S", pindexBest->GetBlockTime()).c_str());
+ chainActive.Tip()->GetBlockHash().ToString().c_str(), chainActive.Height(), log(chainActive.Tip()->nChainWork.getdouble())/log(2.0),
+ DateTimeStrFormat("%Y-%m-%d %H:%M:%S", chainActive.Tip()->GetBlockTime()).c_str());
CheckForkWarningConditions();
}
@@ -1521,7 +1485,7 @@ void static InvalidBlockFound(CBlockIndex *pindex) {
pblocktree->WriteBlockIndex(CDiskBlockIndex(pindex));
setBlockIndexValid.erase(pindex);
InvalidChainFound(pindex);
- if (pindex->GetNextInMainChain()) {
+ if (chainActive.Next(pindex)) {
CValidationState stateDummy;
ConnectBestBlock(stateDummy); // reorganise away from the failed block
}
@@ -1538,7 +1502,7 @@ bool ConnectBestBlock(CValidationState &state) {
pindexNewBest = *it;
}
- if (pindexNewBest == pindexBest || (pindexBest && pindexNewBest->nChainWork == pindexBest->nChainWork))
+ if (pindexNewBest == chainActive.Tip() || (chainActive.Tip() && pindexNewBest->nChainWork == chainActive.Tip()->nChainWork))
return true; // nothing to do
// check ancestry
@@ -1558,10 +1522,10 @@ bool ConnectBestBlock(CValidationState &state) {
break;
}
- if (pindexBest == NULL || pindexTest->nChainWork > pindexBest->nChainWork)
+ if (chainActive.Tip() == NULL || pindexTest->nChainWork > chainActive.Tip()->nChainWork)
vAttach.push_back(pindexTest);
- if (pindexTest->pprev == NULL || pindexTest->GetNextInMainChain()) {
+ if (pindexTest->pprev == NULL || chainActive.Next(pindexTest)) {
reverse(vAttach.begin(), vAttach.end());
BOOST_FOREACH(CBlockIndex *pindexSwitch, vAttach) {
boost::this_thread::interruption_point();
@@ -1881,7 +1845,6 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C
// (its coinbase is unspendable)
if (block.GetHash() == Params().HashGenesisBlock()) {
view.SetBestBlock(pindex);
- pindexGenesisBlock = pindex;
return true;
}
@@ -2129,9 +2092,7 @@ bool SetBestChain(CValidationState &state, CBlockIndex* pindexNew)
// Proceed by updating the memory structures.
// Register new best chain
- vBlockIndexByHeight.resize(pindexNew->nHeight + 1);
- BOOST_FOREACH(CBlockIndex* pindex, vConnect)
- vBlockIndexByHeight[pindex->nHeight] = pindex;
+ chainActive.SetTip(pindexNew);
// Resurrect memory transactions that were in the disconnected branch
BOOST_FOREACH(CTransaction& tx, vResurrect) {
@@ -2151,29 +2112,21 @@ bool SetBestChain(CValidationState &state, CBlockIndex* pindexNew)
// Update best block in wallet (so we can detect restored wallets)
if ((pindexNew->nHeight % 20160) == 0 || (!fIsInitialDownload && (pindexNew->nHeight % 144) == 0))
- {
- const CBlockLocator locator(pindexNew);
- ::SetBestChain(locator);
- }
+ ::SetBestChain(chainActive.GetLocator(pindexNew));
// New best block
- hashBestChain = pindexNew->GetBlockHash();
- pindexBest = pindexNew;
- pblockindexFBBHLast = NULL;
- nBestHeight = pindexBest->nHeight;
- nBestChainWork = pindexNew->nChainWork;
nTimeBestReceived = GetTime();
nTransactionsUpdated++;
LogPrintf("SetBestChain: new best=%s height=%d log2_work=%.8g tx=%lu date=%s progress=%f\n",
- hashBestChain.ToString().c_str(), nBestHeight, log(nBestChainWork.getdouble())/log(2.0), (unsigned long)pindexNew->nChainTx,
- DateTimeStrFormat("%Y-%m-%d %H:%M:%S", pindexBest->GetBlockTime()).c_str(),
- Checkpoints::GuessVerificationProgress(pindexBest));
+ chainActive.Tip()->GetBlockHash().ToString().c_str(), chainActive.Height(), log(chainActive.Tip()->nChainWork.getdouble())/log(2.0), (unsigned long)pindexNew->nChainTx,
+ DateTimeStrFormat("%Y-%m-%d %H:%M:%S", chainActive.Tip()->GetBlockTime()).c_str(),
+ Checkpoints::GuessVerificationProgress(chainActive.Tip()));
// Check the version of the last 100 blocks to see if we need to upgrade:
if (!fIsInitialDownload)
{
int nUpgraded = 0;
- const CBlockIndex* pindex = pindexBest;
+ const CBlockIndex* pindex = chainActive.Tip();
for (int i = 0; i < 100 && pindex != NULL; i++)
{
if (pindex->nVersion > CBlock::CURRENT_VERSION)
@@ -2191,7 +2144,7 @@ bool SetBestChain(CValidationState &state, CBlockIndex* pindexNew)
if (!fIsInitialDownload && !strCmd.empty())
{
- boost::replace_all(strCmd, "%s", hashBestChain.GetHex());
+ boost::replace_all(strCmd, "%s", chainActive.Tip()->GetBlockHash().GetHex());
boost::thread t(runCommand, strCmd); // thread runs free
}
@@ -2233,7 +2186,7 @@ bool AddToBlockIndex(CBlock& block, CValidationState& state, const CDiskBlockPos
if (!ConnectBestBlock(state))
return false;
- if (pindexNew == pindexBest)
+ if (pindexNew == chainActive.Tip())
{
// Clear fork warning if its no longer applicable
CheckForkWarningConditions();
@@ -2482,11 +2435,11 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CDiskBlockPos* dbp)
// Relay inventory, but don't relay old inventory during initial block download
int nBlockEstimate = Checkpoints::GetTotalBlocksEstimate();
- if (hashBestChain == hash)
+ if (chainActive.Tip()->GetBlockHash() == hash)
{
LOCK(cs_vNodes);
BOOST_FOREACH(CNode* pnode, vNodes)
- if (nBestHeight > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : nBlockEstimate))
+ if (chainActive.Height() > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : nBlockEstimate))
pnode->PushInventory(CInv(MSG_BLOCK, hash));
}
@@ -2505,6 +2458,18 @@ bool CBlockIndex::IsSuperMajority(int minVersion, const CBlockIndex* pstart, uns
return (nFound >= nRequired);
}
+int64 CBlockIndex::GetMedianTime() const
+{
+ const CBlockIndex* pindex = this;
+ for (int i = 0; i < nMedianTimeSpan/2; i++)
+ {
+ if (!chainActive.Next(pindex))
+ return GetBlockTime();
+ pindex = chainActive.Next(pindex);
+ }
+ return pindex->GetMedianTimePast();
+}
+
void PushGetBlocks(CNode* pnode, CBlockIndex* pindexBegin, uint256 hashEnd)
{
// Filter out duplicate requests
@@ -2513,7 +2478,7 @@ void PushGetBlocks(CNode* pnode, CBlockIndex* pindexBegin, uint256 hashEnd)
pnode->pindexLastGetBlocksBegin = pindexBegin;
pnode->hashLastGetBlocksEnd = hashEnd;
- pnode->PushMessage("getblocks", CBlockLocator(pindexBegin), hashEnd);
+ pnode->PushMessage("getblocks", chainActive.GetLocator(pindexBegin), hashEnd);
}
bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBlockPos *dbp)
@@ -2530,7 +2495,7 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl
return error("ProcessBlock() : CheckBlock FAILED");
CBlockIndex* pcheckpoint = Checkpoints::GetLastCheckpoint(mapBlockIndex);
- if (pcheckpoint && pblock->hashPrevBlock != hashBestChain)
+ if (pcheckpoint && pblock->hashPrevBlock != (chainActive.Tip() ? chainActive.Tip()->GetBlockHash() : uint256(0)))
{
// Extra checks to prevent "fill up memory by spamming with bogus blocks"
int64 deltaTime = pblock->GetBlockTime() - pcheckpoint->nTime;
@@ -2561,7 +2526,7 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl
mapOrphanBlocksByPrev.insert(make_pair(pblock2->hashPrevBlock, pblock2));
// Ask this guy to fill in what we're missing
- PushGetBlocks(pfrom, pindexBest, GetOrphanRoot(pblock2));
+ PushGetBlocks(pfrom, chainActive.Tip(), GetOrphanRoot(pblock2));
}
return true;
}
@@ -2875,48 +2840,39 @@ bool static LoadBlockIndexDB()
LogPrintf("LoadBlockIndexDB(): transaction index %s\n", fTxIndex ? "enabled" : "disabled");
// Load hashBestChain pointer to end of best chain
- pindexBest = pcoinsTip->GetBestBlock();
- if (pindexBest == NULL)
+ chainActive.SetTip(pcoinsTip->GetBestBlock());
+ if (chainActive.Tip() == NULL)
return true;
- hashBestChain = pindexBest->GetBlockHash();
- nBestHeight = pindexBest->nHeight;
- nBestChainWork = pindexBest->nChainWork;
// register best chain
- CBlockIndex *pindex = pindexBest;
- vBlockIndexByHeight.resize(pindexBest->nHeight + 1);
- while(pindex != NULL) {
- vBlockIndexByHeight[pindex->nHeight] = pindex;
- pindex = pindex->pprev;
- }
LogPrintf("LoadBlockIndexDB(): hashBestChain=%s height=%d date=%s\n",
- hashBestChain.ToString().c_str(), nBestHeight,
- DateTimeStrFormat("%Y-%m-%d %H:%M:%S", pindexBest->GetBlockTime()).c_str());
+ chainActive.Tip()->GetBlockHash().ToString().c_str(), chainActive.Height(),
+ DateTimeStrFormat("%Y-%m-%d %H:%M:%S", chainActive.Tip()->GetBlockTime()).c_str());
return true;
}
bool VerifyDB(int nCheckLevel, int nCheckDepth)
{
- if (pindexBest == NULL || pindexBest->pprev == NULL)
+ if (chainActive.Tip() == NULL || chainActive.Tip()->pprev == NULL)
return true;
// Verify blocks in the best chain
if (nCheckDepth <= 0)
nCheckDepth = 1000000000; // suffices until the year 19000
- if (nCheckDepth > nBestHeight)
- nCheckDepth = nBestHeight;
+ if (nCheckDepth > chainActive.Height())
+ nCheckDepth = chainActive.Height();
nCheckLevel = std::max(0, std::min(4, nCheckLevel));
LogPrintf("Verifying last %i blocks at level %i\n", nCheckDepth, nCheckLevel);
CCoinsViewCache coins(*pcoinsTip, true);
- CBlockIndex* pindexState = pindexBest;
+ CBlockIndex* pindexState = chainActive.Tip();
CBlockIndex* pindexFailure = NULL;
int nGoodTransactions = 0;
CValidationState state;
- for (CBlockIndex* pindex = pindexBest; pindex && pindex->pprev; pindex = pindex->pprev)
+ for (CBlockIndex* pindex = chainActive.Tip(); pindex && pindex->pprev; pindex = pindex->pprev)
{
boost::this_thread::interruption_point();
- if (pindex->nHeight < nBestHeight-nCheckDepth)
+ if (pindex->nHeight < chainActive.Height()-nCheckDepth)
break;
CBlock block;
// check level 0: read from disk
@@ -2948,14 +2904,14 @@ bool VerifyDB(int nCheckLevel, int nCheckDepth)
}
}
if (pindexFailure)
- return error("VerifyDB() : *** coin database inconsistencies found (last %i blocks, %i good transactions before that)\n", pindexBest->nHeight - pindexFailure->nHeight + 1, nGoodTransactions);
+ return error("VerifyDB() : *** coin database inconsistencies found (last %i blocks, %i good transactions before that)\n", chainActive.Height() - pindexFailure->nHeight + 1, nGoodTransactions);
// check level 4: try reconnecting blocks
if (nCheckLevel >= 4) {
CBlockIndex *pindex = pindexState;
- while (pindex != pindexBest) {
+ while (pindex != chainActive.Tip()) {
boost::this_thread::interruption_point();
- pindex = pindex->GetNextInMainChain();
+ pindex = chainActive.Next(pindex);
CBlock block;
if (!ReadBlockFromDisk(block, pindex))
return error("VerifyDB() : *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString().c_str());
@@ -2964,7 +2920,7 @@ bool VerifyDB(int nCheckLevel, int nCheckDepth)
}
}
- LogPrintf("No coin database inconsistencies in last %i blocks (%i transactions)\n", pindexBest->nHeight - pindexState->nHeight, nGoodTransactions);
+ LogPrintf("No coin database inconsistencies in last %i blocks (%i transactions)\n", chainActive.Height() - pindexState->nHeight, nGoodTransactions);
return true;
}
@@ -2973,12 +2929,8 @@ void UnloadBlockIndex()
{
mapBlockIndex.clear();
setBlockIndexValid.clear();
- pindexGenesisBlock = NULL;
- nBestHeight = 0;
- nBestChainWork = 0;
+ chainActive.SetTip(NULL);
nBestInvalidWork = 0;
- hashBestChain = 0;
- pindexBest = NULL;
}
bool LoadBlockIndex()
@@ -2992,7 +2944,7 @@ bool LoadBlockIndex()
bool InitBlockIndex() {
// Check whether we're already initialized
- if (pindexGenesisBlock != NULL)
+ if (chainActive.Genesis() != NULL)
return true;
// Use the provided setting for -txindex in the new database
@@ -3038,7 +2990,7 @@ void PrintBlockTree()
}
vector<pair<int, CBlockIndex*> > vStack;
- vStack.push_back(make_pair(0, pindexGenesisBlock));
+ vStack.push_back(make_pair(0, chainActive.Genesis()));
int nPrevCol = 0;
while (!vStack.empty())
@@ -3081,7 +3033,7 @@ void PrintBlockTree()
vector<CBlockIndex*>& vNext = mapNext[pindex];
for (unsigned int i = 0; i < vNext.size(); i++)
{
- if (vNext[i]->GetNextInMainChain())
+ if (chainActive.Next(vNext[i]))
{
swap(vNext[0], vNext[i]);
break;
@@ -3328,7 +3280,7 @@ void static ProcessGetData(CNode* pfrom)
// and we want it right after the last block so they don't
// wait for other stuff first.
vector<CInv> vInv;
- vInv.push_back(CInv(MSG_BLOCK, hashBestChain));
+ vInv.push_back(CInv(MSG_BLOCK, chainActive.Tip()->GetBlockHash()));
pfrom->PushMessage("inv", vInv);
pfrom->hashContinue = 0;
}
@@ -3610,7 +3562,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
if (!fImporting && !fReindex)
pfrom->AskFor(inv);
} else if (inv.type == MSG_BLOCK && mapOrphanBlocks.count(inv.hash)) {
- PushGetBlocks(pfrom, pindexBest, GetOrphanRoot(mapOrphanBlocks[inv.hash]));
+ PushGetBlocks(pfrom, chainActive.Tip(), GetOrphanRoot(mapOrphanBlocks[inv.hash]));
} else if (nInv == nLastBlock) {
// In case we are on a very long side-chain, it is possible that we already have
// the last block in an inv bundle sent in response to getblocks. Try to detect
@@ -3654,14 +3606,14 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
vRecv >> locator >> hashStop;
// Find the last block the caller has in the main chain
- CBlockIndex* pindex = locator.GetBlockIndex();
+ CBlockIndex* pindex = chainActive.FindFork(locator);
// Send the rest of the chain
if (pindex)
- pindex = pindex->GetNextInMainChain();
+ pindex = chainActive.Next(pindex);
int nLimit = 500;
LogPrint("net", "getblocks %d to %s limit %d\n", (pindex ? pindex->nHeight : -1), hashStop.ToString().c_str(), nLimit);
- for (; pindex; pindex = pindex->GetNextInMainChain())
+ for (; pindex; pindex = chainActive.Next(pindex))
{
if (pindex->GetBlockHash() == hashStop)
{
@@ -3699,16 +3651,16 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
else
{
// Find the last block the caller has in the main chain
- pindex = locator.GetBlockIndex();
+ pindex = chainActive.FindFork(locator);
if (pindex)
- pindex = pindex->GetNextInMainChain();
+ pindex = chainActive.Next(pindex);
}
// we must use CBlocks, as CBlockHeaders won't include the 0x00 nTx count at the end
vector<CBlock> vHeaders;
int nLimit = 2000;
LogPrint("net", "getheaders %d to %s\n", (pindex ? pindex->nHeight : -1), hashStop.ToString().c_str());
- for (; pindex; pindex = pindex->GetNextInMainChain())
+ for (; pindex; pindex = chainActive.Next(pindex))
{
vHeaders.push_back(pindex->GetBlockHeader());
if (--nLimit <= 0 || pindex->GetBlockHash() == hashStop)
@@ -3785,9 +3737,10 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
if (nEvicted > 0)
LogPrint("mempool", "mapOrphan overflow, removed %u tx\n", nEvicted);
}
- int nDoS;
+ int nDoS = 0;
if (state.IsInvalid(nDoS))
- pfrom->Misbehaving(nDoS);
+ if (nDoS > 0)
+ pfrom->Misbehaving(nDoS);
}
@@ -3805,9 +3758,10 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
CValidationState state;
if (ProcessBlock(state, pfrom, &block))
mapAlreadyAskedFor.erase(inv);
- int nDoS;
+ int nDoS = 0;
if (state.IsInvalid(nDoS))
- pfrom->Misbehaving(nDoS);
+ if (nDoS > 0)
+ pfrom->Misbehaving(nDoS);
}
@@ -3861,6 +3815,63 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
}
+ else if (strCommand == "pong")
+ {
+ int64 pingUsecEnd = GetTimeMicros();
+ uint64 nonce = 0;
+ size_t nAvail = vRecv.in_avail();
+ bool bPingFinished = false;
+ std::string sProblem;
+
+ if (nAvail >= sizeof(nonce)) {
+ vRecv >> nonce;
+
+ // Only process pong message if there is an outstanding ping (old ping without nonce should never pong)
+ if (pfrom->nPingNonceSent != 0) {
+ if (nonce == pfrom->nPingNonceSent) {
+ // Matching pong received, this ping is no longer outstanding
+ bPingFinished = true;
+ int64 pingUsecTime = pingUsecEnd - pfrom->nPingUsecStart;
+ if (pingUsecTime > 0) {
+ // Successful ping time measurement, replace previous
+ pfrom->nPingUsecTime = pingUsecTime;
+ } else {
+ // This should never happen
+ sProblem = "Timing mishap";
+ }
+ } else {
+ // Nonce mismatches are normal when pings are overlapping
+ sProblem = "Nonce mismatch";
+ if (nonce == 0) {
+ // This is most likely a bug in another implementation somewhere, cancel this ping
+ bPingFinished = true;
+ sProblem = "Nonce zero";
+ }
+ }
+ } else {
+ sProblem = "Unsolicited pong without ping";
+ }
+ } else {
+ // This is most likely a bug in another implementation somewhere, cancel this ping
+ bPingFinished = true;
+ sProblem = "Short payload";
+ }
+
+ if (!(sProblem.empty())) {
+ LogPrint("net", "pong %s %s: %s, %"PRI64x" expected, %"PRI64x" received, %"PRIszu" bytes\n",
+ pfrom->addr.ToString().c_str(),
+ pfrom->strSubVer.c_str(),
+ sProblem.c_str(),
+ pfrom->nPingNonceSent,
+ nonce,
+ nAvail);
+ }
+ if (bPingFinished) {
+ pfrom->nPingNonceSent = 0;
+ }
+ }
+
+
else if (strCommand == "alert")
{
CAlert alert;
@@ -3959,7 +3970,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
bool ProcessMessages(CNode* pfrom)
{
//if (fDebug)
- // LogPrintf("ProcessMessages(%zu messages)\n", pfrom->vRecvMsg.size());
+ // LogPrintf("ProcessMessages(%"PRIszu" messages)\n", pfrom->vRecvMsg.size());
//
// Message format
@@ -3984,7 +3995,7 @@ bool ProcessMessages(CNode* pfrom)
CNetMessage& msg = *it;
//if (fDebug)
- // LogPrintf("ProcessMessages(message %u msgsz, %zu bytes, complete:%s)\n",
+ // LogPrintf("ProcessMessages(message %u msgsz, %"PRIszu" bytes, complete:%s)\n",
// msg.hdr.nMessageSize, msg.vRecv.size(),
// msg.complete() ? "Y" : "N");
@@ -4082,20 +4093,40 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
if (pto->nVersion == 0)
return true;
- // Keep-alive ping. We send a nonce of zero because we don't use it anywhere
- // right now.
+ //
+ // Message: ping
+ //
+ bool pingSend = false;
+ if (pto->fPingQueued) {
+ // RPC ping request by user
+ pingSend = true;
+ }
if (pto->nLastSend && GetTime() - pto->nLastSend > 30 * 60 && pto->vSendMsg.empty()) {
+ // Ping automatically sent as a keepalive
+ pingSend = true;
+ }
+ if (pingSend) {
uint64 nonce = 0;
- if (pto->nVersion > BIP0031_VERSION)
+ while (nonce == 0) {
+ RAND_bytes((unsigned char*)&nonce, sizeof(nonce));
+ }
+ pto->nPingNonceSent = nonce;
+ pto->fPingQueued = false;
+ if (pto->nVersion > BIP0031_VERSION) {
+ // Take timestamp as close as possible before transmitting ping
+ pto->nPingUsecStart = GetTimeMicros();
pto->PushMessage("ping", nonce);
- else
+ } else {
+ // Peer is too old to support ping command with nonce, pong will never arrive, disable timing
+ pto->nPingUsecStart = 0;
pto->PushMessage("ping");
+ }
}
// Start block sync
if (pto->fStartSync && !fImporting && !fReindex) {
pto->fStartSync = false;
- PushGetBlocks(pto, pindexBest, uint256(0));
+ PushGetBlocks(pto, chainActive.Tip(), uint256(0));
}
// Resend wallet transactions that haven't gotten in a block yet
diff --git a/src/main.h b/src/main.h
index 83b0d07f63..fc60ccc0b5 100644
--- a/src/main.h
+++ b/src/main.h
@@ -74,14 +74,8 @@ extern CScript COINBASE_FLAGS;
extern CCriticalSection cs_main;
extern std::map<uint256, CBlockIndex*> mapBlockIndex;
-extern std::vector<CBlockIndex*> vBlockIndexByHeight;
extern std::set<CBlockIndex*, CBlockIndexWorkComparator> setBlockIndexValid;
-extern CBlockIndex* pindexGenesisBlock;
-extern int nBestHeight;
-extern uint256 nBestChainWork;
extern uint256 nBestInvalidWork;
-extern uint256 hashBestChain;
-extern CBlockIndex* pindexBest;
extern unsigned int nTransactionsUpdated;
extern uint64 nLastBlockTx;
extern uint64 nLastBlockSize;
@@ -153,8 +147,6 @@ void UnloadBlockIndex();
bool VerifyDB(int nCheckLevel, int nCheckDepth);
/** Print the loaded block tree */
void PrintBlockTree();
-/** Find a block by height in the currently-connected chain */
-CBlockIndex* FindBlockByHeight(int nHeight);
/** Process protocol messages received from a given node */
bool ProcessMessages(CNode* pfrom);
/** Send queued protocol messages to be sent to a give node */
@@ -819,15 +811,6 @@ public:
return (CBigNum(1)<<256) / (bnTarget+1);
}
- bool IsInMainChain() const
- {
- return nHeight < (int)vBlockIndexByHeight.size() && vBlockIndexByHeight[nHeight] == this;
- }
-
- CBlockIndex *GetNextInMainChain() const {
- return nHeight+1 >= (int)vBlockIndexByHeight.size() ? NULL : vBlockIndexByHeight[nHeight+1];
- }
-
bool CheckIndex() const
{
return CheckProofOfWork(GetBlockHash(), nBits);
@@ -849,17 +832,7 @@ public:
return pbegin[(pend - pbegin)/2];
}
- int64 GetMedianTime() const
- {
- const CBlockIndex* pindex = this;
- for (int i = 0; i < nMedianTimeSpan/2; i++)
- {
- if (!pindex->GetNextInMainChain())
- return GetBlockTime();
- pindex = pindex->GetNextInMainChain();
- }
- return pindex->GetMedianTimePast();
- }
+ int64 GetMedianTime() const;
/**
* Returns true if there are nRequired or more blocks of minVersion or above
@@ -870,8 +843,8 @@ public:
std::string ToString() const
{
- return strprintf("CBlockIndex(pprev=%p, pnext=%p, nHeight=%d, merkle=%s, hashBlock=%s)",
- pprev, GetNextInMainChain(), nHeight,
+ return strprintf("CBlockIndex(pprev=%p, nHeight=%d, merkle=%s, hashBlock=%s)",
+ pprev, nHeight,
hashMerkleRoot.ToString().c_str(),
GetBlockHash().ToString().c_str());
}
@@ -1011,64 +984,67 @@ public:
}
};
+/** An in-memory indexed chain of blocks. */
+class CChain {
+private:
+ std::vector<CBlockIndex*> vChain;
-
-
-
-
-
-/** Describes a place in the block chain to another node such that if the
- * other node doesn't have the same branch, it can find a recent common trunk.
- * The further back it is, the further before the fork it may be.
- */
-class CBlockLocator
-{
-protected:
- std::vector<uint256> vHave;
public:
- CBlockLocator() {}
+ /** Returns the index entry for the genesis block of this chain, or NULL if none. */
+ CBlockIndex *Genesis() const {
+ return vChain.size() > 0 ? vChain[0] : NULL;
+ }
- explicit CBlockLocator(const CBlockIndex* pindex)
- {
- Set(pindex);
+ /** Returns the index entry for the tip of this chain, or NULL if none. */
+ CBlockIndex *Tip() const {
+ return vChain.size() > 0 ? vChain[vChain.size() - 1] : NULL;
}
- explicit CBlockLocator(uint256 hashBlock);
+ /** Returns the index entry at a particular height in this chain, or NULL if no such height exists. */
+ CBlockIndex *operator[](int nHeight) const {
+ if (nHeight < 0 || nHeight >= (int)vChain.size())
+ return NULL;
+ return vChain[nHeight];
+ }
- CBlockLocator(const std::vector<uint256>& vHaveIn)
- {
- vHave = vHaveIn;
+ /** Compare two chains efficiently. */
+ friend bool operator==(const CChain &a, const CChain &b) {
+ return a.vChain.size() == b.vChain.size() &&
+ a.vChain[a.vChain.size() - 1] == b.vChain[b.vChain.size() - 1];
}
- IMPLEMENT_SERIALIZE
- (
- if (!(nType & SER_GETHASH))
- READWRITE(nVersion);
- READWRITE(vHave);
- )
+ /** Efficiently check whether a block is present in this chain. */
+ bool Contains(const CBlockIndex *pindex) const {
+ return (*this)[pindex->nHeight] == pindex;
+ }
- void SetNull()
- {
- vHave.clear();
+ /** Find the successor of a block in this chain, or NULL if the given index is not found or is the tip. */
+ CBlockIndex *Next(const CBlockIndex *pindex) const {
+ if (Contains(pindex))
+ return (*this)[pindex->nHeight + 1];
+ else
+ return NULL;
}
- bool IsNull()
- {
- return vHave.empty();
+ /** Return the maximal height in the chain. Is equal to chain.Tip() ? chain.Tip()->nHeight : -1. */
+ int Height() const {
+ return vChain.size() - 1;
}
- /** Given a block initialises the locator to that point in the chain. */
- void Set(const CBlockIndex* pindex);
- /** Returns the distance in blocks this locator is from our chain head. */
- int GetDistanceBack();
- /** Returns the first best-chain block the locator contains. */
- CBlockIndex* GetBlockIndex();
- /** Returns the hash of the first best chain block the locator contains. */
- uint256 GetBlockHash();
- /** Returns the height of the first best chain block the locator has. */
- int GetHeight();
+ /** Set/initialize a chain with a given tip. Returns the forking point. */
+ CBlockIndex *SetTip(CBlockIndex *pindex);
+
+ /** Return a CBlockLocator that refers to a block in this chain (by default the tip). */
+ CBlockLocator GetLocator(const CBlockIndex *pindex = NULL) const;
+
+ /** Find the last common block between this chain and a locator. */
+ CBlockIndex *FindFork(const CBlockLocator &locator) const;
};
+/** The currently-connected chain of blocks. */
+extern CChain chainActive;
+
+
diff --git a/src/miner.cpp b/src/miner.cpp
index 30c600071f..e9c1d9aff9 100644
--- a/src/miner.cpp
+++ b/src/miner.cpp
@@ -176,7 +176,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
int64 nFees = 0;
{
LOCK2(cs_main, mempool.cs);
- CBlockIndex* pindexPrev = pindexBest;
+ CBlockIndex* pindexPrev = chainActive.Tip();
CCoinsViewCache view(*pcoinsTip, true);
// Priority order to process transactions
@@ -467,7 +467,7 @@ bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey)
// Found a solution
{
LOCK(cs_main);
- if (pblock->hashPrevBlock != hashBestChain)
+ if (pblock->hashPrevBlock != chainActive.Tip()->GetBlockHash())
return error("BitcoinMiner : generated block is stale");
// Remove key from key pool
@@ -510,7 +510,7 @@ void static BitcoinMiner(CWallet *pwallet)
// Create new block
//
unsigned int nTransactionsUpdatedLast = nTransactionsUpdated;
- CBlockIndex* pindexPrev = pindexBest;
+ CBlockIndex* pindexPrev = chainActive.Tip();
auto_ptr<CBlockTemplate> pblocktemplate(CreateNewBlockWithKey(reservekey));
if (!pblocktemplate.get())
@@ -613,7 +613,7 @@ void static BitcoinMiner(CWallet *pwallet)
break;
if (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60)
break;
- if (pindexPrev != pindexBest)
+ if (pindexPrev != chainActive.Tip())
break;
// Update nTime every few seconds
diff --git a/src/net.cpp b/src/net.cpp
index 781dbfadca..99457be0f5 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -426,8 +426,10 @@ void AddressCurrentlyConnected(const CService& addr)
-
-
+uint64 CNode::nTotalBytesRecv = 0;
+uint64 CNode::nTotalBytesSent = 0;
+CCriticalSection CNode::cs_totalBytesRecv;
+CCriticalSection CNode::cs_totalBytesSent;
CNode* FindNode(const CNetAddr& ip)
{
@@ -540,6 +542,8 @@ void CNode::Cleanup()
void CNode::PushVersion()
{
+ int nBestHeight = g_signals.GetHeight().get_value_or(0);
+
/// when NTP implemented, change to just nTime = GetAdjustedTime()
int64 nTime = (fInbound ? GetAdjustedTime() : GetTime());
CAddress addrYou = (addr.IsRoutable() && !IsProxy(addr) ? addr : CAddress(CService("0.0.0.0",0)));
@@ -620,6 +624,21 @@ void CNode::copyStats(CNodeStats &stats)
X(nSendBytes);
X(nRecvBytes);
stats.fSyncNode = (this == pnodeSync);
+
+ // It is common for nodes with good ping times to suddenly become lagged,
+ // due to a new block arriving or other large transfer.
+ // Merely reporting pingtime might fool the caller into thinking the node was still responsive,
+ // since pingtime does not update until the ping is complete, which might take a while.
+ // So, if a ping is taking an unusually long time in flight,
+ // the caller can immediately detect that this is happening.
+ int64 nPingUsecWait = 0;
+ if ((0 != nPingNonceSent) && (0 != nPingUsecStart)) {
+ nPingUsecWait = GetTimeMicros() - nPingUsecStart;
+ }
+
+ // Raw ping time is in microseconds, but show it to user as whole seconds (Bitcoin users should be well used to small numbers with many decimal places by now :)
+ stats.dPingTime = (((double)nPingUsecTime) / 1e6);
+ stats.dPingWait = (((double)nPingUsecWait) / 1e6);
}
#undef X
@@ -716,6 +735,7 @@ void SocketSendData(CNode *pnode)
pnode->nLastSend = GetTime();
pnode->nSendBytes += nBytes;
pnode->nSendOffset += nBytes;
+ pnode->RecordBytesSent(nBytes);
if (pnode->nSendOffset == data.size()) {
pnode->nSendOffset = 0;
pnode->nSendSize -= data.size();
@@ -811,10 +831,9 @@ void ThreadSocketHandler()
}
}
}
- if (vNodes.size() != nPrevNodeCount)
- {
+ if(vNodes.size() != nPrevNodeCount) {
nPrevNodeCount = vNodes.size();
- uiInterface.NotifyNumConnectionsChanged(vNodes.size());
+ uiInterface.NotifyNumConnectionsChanged(nPrevNodeCount);
}
@@ -993,6 +1012,7 @@ void ThreadSocketHandler()
pnode->CloseSocketDisconnect();
pnode->nLastRecv = GetTime();
pnode->nRecvBytes += nBytes;
+ pnode->RecordBytesRecv(nBytes);
}
else if (nBytes == 0)
{
@@ -1467,6 +1487,8 @@ void static StartSync(const vector<CNode*> &vNodes) {
CNode *pnodeNewSync = NULL;
double dBestScore = 0;
+ int nBestHeight = g_signals.GetHeight().get_value_or(0);
+
// Iterate over all nodes
BOOST_FOREACH(CNode* pnode, vNodes) {
// check preconditions for allowing a sync
@@ -1844,3 +1866,27 @@ void RelayTransaction(const CTransaction& tx, const uint256& hash, const CDataSt
pnode->PushInventory(inv);
}
}
+
+void CNode::RecordBytesRecv(uint64 bytes)
+{
+ LOCK(cs_totalBytesRecv);
+ nTotalBytesRecv += bytes;
+}
+
+void CNode::RecordBytesSent(uint64 bytes)
+{
+ LOCK(cs_totalBytesSent);
+ nTotalBytesSent += bytes;
+}
+
+uint64 CNode::GetTotalBytesRecv()
+{
+ LOCK(cs_totalBytesRecv);
+ return nTotalBytesRecv;
+}
+
+uint64 CNode::GetTotalBytesSent()
+{
+ LOCK(cs_totalBytesSent);
+ return nTotalBytesSent;
+}
diff --git a/src/net.h b/src/net.h
index 49415f6502..9b76d1643d 100644
--- a/src/net.h
+++ b/src/net.h
@@ -28,7 +28,6 @@ static const unsigned int MAX_INV_SZ = 50000;
class CNode;
class CBlockIndex;
-extern int nBestHeight;
@@ -52,6 +51,7 @@ void SocketSendData(CNode *pnode);
// Signals for message handling
struct CNodeSignals
{
+ boost::signals2::signal<int ()> GetHeight;
boost::signals2::signal<bool (CNode*)> ProcessMessages;
boost::signals2::signal<bool (CNode*, bool)> SendMessages;
};
@@ -119,6 +119,8 @@ public:
uint64 nSendBytes;
uint64 nRecvBytes;
bool fSyncNode;
+ double dPingTime;
+ double dPingWait;
};
@@ -234,6 +236,12 @@ public:
CCriticalSection cs_inventory;
std::multimap<int64, CInv> mapAskFor;
+ // Ping time measurement
+ uint64 nPingNonceSent;
+ int64 nPingUsecStart;
+ int64 nPingUsecTime;
+ bool fPingQueued;
+
CNode(SOCKET hSocketIn, CAddress addrIn, std::string addrNameIn = "", bool fInboundIn=false) : ssSend(SER_NETWORK, MIN_PROTO_VERSION)
{
nServices = 0;
@@ -268,6 +276,10 @@ public:
fRelayTxes = false;
setInventoryKnown.max_size(SendBufferSize() / 1000);
pfilter = new CBloomFilter();
+ nPingNonceSent = 0;
+ nPingUsecStart = 0;
+ nPingUsecTime = 0;
+ fPingQueued = false;
// Be shy and don't send version until we hear
if (hSocket != INVALID_SOCKET && !fInbound)
@@ -286,8 +298,15 @@ public:
}
private:
+ // Network usage totals
+ static CCriticalSection cs_totalBytesRecv;
+ static CCriticalSection cs_totalBytesSent;
+ static uint64 nTotalBytesRecv;
+ static uint64 nTotalBytesSent;
+
CNode(const CNode&);
void operator=(const CNode&);
+
public:
@@ -301,7 +320,7 @@ public:
unsigned int GetTotalRecvSize()
{
unsigned int total = 0;
- BOOST_FOREACH(const CNetMessage &msg, vRecvMsg)
+ BOOST_FOREACH(const CNetMessage &msg, vRecvMsg)
total += msg.vRecv.size() + 24;
return total;
}
@@ -634,6 +653,13 @@ public:
static bool IsBanned(CNetAddr ip);
bool Misbehaving(int howmuch); // 1 == a little, 100 == a lot
void copyStats(CNodeStats &stats);
+
+ // Network stats
+ static void RecordBytesRecv(uint64 bytes);
+ static void RecordBytesSent(uint64 bytes);
+
+ static uint64 GetTotalBytesRecv();
+ static uint64 GetTotalBytesSent();
};
diff --git a/src/netbase.cpp b/src/netbase.cpp
index acc2ae32aa..360ecdd959 100644
--- a/src/netbase.cpp
+++ b/src/netbase.cpp
@@ -864,7 +864,7 @@ std::vector<unsigned char> CNetAddr::GetGroup() const
nBits = 4;
}
// for he.net, use /36 groups
- else if (GetByte(15) == 0x20 && GetByte(14) == 0x11 && GetByte(13) == 0x04 && GetByte(12) == 0x70)
+ else if (GetByte(15) == 0x20 && GetByte(14) == 0x01 && GetByte(13) == 0x04 && GetByte(12) == 0x70)
nBits = 36;
// for the rest of the IPv6 network, use /32 groups
else
diff --git a/src/netbase.h b/src/netbase.h
index 8d5135e970..e1f80b4ee8 100644
--- a/src/netbase.h
+++ b/src/netbase.h
@@ -54,7 +54,7 @@ class CNetAddr
bool IsRFC3849() const; // IPv6 documentation address (2001:0DB8::/32)
bool IsRFC3927() const; // IPv4 autoconfig (169.254.0.0/16)
bool IsRFC3964() const; // IPv6 6to4 tunnelling (2002::/16)
- bool IsRFC4193() const; // IPv6 unique local (FC00::/15)
+ bool IsRFC4193() const; // IPv6 unique local (FC00::/7)
bool IsRFC4380() const; // IPv6 Teredo tunnelling (2001::/32)
bool IsRFC4843() const; // IPv6 ORCHID (2001:10::/28)
bool IsRFC4862() const; // IPv6 autoconfig (FE80::/64)
diff --git a/src/qt/Makefile.am b/src/qt/Makefile.am
index 33c5825eb3..e7ae0a905f 100644
--- a/src/qt/Makefile.am
+++ b/src/qt/Makefile.am
@@ -4,7 +4,7 @@ AM_CPPFLAGS = $(INCLUDES) -I$(top_builddir)/src/obj \
-I$(top_srcdir)/src/leveldb/include -I$(top_srcdir)/src \
-I$(top_srcdir)/src/leveldb/helpers -I$(top_builddir)/src/qt \
-I$(top_builddir)/src/qt/forms $(BOOST_INCLUDES) $(PROTOBUF_CFLAGS) \
- $(QR_CFLAGS)
+ $(QR_CFLAGS) $(BDB_CPPFLAGS)
AM_LDFLAGS = $(PTHREAD_CFLAGS)
bin_PROGRAMS = bitcoin-qt
noinst_LIBRARIES = libbitcoinqt.a
@@ -48,7 +48,7 @@ QT_MOC_CPP = moc_aboutdialog.cpp moc_addressbookpage.cpp \
moc_optionsmodel.cpp moc_overviewpage.cpp moc_paymentserver.cpp \
moc_qrcodedialog.cpp moc_qvalidatedlineedit.cpp moc_qvaluecombobox.cpp \
moc_rpcconsole.cpp moc_sendcoinsdialog.cpp moc_sendcoinsentry.cpp \
- moc_signverifymessagedialog.cpp moc_splashscreen.cpp moc_transactiondesc.cpp \
+ moc_signverifymessagedialog.cpp moc_splashscreen.cpp moc_trafficgraphwidget.cpp moc_transactiondesc.cpp \
moc_transactiondescdialog.cpp moc_transactionfilterproxy.cpp \
moc_transactiontablemodel.cpp moc_transactionview.cpp moc_walletframe.cpp \
moc_walletmodel.cpp moc_walletstack.cpp moc_walletview.cpp
@@ -73,7 +73,7 @@ BITCOIN_QT_H = aboutdialog.h addressbookpage.h addresstablemodel.h \
optionsmodel.h overviewpage.h paymentrequestplus.h paymentserver.h \
qrcodedialog.h qvalidatedlineedit.h qvaluecombobox.h rpcconsole.h \
sendcoinsdialog.h sendcoinsentry.h signverifymessagedialog.h splashscreen.h \
- transactiondescdialog.h transactiondesc.h transactionfilterproxy.h \
+ trafficgraphwidget.h transactiondescdialog.h transactiondesc.h transactionfilterproxy.h \
transactionrecord.h transactiontablemodel.h transactionview.h walletframe.h \
walletmodel.h walletmodeltransaction.h walletstack.h walletview.h
@@ -102,7 +102,7 @@ BITCOIN_QT_CPP = aboutdialog.cpp addressbookpage.cpp \
optionsdialog.cpp optionsmodel.cpp overviewpage.cpp paymentrequestplus.cpp \
paymentserver.cpp qvalidatedlineedit.cpp qvaluecombobox.cpp \
rpcconsole.cpp sendcoinsdialog.cpp sendcoinsentry.cpp \
- signverifymessagedialog.cpp splashscreen.cpp transactiondesc.cpp \
+ signverifymessagedialog.cpp splashscreen.cpp trafficgraphwidget.cpp transactiondesc.cpp \
transactiondescdialog.cpp transactionfilterproxy.cpp transactionrecord.cpp \
transactiontablemodel.cpp transactionview.cpp walletframe.cpp \
walletmodel.cpp walletmodeltransaction.cpp walletstack.cpp walletview.cpp
@@ -145,7 +145,7 @@ bitcoin_qt_CPPFLAGS = $(AM_CPPFLAGS) $(QT_INCLUDES) \
-I$(top_srcdir)/src/qt/forms
bitcoin_qt_SOURCES = bitcoin.cpp
bitcoin_qt_LDADD = libbitcoinqt.a $(LIBBITCOIN) $(LIBLEVELDB) $(LIBMEMENV) \
- $(BOOST_LIBS) $(QT_LIBS) $(QT_DBUS_LIBS) $(QR_LIBS) $(PROTOBUF_LIBS)
+ $(BOOST_LIBS) $(QT_LIBS) $(QT_DBUS_LIBS) $(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS)
# forms/foo.h -> forms/ui_foo.h
QT_FORMS_H=$(join $(dir $(QT_FORMS_UI)),$(addprefix ui_, $(notdir $(QT_FORMS_UI:.ui=.h))))
diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp
index f184fb9ef0..78693971da 100644
--- a/src/qt/bitcoin.cpp
+++ b/src/qt/bitcoin.cpp
@@ -155,11 +155,14 @@ static void initTranslations(QTranslator &qtTranslatorBase, QTranslator &qtTrans
#if QT_VERSION < 0x050000
void DebugMessageHandler(QtMsgType type, const char * msg)
{
+ Q_UNUSED(type);
LogPrint("qt", "Bitcoin-Qt: %s\n", msg);
}
#else
void DebugMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString &msg)
{
+ Q_UNUSED(type);
+ Q_UNUSED(context);
LogPrint("qt", "Bitcoin-Qt: %s\n", qPrintable(msg));
}
#endif
diff --git a/src/qt/bitcoinamountfield.cpp b/src/qt/bitcoinamountfield.cpp
index d9d4e3b23d..37b8743eff 100644
--- a/src/qt/bitcoinamountfield.cpp
+++ b/src/qt/bitcoinamountfield.cpp
@@ -130,9 +130,10 @@ void BitcoinAmountField::setValue(qint64 value)
setText(BitcoinUnits::format(currentUnit, value));
}
-void BitcoinAmountField::setReadOnly(bool fReadeOnly)
+void BitcoinAmountField::setReadOnly(bool fReadOnly)
{
- // TODO ...
+ amount->setReadOnly(fReadOnly);
+ unit->setEnabled(!fReadOnly);
}
void BitcoinAmountField::unitChanged(int idx)
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index 49eb35dfec..23a221120f 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -157,6 +157,8 @@ BitcoinGUI::BitcoinGUI(bool fIsTestnet, QWidget *parent) :
rpcConsole = new RPCConsole(this);
connect(openRPCConsoleAction, SIGNAL(triggered()), rpcConsole, SLOT(show()));
+ // prevents an oben debug window from becoming stuck/unusable on client shutdown
+ connect(quitAction, SIGNAL(triggered()), rpcConsole, SLOT(hide()));
// Install event filter to be able to catch status tip events (QEvent::StatusTip)
this->installEventFilter(this);
@@ -233,7 +235,11 @@ void BitcoinGUI::createActions(bool fIsTestnet)
aboutAction = new QAction(QIcon(":/icons/bitcoin_testnet"), tr("&About Bitcoin"), this);
aboutAction->setStatusTip(tr("Show information about Bitcoin"));
aboutAction->setMenuRole(QAction::AboutRole);
+#if QT_VERSION < 0x050000
aboutQtAction = new QAction(QIcon(":/trolltech/qmessagebox/images/qtlogo-64.png"), tr("About &Qt"), this);
+#else
+ aboutQtAction = new QAction(QIcon(":/qt-project.org/qmessagebox/images/qtlogo-64.png"), tr("About &Qt"), this);
+#endif
aboutQtAction->setStatusTip(tr("Show information about Qt"));
aboutQtAction->setMenuRole(QAction::AboutQtRole);
optionsAction = new QAction(QIcon(":/icons/options"), tr("&Options..."), this);
@@ -751,13 +757,9 @@ void BitcoinGUI::handlePaymentRequest(const SendCoinsRecipient& recipient)
walletFrame->handlePaymentRequest(recipient);
}
-void BitcoinGUI::showPaymentACK(QString msg)
+void BitcoinGUI::showPaymentACK(const QString& msg)
{
-#if QT_VERSION < 0x050000
- message(tr("Payment acknowledged"), Qt::escape(msg), CClientUIInterface::MODAL);
-#else
- message(tr("Payment acknowledged"), msg.toHtmlEscaped(), CClientUIInterface::MODAL);
-#endif
+ message(tr("Payment acknowledged"), GUIUtil::HtmlEscape(msg), CClientUIInterface::MODAL);
}
void BitcoinGUI::setEncryptionStatus(int status)
diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h
index fc25e867fc..e2dd5dc6bc 100644
--- a/src/qt/bitcoingui.h
+++ b/src/qt/bitcoingui.h
@@ -154,7 +154,7 @@ public slots:
void askFee(qint64 nFeeRequired, bool *payFee);
void handlePaymentRequest(const SendCoinsRecipient& recipient);
- void showPaymentACK(QString msg);
+ void showPaymentACK(const QString& msg);
/** Show incoming transaction notification for new transactions. */
void incomingTransaction(const QString& date, int unit, qint64 amount, const QString& type, const QString& address);
diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp
index f7dd8adb6b..2bab488135 100644
--- a/src/qt/clientmodel.cpp
+++ b/src/qt/clientmodel.cpp
@@ -24,9 +24,8 @@ ClientModel::ClientModel(OptionsModel *optionsModel, QObject *parent) :
numBlocksAtStartup(-1), pollTimer(0)
{
pollTimer = new QTimer(this);
- pollTimer->setInterval(MODEL_UPDATE_DELAY);
- pollTimer->start();
connect(pollTimer, SIGNAL(timeout()), this, SLOT(updateTimer()));
+ pollTimer->start(MODEL_UPDATE_DELAY);
subscribeToCoreSignals();
}
@@ -43,7 +42,7 @@ int ClientModel::getNumConnections() const
int ClientModel::getNumBlocks() const
{
- return nBestHeight;
+ return chainActive.Height();
}
int ClientModel::getNumBlocksAtStartup()
@@ -52,10 +51,20 @@ int ClientModel::getNumBlocksAtStartup()
return numBlocksAtStartup;
}
+quint64 ClientModel::getTotalBytesRecv() const
+{
+ return CNode::GetTotalBytesRecv();
+}
+
+quint64 ClientModel::getTotalBytesSent() const
+{
+ return CNode::GetTotalBytesSent();
+}
+
QDateTime ClientModel::getLastBlockDate() const
{
- if (pindexBest)
- return QDateTime::fromTime_t(pindexBest->GetBlockTime());
+ if (chainActive.Tip())
+ return QDateTime::fromTime_t(chainActive.Tip()->GetBlockTime());
else if(!isTestNet())
return QDateTime::fromTime_t(1231006505); // Genesis block's time
else
@@ -64,7 +73,7 @@ QDateTime ClientModel::getLastBlockDate() const
double ClientModel::getVerificationProgress() const
{
- return Checkpoints::GuessVerificationProgress(pindexBest);
+ return Checkpoints::GuessVerificationProgress(chainActive.Tip());
}
void ClientModel::updateTimer()
@@ -86,6 +95,8 @@ void ClientModel::updateTimer()
// ensure we return the maximum of newNumBlocksOfPeers and newNumBlocks to not create weird displays in the GUI
emit numBlocksChanged(newNumBlocks, std::max(newNumBlocksOfPeers, newNumBlocks));
}
+
+ emit bytesChanged(getTotalBytesRecv(), getTotalBytesSent());
}
void ClientModel::updateNumConnections(int numConnections)
diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h
index 15074300b4..925f20acd9 100644
--- a/src/qt/clientmodel.h
+++ b/src/qt/clientmodel.h
@@ -35,6 +35,9 @@ public:
int getNumBlocks() const;
int getNumBlocksAtStartup();
+ quint64 getTotalBytesRecv() const;
+ quint64 getTotalBytesSent() const;
+
double getVerificationProgress() const;
QDateTime getLastBlockDate() const;
@@ -74,6 +77,7 @@ signals:
void numConnectionsChanged(int count);
void numBlocksChanged(int count, int countOfPeers);
void alertsChanged(const QString &warnings);
+ void bytesChanged(quint64 totalBytesIn, quint64 totalBytesOut);
//! Asynchronous message notification
void message(const QString &title, const QString &message, unsigned int style);
diff --git a/src/qt/forms/rpcconsole.ui b/src/qt/forms/rpcconsole.ui
index d1d8ab42a0..54c41ffb67 100644
--- a/src/qt/forms/rpcconsole.ui
+++ b/src/qt/forms/rpcconsole.ui
@@ -445,10 +445,271 @@
</item>
</layout>
</widget>
+ <widget class="QWidget" name="tab">
+ <attribute name="title">
+ <string>&amp;Network Traffic</string>
+ </attribute>
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout_4">
+ <item>
+ <widget class="TrafficGraphWidget" name="trafficGraph" native="true">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <widget class="QSlider" name="sldGraphRange">
+ <property name="minimum">
+ <number>1</number>
+ </property>
+ <property name="maximum">
+ <number>288</number>
+ </property>
+ <property name="pageStep">
+ <number>12</number>
+ </property>
+ <property name="value">
+ <number>6</number>
+ </property>
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="lblGraphRange">
+ <property name="minimumSize">
+ <size>
+ <width>100</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="btnClearTrafficGraph">
+ <property name="text">
+ <string>&amp;Clear</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QGroupBox" name="groupBox">
+ <property name="title">
+ <string>Totals</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_5">
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_4">
+ <item>
+ <widget class="Line" name="line">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>10</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="palette">
+ <palette>
+ <active>
+ <colorrole role="Light">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>0</red>
+ <green>255</green>
+ <blue>0</blue>
+ </color>
+ </brush>
+ </colorrole>
+ </active>
+ <inactive>
+ <colorrole role="Light">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>0</red>
+ <green>255</green>
+ <blue>0</blue>
+ </color>
+ </brush>
+ </colorrole>
+ </inactive>
+ <disabled>
+ <colorrole role="Light">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>0</red>
+ <green>255</green>
+ <blue>0</blue>
+ </color>
+ </brush>
+ </colorrole>
+ </disabled>
+ </palette>
+ </property>
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_16">
+ <property name="text">
+ <string>In:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="lblBytesIn">
+ <property name="minimumSize">
+ <size>
+ <width>50</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_5">
+ <item>
+ <widget class="Line" name="line_2">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>10</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="palette">
+ <palette>
+ <active>
+ <colorrole role="Light">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>255</red>
+ <green>0</green>
+ <blue>0</blue>
+ </color>
+ </brush>
+ </colorrole>
+ </active>
+ <inactive>
+ <colorrole role="Light">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>255</red>
+ <green>0</green>
+ <blue>0</blue>
+ </color>
+ </brush>
+ </colorrole>
+ </inactive>
+ <disabled>
+ <colorrole role="Light">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>255</red>
+ <green>0</green>
+ <blue>0</blue>
+ </color>
+ </brush>
+ </colorrole>
+ </disabled>
+ </palette>
+ </property>
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_17">
+ <property name="text">
+ <string>Out:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="lblBytesOut">
+ <property name="minimumSize">
+ <size>
+ <width>50</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <spacer name="verticalSpacer_4">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>407</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
</widget>
</item>
</layout>
</widget>
+ <customwidgets>
+ <customwidget>
+ <class>TrafficGraphWidget</class>
+ <extends>QWidget</extends>
+ <header>trafficgraphwidget.h</header>
+ <container>1</container>
+ <slots>
+ <slot>clear()</slot>
+ </slots>
+ </customwidget>
+ </customwidgets>
<resources>
<include location="../bitcoin.qrc"/>
</resources>
diff --git a/src/qt/forms/sendcoinsentry.ui b/src/qt/forms/sendcoinsentry.ui
index a2ef9a0a38..5c6afd6c71 100644
--- a/src/qt/forms/sendcoinsentry.ui
+++ b/src/qt/forms/sendcoinsentry.ui
@@ -10,19 +10,13 @@
<height>150</height>
</rect>
</property>
- <property name="windowTitle">
- <string>StackedWidget</string>
- </property>
<property name="autoFillBackground">
<bool>false</bool>
</property>
<property name="currentIndex">
- <number>1</number>
+ <number>0</number>
</property>
<widget class="QFrame" name="SendCoinsInsecure">
- <property name="windowTitle">
- <string>Form</string>
- </property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
@@ -34,7 +28,7 @@
<number>12</number>
</property>
<item row="5" column="0">
- <widget class="QLabel" name="label">
+ <widget class="QLabel" name="amountLabel">
<property name="text">
<string>A&amp;mount:</string>
</property>
@@ -47,7 +41,7 @@
</widget>
</item>
<item row="3" column="0">
- <widget class="QLabel" name="label_2">
+ <widget class="QLabel" name="payToLabel">
<property name="text">
<string>Pay &amp;To:</string>
</property>
@@ -63,7 +57,7 @@
<widget class="BitcoinAmountField" name="payAmount"/>
</item>
<item row="4" column="0">
- <widget class="QLabel" name="label_4">
+ <widget class="QLabel" name="labellLabel">
<property name="text">
<string>&amp;Label:</string>
</property>
@@ -592,9 +586,6 @@
</disabled>
</palette>
</property>
- <property name="windowTitle">
- <string>SecureSend</string>
- </property>
<property name="autoFillBackground">
<bool>true</bool>
</property>
@@ -609,7 +600,7 @@
<number>12</number>
</property>
<item row="4" column="0">
- <widget class="QLabel" name="label_s4">
+ <widget class="QLabel" name="memoLabel_s">
<property name="text">
<string>Memo:</string>
</property>
@@ -622,7 +613,7 @@
</widget>
</item>
<item row="5" column="0">
- <widget class="QLabel" name="label_s1">
+ <widget class="QLabel" name="amountLabel_s">
<property name="text">
<string>A&amp;mount:</string>
</property>
@@ -630,12 +621,12 @@
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
- <cstring>payAmount</cstring>
+ <cstring>payAmount_s</cstring>
</property>
</widget>
</item>
<item row="3" column="0">
- <widget class="QLabel" name="label_s2">
+ <widget class="QLabel" name="payToLabel_s">
<property name="text">
<string>Pay &amp;To:</string>
</property>
@@ -649,15 +640,9 @@
</item>
<item row="5" column="2">
<widget class="BitcoinAmountField" name="payAmount_s">
- <property name="enabled">
- <bool>false</bool>
- </property>
<property name="acceptDrops">
<bool>false</bool>
</property>
- <property name="readOnly">
- <bool>true</bool>
- </property>
</widget>
</item>
<item row="3" column="2">
@@ -667,14 +652,17 @@
</property>
<item>
<widget class="QLabel" name="payTo_s">
+ <property name="textFormat">
+ <enum>Qt::PlainText</enum>
+ </property>
</widget>
</item>
</layout>
</item>
<item row="4" column="2">
- <widget class="QLabel" name="memo_s">
- <property name="text">
- <string>message from merchant</string>
+ <widget class="QLabel" name="memoTextLabel_s">
+ <property name="textFormat">
+ <enum>Qt::PlainText</enum>
</property>
</widget>
</item>
diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp
index 72f75b42e6..96ba997943 100644
--- a/src/qt/paymentserver.cpp
+++ b/src/qt/paymentserver.cpp
@@ -48,6 +48,7 @@ const int BITCOIN_IPC_CONNECT_TIMEOUT = 1000; // milliseconds
const QString BITCOIN_IPC_PREFIX("bitcoin:");
const char* BITCOIN_REQUEST_MIMETYPE = "application/bitcoin-paymentrequest";
const char* BITCOIN_PAYMENTACK_MIMETYPE = "application/bitcoin-paymentack";
+const char* BITCOIN_PAYMENTACK_CONTENTTYPE = "application/bitcoin-payment";
X509_STORE* PaymentServer::certStore = NULL;
void PaymentServer::freeCertStore()
@@ -471,11 +472,7 @@ bool PaymentServer::processPaymentRequest(PaymentRequestPlus& request, QList<Sen
recipients.append(SendCoinsRecipient());
recipients[i].amount = sendingTo.second;
QString memo = QString::fromStdString(request.getDetails().memo());
-#if QT_VERSION < 0x050000
- recipients[i].label = Qt::escape(memo);
-#else
- recipients[i].label = memo.toHtmlEscaped();
-#endif
+ recipients[i].label = GUIUtil::HtmlEscape(memo);
CTxDestination dest;
if (ExtractDestination(sendingTo.first, dest)) {
if (i == 0) // Tie request to first pay-to, we don't want multiple ACKs
@@ -518,7 +515,7 @@ void PaymentServer::fetchPaymentACK(CWallet* wallet, SendCoinsRecipient recipien
QNetworkRequest netRequest;
netRequest.setAttribute(QNetworkRequest::User, "PaymentACK");
netRequest.setUrl(QString::fromStdString(details.payment_url()));
- netRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/bitcoin-payment");
+ netRequest.setHeader(QNetworkRequest::ContentTypeHeader, BITCOIN_PAYMENTACK_CONTENTTYPE);
netRequest.setRawHeader("User-Agent", CLIENT_NAME.c_str());
netRequest.setRawHeader("Accept", BITCOIN_PAYMENTACK_MIMETYPE);
diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp
index 8953c36579..e7dcdf62a1 100644
--- a/src/qt/rpcconsole.cpp
+++ b/src/qt/rpcconsole.cpp
@@ -22,6 +22,8 @@
const int CONSOLE_HISTORY = 50;
const QSize ICON_SIZE(24, 24);
+const int INITIAL_TRAFFIC_GRAPH_MINS = 30;
+
const struct {
const char *url;
const char *source;
@@ -204,6 +206,7 @@ RPCConsole::RPCConsole(QWidget *parent) :
ui->openSSLVersion->setText(SSLeay_version(SSLEAY_VERSION));
startExecutor();
+ setTrafficGraphRange(INITIAL_TRAFFIC_GRAPH_MINS);
clear();
}
@@ -253,7 +256,8 @@ bool RPCConsole::eventFilter(QObject* obj, QEvent *event)
void RPCConsole::setClientModel(ClientModel *model)
{
- this->clientModel = model;
+ clientModel = model;
+ ui->trafficGraph->setClientModel(model);
if(model)
{
// Keep up to date with client
@@ -263,6 +267,9 @@ void RPCConsole::setClientModel(ClientModel *model)
setNumBlocks(model->getNumBlocks(), model->getNumBlocksOfPeers());
connect(model, SIGNAL(numBlocksChanged(int,int)), this, SLOT(setNumBlocks(int,int)));
+ updateTrafficStats(model->getTotalBytesRecv(), model->getTotalBytesSent());
+ connect(model, SIGNAL(bytesChanged(quint64,quint64)), this, SLOT(updateTrafficStats(quint64, quint64)));
+
// Provide initial values
ui->clientVersion->setText(model->formatFullVersion());
ui->clientName->setText(model->clientName());
@@ -431,3 +438,49 @@ void RPCConsole::on_showCLOptionsButton_clicked()
GUIUtil::HelpMessageBox help;
help.exec();
}
+
+void RPCConsole::on_sldGraphRange_valueChanged(int value)
+{
+ const int multiplier = 5; // each position on the slider represents 5 min
+ int mins = value * multiplier;
+ setTrafficGraphRange(mins);
+}
+
+QString RPCConsole::FormatBytes(quint64 bytes)
+{
+ if(bytes < 1024)
+ return QString(tr("%1 B")).arg(bytes);
+ if(bytes < 1024 * 1024)
+ return QString(tr("%1 KB")).arg(bytes / 1024);
+ if(bytes < 1024 * 1024 * 1024)
+ return QString(tr("%1 MB")).arg(bytes / 1024 / 1024);
+
+ return QString(tr("%1 GB")).arg(bytes / 1024 / 1024 / 1024);
+}
+
+void RPCConsole::setTrafficGraphRange(int mins)
+{
+ ui->trafficGraph->setGraphRangeMins(mins);
+ if(mins < 60) {
+ ui->lblGraphRange->setText(QString(tr("%1 m")).arg(mins));
+ } else {
+ int hours = mins / 60;
+ int minsLeft = mins % 60;
+ if(minsLeft == 0) {
+ ui->lblGraphRange->setText(QString(tr("%1 h")).arg(hours));
+ } else {
+ ui->lblGraphRange->setText(QString(tr("%1 h %2 m")).arg(hours).arg(minsLeft));
+ }
+ }
+}
+
+void RPCConsole::updateTrafficStats(quint64 totalBytesIn, quint64 totalBytesOut)
+{
+ ui->lblBytesIn->setText(FormatBytes(totalBytesIn));
+ ui->lblBytesOut->setText(FormatBytes(totalBytesOut));
+}
+
+void RPCConsole::on_btnClearTrafficGraph_clicked()
+{
+ ui->trafficGraph->clear();
+}
diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h
index 3c38b4b8de..af92b55770 100644
--- a/src/qt/rpcconsole.h
+++ b/src/qt/rpcconsole.h
@@ -37,6 +37,12 @@ private slots:
void on_openDebugLogfileButton_clicked();
/** display messagebox with program parameters (same as bitcoin-qt --help) */
void on_showCLOptionsButton_clicked();
+ /** change the time range of the network traffic graph */
+ void on_sldGraphRange_valueChanged(int value);
+ /** update traffic statistics */
+ void updateTrafficStats(quint64 totalBytesIn, quint64 totalBytesOut);
+ /** clear traffic graph */
+ void on_btnClearTrafficGraph_clicked();
public slots:
void clear();
@@ -55,6 +61,9 @@ signals:
void cmdRequest(const QString &command);
private:
+ static QString FormatBytes(quint64 bytes);
+ void setTrafficGraphRange(int mins);
+
Ui::RPCConsole *ui;
ClientModel *clientModel;
QStringList history;
diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp
index 809eff9c27..3fd4a26e76 100644
--- a/src/qt/sendcoinsdialog.cpp
+++ b/src/qt/sendcoinsdialog.cpp
@@ -94,27 +94,33 @@ void SendCoinsDialog::on_sendButton_clicked()
QStringList formatted;
foreach(const SendCoinsRecipient &rcp, recipients)
{
- QString amount = BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), rcp.amount);
+ // generate bold amount string
+ QString amount = "<b>" + BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), rcp.amount);
+ amount.append("</b>");
+ // generate monospace address string
+ QString address = "<span style='font-family: monospace;'>" + rcp.address;
+ address.append("</span>");
+
+ QString recipientElement;
+
if (rcp.authenticatedMerchant.isEmpty())
{
- QString recipientElement = QString("<b>%1</b> ").arg(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), rcp.amount));
- recipientElement.append(tr("to"));
-
- if(rcp.label.length() > 0)
+ if(rcp.label.length() > 0) // label with address
{
- recipientElement.append(QString(" %1 <span style='font-size:8px;'>%2</span><br />").arg(GUIUtil::HtmlEscape(rcp.label), rcp.address)); // add address with label
+ recipientElement = tr("%1 to %2").arg(amount, GUIUtil::HtmlEscape(rcp.label));
+ recipientElement.append(QString(" (%1)").arg(address));
}
- else
+ else // just address
{
- recipientElement.append(QString(" %1<br />").arg(rcp.address)); // add address WITHOUT label
+ recipientElement = tr("%1 to %2").arg(amount, address);
}
- formatted.append(recipientElement);
}
- else
+ else // just merchant
{
- QString merchant = GUIUtil::HtmlEscape(rcp.authenticatedMerchant);
- formatted.append(tr("<b>%1</b> to %2").arg(amount, merchant));
+ recipientElement = tr("%1 to %2").arg(amount, GUIUtil::HtmlEscape(rcp.authenticatedMerchant));
}
+
+ formatted.append(recipientElement);
}
fNewRecipientAllowed = false;
@@ -132,42 +138,38 @@ void SendCoinsDialog::on_sendButton_clicked()
WalletModelTransaction currentTransaction(recipients);
WalletModel::SendCoinsReturn prepareStatus = model->prepareTransaction(currentTransaction);
+ QString strSendCoins = tr("Send Coins");
switch(prepareStatus.status)
{
case WalletModel::InvalidAddress:
- QMessageBox::warning(this, tr("Send Coins"),
- tr("The recipient address is not valid, please recheck."),
- QMessageBox::Ok, QMessageBox::Ok);
+ QMessageBox::warning(this, strSendCoins,
+ tr("The recipient address is not valid, please recheck."));
break;
case WalletModel::InvalidAmount:
- QMessageBox::warning(this, tr("Send Coins"),
- tr("The amount to pay must be larger than 0."),
- QMessageBox::Ok, QMessageBox::Ok);
+ QMessageBox::warning(this, strSendCoins,
+ tr("The amount to pay must be larger than 0."));
break;
case WalletModel::AmountExceedsBalance:
- QMessageBox::warning(this, tr("Send Coins"),
- tr("The amount exceeds your balance."),
- QMessageBox::Ok, QMessageBox::Ok);
+ QMessageBox::warning(this, strSendCoins,
+ tr("The amount exceeds your balance."));
break;
case WalletModel::AmountWithFeeExceedsBalance:
- QMessageBox::warning(this, tr("Send Coins"),
+ QMessageBox::warning(this, strSendCoins,
tr("The total exceeds your balance when the %1 transaction fee is included.").
- arg(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), currentTransaction.getTransactionFee())),
- QMessageBox::Ok, QMessageBox::Ok);
+ arg(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), currentTransaction.getTransactionFee())));
break;
case WalletModel::DuplicateAddress:
- QMessageBox::warning(this, tr("Send Coins"),
- tr("Duplicate address found, can only send to each address once per send operation."),
- QMessageBox::Ok, QMessageBox::Ok);
+ QMessageBox::warning(this, strSendCoins,
+ tr("Duplicate address found, can only send to each address once per send operation."));
break;
case WalletModel::TransactionCreationFailed:
- QMessageBox::warning(this, tr("Send Coins"),
- tr("Error: Transaction creation failed!"),
- QMessageBox::Ok, QMessageBox::Ok);
+ QMessageBox::warning(this, strSendCoins,
+ tr("Error: Transaction creation failed!"));
break;
- case WalletModel::Aborted: // User aborted, nothing to do
- case WalletModel::OK:
case WalletModel::TransactionCommitFailed:
+ case WalletModel::OK:
+ case WalletModel::Aborted: // User aborted, nothing to do
+ default:
break;
}
@@ -197,7 +199,7 @@ void SendCoinsDialog::on_sendButton_clicked()
QMessageBox::StandardButton retval = QMessageBox::question(this, tr("Confirm send coins"),
questionString.arg(formatted.join("<br />")),
- QMessageBox::Yes|QMessageBox::Cancel,
+ QMessageBox::Yes | QMessageBox::Cancel,
QMessageBox::Cancel);
if(retval != QMessageBox::Yes)
@@ -211,15 +213,13 @@ void SendCoinsDialog::on_sendButton_clicked()
switch(sendstatus.status)
{
case WalletModel::TransactionCommitFailed:
- QMessageBox::warning(this, tr("Send Coins"),
- tr("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."),
- QMessageBox::Ok, QMessageBox::Ok);
- break;
- case WalletModel::Aborted: // User aborted, nothing to do
+ QMessageBox::warning(this, strSendCoins,
+ tr("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."));
break;
case WalletModel::OK:
accept();
break;
+ case WalletModel::Aborted: // User aborted, nothing to do
default:
break;
}
@@ -351,22 +351,22 @@ void SendCoinsDialog::pasteEntry(const SendCoinsRecipient &rv)
bool SendCoinsDialog::handlePaymentRequest(const SendCoinsRecipient &rv)
{
+ QString strSendCoins = tr("Send Coins");
if (!rv.authenticatedMerchant.isEmpty()) {
// Expired payment request?
const payments::PaymentDetails& details = rv.paymentRequest.getDetails();
if (details.has_expires() && (int64)details.expires() < GetTime())
{
- QMessageBox::warning(this, tr("Send Coins"),
- tr("Payment request expired"));
+ QMessageBox::warning(this, strSendCoins,
+ tr("Payment request expired"));
return false;
}
}
else {
CBitcoinAddress address(rv.address.toStdString());
if (!address.IsValid()) {
- QString strAddress(address.ToString().c_str());
- QMessageBox::warning(this, tr("Send Coins"),
- tr("Invalid payment address %1").arg(strAddress));
+ QMessageBox::warning(this, strSendCoins,
+ tr("Invalid payment address %1").arg(rv.address));
return false;
}
}
diff --git a/src/qt/sendcoinsentry.cpp b/src/qt/sendcoinsentry.cpp
index 75610f199e..aa671e0540 100644
--- a/src/qt/sendcoinsentry.cpp
+++ b/src/qt/sendcoinsentry.cpp
@@ -85,10 +85,17 @@ void SendCoinsEntry::setRemoveEnabled(bool enabled)
void SendCoinsEntry::clear()
{
+ // clear UI elements for insecure payments
ui->payTo->clear();
ui->addAsLabel->clear();
ui->payAmount->clear();
+ // and the ones for secure payments just to be sure
+ ui->payTo_s->clear();
+ ui->memoTextLabel_s->clear();
+ ui->payAmount_s->clear();
+
ui->payTo->setFocus();
+
// update the display unit, to not use the default ("BTC")
updateDisplayUnit();
}
@@ -106,8 +113,8 @@ bool SendCoinsEntry::validate()
if (!recipient.authenticatedMerchant.isEmpty())
return retval;
- if(!ui->payTo->hasAcceptableInput() ||
- (model && !model->validateAddress(ui->payTo->text())))
+ if (!ui->payTo->hasAcceptableInput() ||
+ (model && !model->validateAddress(ui->payTo->text())))
{
ui->payTo->setValid(false);
retval = false;
@@ -154,18 +161,20 @@ void SendCoinsEntry::setValue(const SendCoinsRecipient &value)
{
recipient = value;
- ui->payTo->setText(value.address);
- ui->addAsLabel->setText(value.label);
- ui->payAmount->setValue(value.amount);
-
- if (!recipient.authenticatedMerchant.isEmpty())
+ if (recipient.authenticatedMerchant.isEmpty())
+ {
+ ui->payTo->setText(recipient.address);
+ ui->addAsLabel->setText(recipient.label);
+ ui->payAmount->setValue(recipient.amount);
+ }
+ else
{
- const payments::PaymentDetails& details = value.paymentRequest.getDetails();
+ const payments::PaymentDetails& details = recipient.paymentRequest.getDetails();
- ui->payTo_s->setText(value.authenticatedMerchant);
- ui->memo_s->setTextFormat(Qt::PlainText);
- ui->memo_s->setText(QString::fromStdString(details.memo()));
- ui->payAmount_s->setValue(value.amount);
+ ui->payTo_s->setText(recipient.authenticatedMerchant);
+ ui->memoTextLabel_s->setText(QString::fromStdString(details.memo()));
+ ui->payAmount_s->setValue(recipient.amount);
+ ui->payAmount_s->setReadOnly(true);
setCurrentWidget(ui->SendCoinsSecure);
}
}
diff --git a/src/qt/sendcoinsentry.h b/src/qt/sendcoinsentry.h
index 9c7bfe9521..49e622daf1 100644
--- a/src/qt/sendcoinsentry.h
+++ b/src/qt/sendcoinsentry.h
@@ -33,7 +33,8 @@ public:
void setValue(const SendCoinsRecipient &value);
void setAddress(const QString &address);
- /** Set up the tab chain manually, as Qt messes up the tab chain by default in some cases (issue https://bugreports.qt-project.org/browse/QTBUG-10907).
+ /** Set up the tab chain manually, as Qt messes up the tab chain by default in some cases
+ * (issue https://bugreports.qt-project.org/browse/QTBUG-10907).
*/
QWidget *setupTabChain(QWidget *prev);
diff --git a/src/qt/test/Makefile.am b/src/qt/test/Makefile.am
index f51ac9bd6d..f8fe97462b 100644
--- a/src/qt/test/Makefile.am
+++ b/src/qt/test/Makefile.am
@@ -4,7 +4,7 @@ AM_CPPFLAGS = $(INCLUDES) -I$(top_builddir)/src/obj \
-I$(top_srcdir)/src/leveldb/include -I$(top_srcdir)/src \
-I$(top_srcdir)/src/leveldb/helpers -I$(top_srcdir)/src/qt \
-I$(top_builddir)/src/qt $(BOOST_INCLUDES) $(PROTOBUF_CFLAGS) \
- $(QR_CFLAGS)
+ $(QR_CFLAGS) $(BDB_CPPFLAGS)
AM_LDFLAGS = $(PTHREAD_CFLAGS)
bin_PROGRAMS = test_bitcoin-qt
TESTS = test_bitcoin-qt
@@ -20,7 +20,7 @@ test_bitcoin_qt_SOURCES = test_main.cpp uritests.cpp paymentservertests.cpp $(TE
nodist_test_bitcoin_qt_SOURCES = $(TEST_QT_MOC_CPP)
test_bitcoin_qt_LDADD = $(LIBBITCOINQT) $(LIBBITCOIN) $(LIBLEVELDB) \
$(LIBMEMENV) $(BOOST_LIBS) $(QT_LIBS) $(QT_DBUS_LIBS) $(QT_TEST_LIBS) \
- $(QR_LIBS) $(PROTOBUF_LIBS)
+ $(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS)
CLEANFILES = $(BUILT_SOURCES) *.gcda *.gcno
diff --git a/src/qt/trafficgraphwidget.cpp b/src/qt/trafficgraphwidget.cpp
new file mode 100644
index 0000000000..d49bc31f3e
--- /dev/null
+++ b/src/qt/trafficgraphwidget.cpp
@@ -0,0 +1,169 @@
+#include "trafficgraphwidget.h"
+#include "clientmodel.h"
+
+#include <QPainter>
+#include <QColor>
+#include <QTimer>
+
+#include <cmath>
+
+#define DESIRED_SAMPLES 800
+
+#define XMARGIN 10
+#define YMARGIN 10
+
+TrafficGraphWidget::TrafficGraphWidget(QWidget *parent) :
+ QWidget(parent),
+ timer(0),
+ fMax(0.0f),
+ nMins(0),
+ vSamplesIn(),
+ vSamplesOut(),
+ nLastBytesIn(0),
+ nLastBytesOut(0),
+ clientModel(0)
+{
+ timer = new QTimer(this);
+ connect(timer, SIGNAL(timeout()), SLOT(updateRates()));
+}
+
+void TrafficGraphWidget::setClientModel(ClientModel *model)
+{
+ clientModel = model;
+ if(model) {
+ nLastBytesIn = model->getTotalBytesRecv();
+ nLastBytesOut = model->getTotalBytesSent();
+ }
+}
+
+int TrafficGraphWidget::getGraphRangeMins() const
+{
+ return nMins;
+}
+
+void TrafficGraphWidget::paintPath(QPainterPath &path, QQueue<float> &samples)
+{
+ int h = height() - YMARGIN * 2, w = width() - XMARGIN * 2;
+ int sampleCount = samples.size(), x = XMARGIN + w, y;
+ if(sampleCount > 0) {
+ path.moveTo(x, YMARGIN + h);
+ for(int i = 0; i < sampleCount; ++i) {
+ x = XMARGIN + w - w * i / DESIRED_SAMPLES;
+ y = YMARGIN + h - (int)(h * samples.at(i) / fMax);
+ path.lineTo(x, y);
+ }
+ path.lineTo(x, YMARGIN + h);
+ }
+}
+
+void TrafficGraphWidget::paintEvent(QPaintEvent *)
+{
+ QPainter painter(this);
+ painter.fillRect(rect(), Qt::black);
+
+ if(fMax <= 0.0f) return;
+
+ QColor axisCol(Qt::gray);
+ int h = height() - YMARGIN * 2;
+ painter.setPen(axisCol);
+ painter.drawLine(XMARGIN, YMARGIN + h, width() - XMARGIN, YMARGIN + h);
+
+ // decide what order of magnitude we are
+ int base = floor(log10(fMax));
+ float val = pow(10.0f, base);
+
+ const QString units = tr("KB/s");
+ // draw lines
+ painter.setPen(axisCol);
+ painter.drawText(XMARGIN, YMARGIN + h - h * val / fMax, QString("%1 %2").arg(val).arg(units));
+ for(float y = val; y < fMax; y += val) {
+ int yy = YMARGIN + h - h * y / fMax;
+ painter.drawLine(XMARGIN, yy, width() - XMARGIN, yy);
+ }
+ // if we drew 3 or fewer lines, break them up at the next lower order of magnitude
+ if(fMax / val <= 3.0f) {
+ axisCol = axisCol.darker();
+ val = pow(10.0f, base - 1);
+ painter.setPen(axisCol);
+ painter.drawText(XMARGIN, YMARGIN + h - h * val / fMax, QString("%1 %2").arg(val).arg(units));
+ int count = 1;
+ for(float y = val; y < fMax; y += val, count++) {
+ // don't overwrite lines drawn above
+ if(count % 10 == 0)
+ continue;
+ int yy = YMARGIN + h - h * y / fMax;
+ painter.drawLine(XMARGIN, yy, width() - XMARGIN, yy);
+ }
+ }
+
+ if(!vSamplesIn.empty()) {
+ QPainterPath p;
+ paintPath(p, vSamplesIn);
+ painter.fillPath(p, QColor(0, 255, 0, 128));
+ painter.setPen(Qt::green);
+ painter.drawPath(p);
+ }
+ if(!vSamplesOut.empty()) {
+ QPainterPath p;
+ paintPath(p, vSamplesOut);
+ painter.fillPath(p, QColor(255, 0, 0, 128));
+ painter.setPen(Qt::red);
+ painter.drawPath(p);
+ }
+}
+
+void TrafficGraphWidget::updateRates()
+{
+ if(!clientModel) return;
+
+ quint64 bytesIn = clientModel->getTotalBytesRecv(),
+ bytesOut = clientModel->getTotalBytesSent();
+ float inRate = (bytesIn - nLastBytesIn) / 1024.0f * 1000 / timer->interval();
+ float outRate = (bytesOut - nLastBytesOut) / 1024.0f * 1000 / timer->interval();
+ vSamplesIn.push_front(inRate);
+ vSamplesOut.push_front(outRate);
+ nLastBytesIn = bytesIn;
+ nLastBytesOut = bytesOut;
+
+ while(vSamplesIn.size() > DESIRED_SAMPLES) {
+ vSamplesIn.pop_back();
+ }
+ while(vSamplesOut.size() > DESIRED_SAMPLES) {
+ vSamplesOut.pop_back();
+ }
+
+ float tmax = 0.0f;
+ foreach(float f, vSamplesIn) {
+ if(f > tmax) tmax = f;
+ }
+ foreach(float f, vSamplesOut) {
+ if(f > tmax) tmax = f;
+ }
+ fMax = tmax;
+ update();
+}
+
+void TrafficGraphWidget::setGraphRangeMins(int mins)
+{
+ nMins = mins;
+ int msecsPerSample = nMins * 60 * 1000 / DESIRED_SAMPLES;
+ timer->stop();
+ timer->setInterval(msecsPerSample);
+
+ clear();
+}
+
+void TrafficGraphWidget::clear()
+{
+ timer->stop();
+
+ vSamplesOut.clear();
+ vSamplesIn.clear();
+ fMax = 0.0f;
+
+ if(clientModel) {
+ nLastBytesIn = clientModel->getTotalBytesRecv();
+ nLastBytesOut = clientModel->getTotalBytesSent();
+ }
+ timer->start();
+}
diff --git a/src/qt/trafficgraphwidget.h b/src/qt/trafficgraphwidget.h
new file mode 100644
index 0000000000..b31d1d5b0a
--- /dev/null
+++ b/src/qt/trafficgraphwidget.h
@@ -0,0 +1,44 @@
+#ifndef TRAFFICGRAPHWIDGET_H
+#define TRAFFICGRAPHWIDGET_H
+
+#include <QWidget>
+#include <QQueue>
+
+class ClientModel;
+
+QT_BEGIN_NAMESPACE
+class QPaintEvent;
+class QTimer;
+QT_END_NAMESPACE
+
+class TrafficGraphWidget : public QWidget
+{
+ Q_OBJECT
+
+public:
+ explicit TrafficGraphWidget(QWidget *parent = 0);
+ void setClientModel(ClientModel *model);
+ int getGraphRangeMins() const;
+
+protected:
+ void paintEvent(QPaintEvent *);
+
+public slots:
+ void updateRates();
+ void setGraphRangeMins(int mins);
+ void clear();
+
+private:
+ void paintPath(QPainterPath &path, QQueue<float> &samples);
+
+ QTimer *timer;
+ float fMax;
+ int nMins;
+ QQueue<float> vSamplesIn;
+ QQueue<float> vSamplesOut;
+ quint64 nLastBytesIn;
+ quint64 nLastBytesOut;
+ ClientModel *clientModel;
+};
+
+#endif // TRAFFICGRAPHWIDGET_H
diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp
index e27aa93a4a..93fc8cab22 100644
--- a/src/qt/transactiondesc.cpp
+++ b/src/qt/transactiondesc.cpp
@@ -17,7 +17,7 @@ QString TransactionDesc::FormatTxStatus(const CWalletTx& wtx)
if (!IsFinalTx(wtx))
{
if (wtx.nLockTime < LOCKTIME_THRESHOLD)
- return tr("Open for %n more block(s)", "", wtx.nLockTime - nBestHeight + 1);
+ return tr("Open for %n more block(s)", "", wtx.nLockTime - chainActive.Height() + 1);
else
return tr("Open until %1").arg(GUIUtil::dateTimeStr(wtx.nLockTime));
}
diff --git a/src/qt/transactionrecord.cpp b/src/qt/transactionrecord.cpp
index ea2c1f0a5c..162908a9a4 100644
--- a/src/qt/transactionrecord.cpp
+++ b/src/qt/transactionrecord.cpp
@@ -160,14 +160,14 @@ void TransactionRecord::updateStatus(const CWalletTx &wtx)
idx);
status.confirmed = wtx.IsConfirmed();
status.depth = wtx.GetDepthInMainChain();
- status.cur_num_blocks = nBestHeight;
+ status.cur_num_blocks = chainActive.Height();
if (!IsFinalTx(wtx))
{
if (wtx.nLockTime < LOCKTIME_THRESHOLD)
{
status.status = TransactionStatus::OpenUntilBlock;
- status.open_for = wtx.nLockTime - nBestHeight + 1;
+ status.open_for = wtx.nLockTime - chainActive.Height() + 1;
}
else
{
@@ -221,7 +221,7 @@ void TransactionRecord::updateStatus(const CWalletTx &wtx)
bool TransactionRecord::statusUpdateNeeded()
{
- return status.cur_num_blocks != nBestHeight;
+ return status.cur_num_blocks != chainActive.Height();
}
QString TransactionRecord::getTxID() const
diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp
index 07f6a62150..6f7a5933ab 100644
--- a/src/qt/transactiontablemodel.cpp
+++ b/src/qt/transactiontablemodel.cpp
@@ -250,9 +250,9 @@ void TransactionTableModel::updateTransaction(const QString &hash, int status)
void TransactionTableModel::updateConfirmations()
{
- if(nBestHeight != cachedNumBlocks)
+ if(chainActive.Height() != cachedNumBlocks)
{
- cachedNumBlocks = nBestHeight;
+ cachedNumBlocks = chainActive.Height();
// 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
diff --git a/src/qt/walletframe.cpp b/src/qt/walletframe.cpp
index 99a6647a65..8d6a1b387e 100644
--- a/src/qt/walletframe.cpp
+++ b/src/qt/walletframe.cpp
@@ -56,12 +56,9 @@ bool WalletFrame::handlePaymentRequest(const SendCoinsRecipient &recipient)
void WalletFrame::showOutOfSyncWarning(bool fShow)
{
- if (!walletStack) {
- QMessageBox box;
- box.setText("walletStack is null");
- box.exec();
+ if (!walletStack)
return;
- }
+
walletStack->showOutOfSyncWarning(fShow);
}
diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp
index 1dcecbe60b..417bac9928 100644
--- a/src/qt/walletmodel.cpp
+++ b/src/qt/walletmodel.cpp
@@ -73,10 +73,10 @@ void WalletModel::updateStatus()
void WalletModel::pollBalanceChanged()
{
- if(nBestHeight != cachedNumBlocks)
+ if(chainActive.Height() != cachedNumBlocks)
{
// Balance and number of transactions might have changed
- cachedNumBlocks = nBestHeight;
+ cachedNumBlocks = chainActive.Height();
checkBalanceChanged();
}
}
@@ -143,7 +143,7 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact
foreach(const SendCoinsRecipient &rcp, recipients)
{
if (rcp.paymentRequest.IsInitialized())
- { // PaymentRequest...
+ { // PaymentRequest...
int64 subtotal = 0;
const payments::PaymentDetails& details = rcp.paymentRequest.getDetails();
for (int i = 0; i < details.outputs_size(); i++)
@@ -258,22 +258,26 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(WalletModelTransaction &tran
// and emit coinsSent signal for each recipient
foreach(const SendCoinsRecipient &rcp, transaction.getRecipients())
{
- std::string strAddress = rcp.address.toStdString();
- CTxDestination dest = CBitcoinAddress(strAddress).Get();
- std::string strLabel = rcp.label.toStdString();
+ // Don't touch the address book when we have a secure payment-request
+ if (rcp.authenticatedMerchant.isEmpty())
{
- LOCK(wallet->cs_wallet);
-
- std::map<CTxDestination, CAddressBookData>::iterator mi = wallet->mapAddressBook.find(dest);
-
- // Check if we have a new address or an updated label
- if (mi == wallet->mapAddressBook.end())
- {
- wallet->SetAddressBook(dest, strLabel, "send");
- }
- else if (mi->second.name != strLabel)
+ std::string strAddress = rcp.address.toStdString();
+ CTxDestination dest = CBitcoinAddress(strAddress).Get();
+ std::string strLabel = rcp.label.toStdString();
{
- wallet->SetAddressBook(dest, strLabel, ""); // "" means don't change purpose
+ LOCK(wallet->cs_wallet);
+
+ std::map<CTxDestination, CAddressBookData>::iterator mi = wallet->mapAddressBook.find(dest);
+
+ // Check if we have a new address or an updated label
+ if (mi == wallet->mapAddressBook.end())
+ {
+ wallet->SetAddressBook(dest, strLabel, "send");
+ }
+ else if (mi->second.name != strLabel)
+ {
+ wallet->SetAddressBook(dest, strLabel, ""); // "" means don't change purpose
+ }
}
}
emit coinsSent(wallet, rcp, transaction_array);
diff --git a/src/qt/walletmodeltransaction.cpp b/src/qt/walletmodeltransaction.cpp
index 96fc3edbb2..706ed60b77 100644
--- a/src/qt/walletmodeltransaction.cpp
+++ b/src/qt/walletmodeltransaction.cpp
@@ -32,7 +32,7 @@ qint64 WalletModelTransaction::getTransactionFee()
void WalletModelTransaction::setTransactionFee(qint64 newFee)
{
- fee=newFee;
+ fee = newFee;
}
qint64 WalletModelTransaction::getTotalTransactionAmount()
@@ -40,7 +40,7 @@ qint64 WalletModelTransaction::getTotalTransactionAmount()
qint64 totalTransactionAmount = 0;
foreach(const SendCoinsRecipient &rcp, recipients)
{
- totalTransactionAmount+=rcp.amount;
+ totalTransactionAmount += rcp.amount;
}
return totalTransactionAmount;
}
diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp
index 398f33605a..957241d6a0 100644
--- a/src/rpcblockchain.cpp
+++ b/src/rpcblockchain.cpp
@@ -17,10 +17,10 @@ double GetDifficulty(const CBlockIndex* blockindex)
// minimum difficulty = 1.0.
if (blockindex == NULL)
{
- if (pindexBest == NULL)
+ if (chainActive.Tip() == NULL)
return 1.0;
else
- blockindex = pindexBest;
+ blockindex = chainActive.Tip();
}
int nShift = (blockindex->nBits >> 24) & 0xff;
@@ -66,7 +66,7 @@ Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex)
if (blockindex->pprev)
result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex()));
- CBlockIndex *pnext = blockindex->GetNextInMainChain();
+ CBlockIndex *pnext = chainActive.Next(blockindex);
if (pnext)
result.push_back(Pair("nextblockhash", pnext->GetBlockHash().GetHex()));
return result;
@@ -80,7 +80,7 @@ Value getblockcount(const Array& params, bool fHelp)
"getblockcount\n"
"Returns the number of blocks in the longest block chain.");
- return nBestHeight;
+ return chainActive.Height();
}
Value getbestblockhash(const Array& params, bool fHelp)
@@ -90,7 +90,7 @@ Value getbestblockhash(const Array& params, bool fHelp)
"getbestblockhash\n"
"Returns the hash of the best (tip) block in the longest block chain.");
- return hashBestChain.GetHex();
+ return chainActive.Tip()->GetBlockHash().GetHex();
}
Value getdifficulty(const Array& params, bool fHelp)
@@ -145,11 +145,11 @@ Value getblockhash(const Array& params, bool fHelp)
"Returns hash of block in best-block-chain at <index>.");
int nHeight = params[0].get_int();
- if (nHeight < 0 || nHeight > nBestHeight)
+ if (nHeight < 0 || nHeight > chainActive.Height())
throw runtime_error("Block number out of range.");
- CBlockIndex* pblockindex = FindBlockByHeight(nHeight);
- return pblockindex->phashBlock->GetHex();
+ CBlockIndex* pblockindex = chainActive[nHeight];
+ return pblockindex->GetBlockHash().GetHex();
}
Value getblock(const Array& params, bool fHelp)
diff --git a/src/rpcdump.cpp b/src/rpcdump.cpp
index 842910c7e0..61cd07d507 100644
--- a/src/rpcdump.cpp
+++ b/src/rpcdump.cpp
@@ -102,7 +102,7 @@ Value importprivkey(const Array& params, bool fHelp)
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet");
if (fRescan) {
- pwalletMain->ScanForWalletTransactions(pindexGenesisBlock, true);
+ pwalletMain->ScanForWalletTransactions(chainActive.Genesis(), true);
pwalletMain->ReacceptWalletTransactions();
}
}
@@ -124,7 +124,7 @@ Value importwallet(const Array& params, bool fHelp)
if (!file.is_open())
throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot open wallet dump file");
- int64 nTimeBegin = pindexBest->nTime;
+ int64 nTimeBegin = chainActive.Tip()->nTime;
bool fGood = true;
@@ -175,11 +175,11 @@ Value importwallet(const Array& params, bool fHelp)
}
file.close();
- CBlockIndex *pindex = pindexBest;
+ CBlockIndex *pindex = chainActive.Tip();
while (pindex && pindex->pprev && pindex->nTime > nTimeBegin - 7200)
pindex = pindex->pprev;
- LogPrintf("Rescanning last %i blocks\n", pindexBest->nHeight - pindex->nHeight + 1);
+ LogPrintf("Rescanning last %i blocks\n", chainActive.Height() - pindex->nHeight + 1);
pwalletMain->ScanForWalletTransactions(pindex);
pwalletMain->ReacceptWalletTransactions();
pwalletMain->MarkDirty();
@@ -243,8 +243,8 @@ Value dumpwallet(const Array& params, bool fHelp)
// produce output
file << strprintf("# Wallet dump created by Bitcoin %s (%s)\n", CLIENT_BUILD.c_str(), CLIENT_DATE.c_str());
file << strprintf("# * Created on %s\n", EncodeDumpTime(GetTime()).c_str());
- file << strprintf("# * Best block at time of backup was %i (%s),\n", nBestHeight, hashBestChain.ToString().c_str());
- file << strprintf("# mined on %s\n", EncodeDumpTime(pindexBest->nTime).c_str());
+ file << strprintf("# * Best block at time of backup was %i (%s),\n", chainActive.Height(), chainActive.Tip()->GetBlockHash().ToString().c_str());
+ file << strprintf("# mined on %s\n", EncodeDumpTime(chainActive.Tip()->nTime).c_str());
file << "\n";
for (std::vector<std::pair<int64, CKeyID> >::const_iterator it = vKeyBirth.begin(); it != vKeyBirth.end(); it++) {
const CKeyID &keyid = it->second;
diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp
index c7f516caa7..f123c3a9e0 100644
--- a/src/rpcmining.cpp
+++ b/src/rpcmining.cpp
@@ -18,15 +18,71 @@ static CReserveKey* pMiningKey = NULL;
void InitRPCMining()
{
+ if (!pwalletMain)
+ return;
+
// getwork/getblocktemplate mining rewards paid here:
pMiningKey = new CReserveKey(pwalletMain);
}
void ShutdownRPCMining()
{
+ if (!pMiningKey)
+ return;
+
delete pMiningKey; pMiningKey = NULL;
}
+// Return average network hashes per second based on the last 'lookup' blocks,
+// or from the last difficulty change if 'lookup' is nonpositive.
+// If 'height' is nonnegative, compute the estimate at the time when a given block was found.
+Value GetNetworkHashPS(int lookup, int height) {
+ CBlockIndex *pb = chainActive[height];
+
+ if (pb == NULL || !pb->nHeight)
+ return 0;
+
+ // If lookup is -1, then use blocks since last difficulty change.
+ if (lookup <= 0)
+ lookup = pb->nHeight % 2016 + 1;
+
+ // If lookup is larger than chain, then set it to chain length.
+ if (lookup > pb->nHeight)
+ lookup = pb->nHeight;
+
+ CBlockIndex *pb0 = pb;
+ int64 minTime = pb0->GetBlockTime();
+ int64 maxTime = minTime;
+ for (int i = 0; i < lookup; i++) {
+ pb0 = pb0->pprev;
+ int64 time = pb0->GetBlockTime();
+ minTime = std::min(time, minTime);
+ maxTime = std::max(time, maxTime);
+ }
+
+ // In case there's a situation where minTime == maxTime, we don't want a divide by zero exception.
+ if (minTime == maxTime)
+ return 0;
+
+ uint256 workDiff = pb->nChainWork - pb0->nChainWork;
+ int64 timeDiff = maxTime - minTime;
+
+ return (boost::int64_t)(workDiff.getdouble() / timeDiff);
+}
+
+Value getnetworkhashps(const Array& params, bool fHelp)
+{
+ if (fHelp || params.size() > 2)
+ throw runtime_error(
+ "getnetworkhashps [blocks] [height]\n"
+ "Returns the estimated network hashes per second based on the last 120 blocks.\n"
+ "Pass in [blocks] to override # of blocks, -1 specifies since last difficulty change.\n"
+ "Pass in [height] to estimate the network speed at the time when a certain block was found.");
+
+ return GetNetworkHashPS(params.size() > 0 ? params[0].get_int() : 120, params.size() > 1 ? params[1].get_int() : -1);
+}
+
+
Value getgenerate(const Array& params, bool fHelp)
{
if (fHelp || params.size() != 0)
@@ -34,6 +90,9 @@ Value getgenerate(const Array& params, bool fHelp)
"getgenerate\n"
"Returns true or false.");
+ if (!pMiningKey)
+ return false;
+
return GetBoolArg("-gen", false);
}
@@ -59,6 +118,7 @@ Value setgenerate(const Array& params, bool fHelp)
}
mapArgs["-gen"] = (fGenerate ? "1" : "0");
+ assert(pwalletMain != NULL);
GenerateBitcoins(fGenerate, pwalletMain);
return Value::null;
}
@@ -85,14 +145,15 @@ Value getmininginfo(const Array& params, bool fHelp)
"Returns an object containing mining-related information.");
Object obj;
- obj.push_back(Pair("blocks", (int)nBestHeight));
+ obj.push_back(Pair("blocks", (int)chainActive.Height()));
obj.push_back(Pair("currentblocksize", (uint64_t)nLastBlockSize));
obj.push_back(Pair("currentblocktx", (uint64_t)nLastBlockTx));
obj.push_back(Pair("difficulty", (double)GetDifficulty()));
obj.push_back(Pair("errors", GetWarnings("statusbar")));
- obj.push_back(Pair("generate", GetBoolArg("-gen", false)));
+ obj.push_back(Pair("generate", getgenerate(params, false)));
obj.push_back(Pair("genproclimit", (int)GetArg("-genproclimit", -1)));
obj.push_back(Pair("hashespersec", gethashespersec(params, false)));
+ obj.push_back(Pair("networkhashps", getnetworkhashps(params, false)));
obj.push_back(Pair("pooledtx", (uint64_t)mempool.size()));
obj.push_back(Pair("testnet", TestNet()));
return obj;
@@ -128,10 +189,10 @@ Value getwork(const Array& params, bool fHelp)
static CBlockIndex* pindexPrev;
static int64 nStart;
static CBlockTemplate* pblocktemplate;
- if (pindexPrev != pindexBest ||
+ if (pindexPrev != chainActive.Tip() ||
(nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60))
{
- if (pindexPrev != pindexBest)
+ if (pindexPrev != chainActive.Tip())
{
// Deallocate old blocks since they're obsolete now
mapNewBlock.clear();
@@ -145,7 +206,7 @@ Value getwork(const Array& params, bool fHelp)
// Store the pindexBest used before CreateNewBlock, to avoid races
nTransactionsUpdatedLast = nTransactionsUpdated;
- CBlockIndex* pindexPrevNew = pindexBest;
+ CBlockIndex* pindexPrevNew = chainActive.Tip();
nStart = GetTime();
// Create new block
@@ -207,6 +268,7 @@ Value getwork(const Array& params, bool fHelp)
pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second;
pblock->hashMerkleRoot = pblock->BuildMerkleTree();
+ assert(pwalletMain != NULL);
return CheckWork(pblock, *pwalletMain, *pMiningKey);
}
}
@@ -263,7 +325,7 @@ Value getblocktemplate(const Array& params, bool fHelp)
static CBlockIndex* pindexPrev;
static int64 nStart;
static CBlockTemplate* pblocktemplate;
- if (pindexPrev != pindexBest ||
+ if (pindexPrev != chainActive.Tip() ||
(nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 5))
{
// Clear pindexPrev so future calls make a new block, despite any failures from here on
@@ -271,7 +333,7 @@ Value getblocktemplate(const Array& params, bool fHelp)
// Store the pindexBest used before CreateNewBlock, to avoid races
nTransactionsUpdatedLast = nTransactionsUpdated;
- CBlockIndex* pindexPrevNew = pindexBest;
+ CBlockIndex* pindexPrevNew = chainActive.Tip();
nStart = GetTime();
// Create new block
diff --git a/src/rpcnet.cpp b/src/rpcnet.cpp
index bd7bc0ba10..f78f034e32 100644
--- a/src/rpcnet.cpp
+++ b/src/rpcnet.cpp
@@ -19,6 +19,24 @@ Value getconnectioncount(const Array& params, bool fHelp)
return (int)vNodes.size();
}
+Value ping(const Array& params, bool fHelp)
+{
+ if (fHelp || params.size() != 0)
+ throw runtime_error(
+ "ping\n"
+ "Requests that a ping be sent to all other nodes, to measure ping time.\n"
+ "Results provided in getpeerinfo, pingtime and pingwait fields are decimal seconds.\n"
+ "Ping command is handled in queue with all other commands, so it measures processing backlog, not just network ping.");
+
+ // Request that each node send a ping during next message processing pass
+ LOCK(cs_vNodes);
+ BOOST_FOREACH(CNode* pNode, vNodes) {
+ pNode->fPingQueued = true;
+ }
+
+ return Value::null;
+}
+
static void CopyNodeStats(std::vector<CNodeStats>& vstats)
{
vstats.clear();
@@ -54,6 +72,9 @@ Value getpeerinfo(const Array& params, bool fHelp)
obj.push_back(Pair("bytessent", (boost::int64_t)stats.nSendBytes));
obj.push_back(Pair("bytesrecv", (boost::int64_t)stats.nRecvBytes));
obj.push_back(Pair("conntime", (boost::int64_t)stats.nTimeConnected));
+ obj.push_back(Pair("pingtime", stats.dPingTime));
+ if (stats.dPingWait > 0.0)
+ obj.push_back(Pair("pingwait", stats.dPingWait));
obj.push_back(Pair("version", stats.nVersion));
obj.push_back(Pair("subver", stats.strSubVer));
obj.push_back(Pair("inbound", stats.fInbound));
@@ -202,3 +223,17 @@ Value getaddednodeinfo(const Array& params, bool fHelp)
return ret;
}
+Value getnettotals(const Array& params, bool fHelp)
+{
+ if (fHelp || params.size() > 0)
+ throw runtime_error(
+ "getnettotals\n"
+ "Returns information about network traffic, including bytes in, bytes out,\n"
+ "and current time.");
+
+ Object obj;
+ obj.push_back(Pair("totalbytesrecv", static_cast< boost::uint64_t>(CNode::GetTotalBytesRecv())));
+ obj.push_back(Pair("totalbytessent", static_cast<boost::uint64_t>(CNode::GetTotalBytesSent())));
+ obj.push_back(Pair("timemillis", static_cast<boost::int64_t>(GetTimeMillis())));
+ return obj;
+}
diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp
index ce9d60e667..5384b65906 100644
--- a/src/rpcrawtransaction.cpp
+++ b/src/rpcrawtransaction.cpp
@@ -87,9 +87,9 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry)
if (mi != mapBlockIndex.end() && (*mi).second)
{
CBlockIndex* pindex = (*mi).second;
- if (pindex->IsInMainChain())
+ if (chainActive.Contains(pindex))
{
- entry.push_back(Pair("confirmations", 1 + nBestHeight - pindex->nHeight));
+ entry.push_back(Pair("confirmations", 1 + chainActive.Height() - pindex->nHeight));
entry.push_back(Pair("time", (boost::int64_t)pindex->nTime));
entry.push_back(Pair("blocktime", (boost::int64_t)pindex->nTime));
}
@@ -171,6 +171,7 @@ Value listunspent(const Array& params, bool fHelp)
Array results;
vector<COutput> vecOutputs;
+ assert(pwalletMain != NULL);
pwalletMain->AvailableCoins(vecOutputs, false);
BOOST_FOREACH(const COutput& out, vecOutputs)
{
@@ -458,7 +459,7 @@ Value signrawtransaction(const Array& params, bool fHelp)
}
}
- const CKeyStore& keystore = (fGivenKeys ? tempKeystore : *pwalletMain);
+ const CKeyStore& keystore = ((fGivenKeys || !pwalletMain) ? tempKeystore : *pwalletMain);
int nHashType = SIGHASH_ALL;
if (params.size() > 3 && params[3].type() != null_type)
diff --git a/src/rpcwallet.cpp b/src/rpcwallet.cpp
index 46338bdf26..f7341f7b69 100644
--- a/src/rpcwallet.cpp
+++ b/src/rpcwallet.cpp
@@ -21,7 +21,7 @@ static CCriticalSection cs_nWalletUnlockTime;
std::string HelpRequiringPassphrase()
{
- return pwalletMain->IsCrypted()
+ return pwalletMain && pwalletMain->IsCrypted()
? "\nrequires wallet passphrase to be set with walletpassphrase first"
: "";
}
@@ -72,18 +72,22 @@ Value getinfo(const Array& params, bool fHelp)
Object obj;
obj.push_back(Pair("version", (int)CLIENT_VERSION));
obj.push_back(Pair("protocolversion",(int)PROTOCOL_VERSION));
- obj.push_back(Pair("walletversion", pwalletMain->GetVersion()));
- obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
- obj.push_back(Pair("blocks", (int)nBestHeight));
+ if (pwalletMain) {
+ obj.push_back(Pair("walletversion", pwalletMain->GetVersion()));
+ obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
+ }
+ obj.push_back(Pair("blocks", (int)chainActive.Height()));
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()));
obj.push_back(Pair("testnet", TestNet()));
- obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime()));
- obj.push_back(Pair("keypoolsize", (int)pwalletMain->GetKeyPoolSize()));
+ if (pwalletMain) {
+ obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime()));
+ obj.push_back(Pair("keypoolsize", (int)pwalletMain->GetKeyPoolSize()));
+ }
obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee)));
- if (pwalletMain->IsCrypted())
+ if (pwalletMain && pwalletMain->IsCrypted())
obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime));
obj.push_back(Pair("errors", GetWarnings("statusbar")));
return obj;
@@ -738,7 +742,7 @@ static CScript _createmultisig(const Array& params)
// Case 1: Bitcoin address and we have full public key:
CBitcoinAddress address(ks);
- if (address.IsValid())
+ if (pwalletMain && address.IsValid())
{
CKeyID keyID;
if (!address.GetKeyID(keyID))
@@ -1165,7 +1169,9 @@ Value listsinceblock(const Array& params, bool fHelp)
uint256 blockId = 0;
blockId.SetHex(params[0].get_str());
- pindex = CBlockLocator(blockId).GetBlockIndex();
+ std::map<uint256, CBlockIndex*>::iterator it = mapBlockIndex.find(blockId);
+ if (it != mapBlockIndex.end())
+ pindex = it->second;
}
if (params.size() > 1)
@@ -1176,7 +1182,7 @@ Value listsinceblock(const Array& params, bool fHelp)
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter");
}
- int depth = pindex ? (1 + nBestHeight - pindex->nHeight) : -1;
+ int depth = pindex ? (1 + chainActive.Height() - pindex->nHeight) : -1;
Array transactions;
@@ -1188,23 +1194,8 @@ Value listsinceblock(const Array& params, bool fHelp)
ListTransactions(tx, "*", 0, true, transactions);
}
- uint256 lastblock;
-
- if (target_confirms == 1)
- {
- lastblock = hashBestChain;
- }
- else
- {
- int target_height = pindexBest->nHeight + 1 - target_confirms;
-
- CBlockIndex *block;
- for (block = pindexBest;
- block && block->nHeight > target_height;
- block = block->pprev) { }
-
- lastblock = block ? block->GetBlockHash() : 0;
- }
+ CBlockIndex *pblockLast = chainActive[chainActive.Height() + 1 - target_confirms];
+ uint256 lastblock = pblockLast ? pblockLast->GetBlockHash() : 0;
Object ret;
ret.push_back(Pair("transactions", transactions));
@@ -1475,13 +1466,13 @@ Value validateaddress(const Array& params, bool fHelp)
CTxDestination dest = address.Get();
string currentAddress = address.ToString();
ret.push_back(Pair("address", currentAddress));
- bool fMine = IsMine(*pwalletMain, dest);
+ bool fMine = pwalletMain ? IsMine(*pwalletMain, dest) : false;
ret.push_back(Pair("ismine", fMine));
if (fMine) {
Object detail = boost::apply_visitor(DescribeAddressVisitor(), dest);
ret.insert(ret.end(), detail.begin(), detail.end());
}
- if (pwalletMain->mapAddressBook.count(dest))
+ if (pwalletMain && pwalletMain->mapAddressBook.count(dest))
ret.push_back(Pair("account", pwalletMain->mapAddressBook[dest].name));
}
return ret;
diff --git a/src/test/Makefile.am b/src/test/Makefile.am
index bedc5d0c29..c3495095d9 100644
--- a/src/test/Makefile.am
+++ b/src/test/Makefile.am
@@ -2,7 +2,7 @@ include $(top_srcdir)/src/Makefile.include
AM_CPPFLAGS = $(INCLUDES) -I$(top_builddir)/src/obj \
-I$(top_srcdir)/src/leveldb/include -I$(top_srcdir)/src/leveldb/helpers \
- -I$(top_srcdir)/src $(BOOST_INCLUDES)
+ -I$(top_srcdir)/src $(BOOST_INCLUDES) $(BDB_CPPFLAGS)
AM_LDFLAGS = $(PTHREAD_CFLAGS)
@@ -25,7 +25,7 @@ BUILT_SOURCES = $(JSON_TEST_FILES:.json=.json.h) $(RAW_TEST_FILES:.raw=.raw.h)
# test_bitcoin binary #
test_bitcoin_CPPFLAGS = $(AM_CPPFLAGS) $(TESTDEFS)
test_bitcoin_LDADD = $(LIBBITCOIN) $(LIBLEVELDB) $(LIBMEMENV) \
- $(BOOST_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIB)
+ $(BOOST_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) $(BDB_LIBS)
test_bitcoin_SOURCES = accounting_tests.cpp alert_tests.cpp \
allocator_tests.cpp base32_tests.cpp base58_tests.cpp base64_tests.cpp \
bignum_tests.cpp bloom_tests.cpp canonical_tests.cpp checkblock_tests.cpp \
diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp
index eeeacb0ad4..67165760b2 100644
--- a/src/test/miner_tests.cpp
+++ b/src/test/miner_tests.cpp
@@ -65,10 +65,10 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
{
CBlock *pblock = &pblocktemplate->block; // pointer for convenience
pblock->nVersion = 1;
- pblock->nTime = pindexBest->GetMedianTimePast()+1;
+ pblock->nTime = chainActive.Tip()->GetMedianTimePast()+1;
pblock->vtx[0].vin[0].scriptSig = CScript();
pblock->vtx[0].vin[0].scriptSig.push_back(blockinfo[i].extranonce);
- pblock->vtx[0].vin[0].scriptSig.push_back(pindexBest->nHeight);
+ pblock->vtx[0].vin[0].scriptSig.push_back(chainActive.Height());
pblock->vtx[0].vout[0].scriptPubKey = CScript();
if (txFirst.size() < 2)
txFirst.push_back(new CTransaction(pblock->vtx[0]));
@@ -193,14 +193,14 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
mempool.clear();
// subsidy changing
- int nHeight = pindexBest->nHeight;
- pindexBest->nHeight = 209999;
+ int nHeight = chainActive.Height();
+ chainActive.Tip()->nHeight = 209999;
BOOST_CHECK(pblocktemplate = CreateNewBlockWithKey(reservekey));
delete pblocktemplate;
- pindexBest->nHeight = 210000;
+ chainActive.Tip()->nHeight = 210000;
BOOST_CHECK(pblocktemplate = CreateNewBlockWithKey(reservekey));
delete pblocktemplate;
- pindexBest->nHeight = nHeight;
+ chainActive.Tip()->nHeight = nHeight;
BOOST_FOREACH(CTransaction *tx, txFirst)
delete tx;
diff --git a/src/txdb.cpp b/src/txdb.cpp
index 0d2fdc2887..24ee8ec3e8 100644
--- a/src/txdb.cpp
+++ b/src/txdb.cpp
@@ -223,10 +223,6 @@ bool CBlockTreeDB::LoadBlockIndexGuts()
pindexNew->nStatus = diskindex.nStatus;
pindexNew->nTx = diskindex.nTx;
- // Watch for genesis block
- if (pindexGenesisBlock == NULL && diskindex.GetBlockHash() == Params().HashGenesisBlock())
- pindexGenesisBlock = pindexNew;
-
if (!pindexNew->CheckIndex())
return error("LoadBlockIndex() : CheckIndex failed: %s", pindexNew->ToString().c_str());
diff --git a/src/util.cpp b/src/util.cpp
index 73428b4c22..cfaf5bdf8c 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -78,7 +78,6 @@ bool fPrintToConsole = false;
bool fPrintToDebugger = false;
bool fDaemon = false;
bool fServer = false;
-bool fCommandLine = false;
string strMiscWarning;
bool fNoListen = false;
bool fLogTimestamps = false;
diff --git a/src/util.h b/src/util.h
index a216aacdc9..c3fb01dbf0 100644
--- a/src/util.h
+++ b/src/util.h
@@ -145,7 +145,6 @@ extern bool fPrintToConsole;
extern bool fPrintToDebugger;
extern bool fDaemon;
extern bool fServer;
-extern bool fCommandLine;
extern std::string strMiscWarning;
extern bool fNoListen;
extern bool fLogTimestamps;
diff --git a/src/wallet.cpp b/src/wallet.cpp
index 26ffc71e19..0f0ce7e631 100644
--- a/src/wallet.cpp
+++ b/src/wallet.cpp
@@ -799,7 +799,7 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate)
// no need to read and scan block, if block was created before
// our wallet birthday (as adjusted for block time variability)
if (nTimeFirstKey && (pindex->nTime < (nTimeFirstKey - 7200))) {
- pindex = pindex->GetNextInMainChain();
+ pindex = chainActive.Next(pindex);
continue;
}
@@ -810,7 +810,7 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate)
if (AddToWalletIfInvolvingMe(tx.GetHash(), tx, &block, fUpdate))
ret++;
}
- pindex = pindex->GetNextInMainChain();
+ pindex = chainActive.Next(pindex);
}
}
return ret;
@@ -864,7 +864,7 @@ void CWallet::ReacceptWalletTransactions()
if (fMissing)
{
// TODO: optimize this to scan just part of the block chain?
- if (ScanForWalletTransactions(pindexGenesisBlock))
+ if (ScanForWalletTransactions(chainActive.Genesis()))
fRepeat = true; // Found missing transactions: re-do re-accept.
}
}
@@ -1933,7 +1933,7 @@ void CWallet::GetKeyBirthTimes(std::map<CKeyID, int64> &mapKeyBirth) const {
mapKeyBirth[it->first] = it->second.nCreateTime;
// map in which we'll infer heights of other keys
- CBlockIndex *pindexMax = FindBlockByHeight(std::max(0, nBestHeight - 144)); // the tip can be reorganised; use a 144-block safety margin
+ CBlockIndex *pindexMax = chainActive[std::max(0, chainActive.Height() - 144)]; // the tip can be reorganised; use a 144-block safety margin
std::map<CKeyID, CBlockIndex*> mapKeyFirstBlock;
std::set<CKeyID> setKeys;
GetKeys(setKeys);
@@ -1953,7 +1953,7 @@ void CWallet::GetKeyBirthTimes(std::map<CKeyID, int64> &mapKeyBirth) const {
// iterate over all wallet transactions...
const CWalletTx &wtx = (*it).second;
std::map<uint256, CBlockIndex*>::const_iterator blit = mapBlockIndex.find(wtx.hashBlock);
- if (blit != mapBlockIndex.end() && blit->second->IsInMainChain()) {
+ if (blit != mapBlockIndex.end() && chainActive.Contains(blit->second)) {
// ... which are already in a block
int nHeight = blit->second->nHeight;
BOOST_FOREACH(const CTxOut &txout, wtx.vout) {