aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xautogen.sh6
-rw-r--r--configure.ac36
-rw-r--r--contrib/README.md8
-rw-r--r--contrib/bitrpc/README.md10
-rw-r--r--contrib/devtools/README.md38
-rwxr-xr-xcontrib/devtools/github-merge.sh173
-rw-r--r--contrib/gitian-descriptors/deps-win32.yml2
-rw-r--r--contrib/wallettools/README.md4
-rw-r--r--contrib/wallettools/walletchangepass.py5
-rw-r--r--contrib/wallettools/walletunlock.py4
-rw-r--r--doc/bitcoin_logo_doxygen.pngbin4757 -> 3272 bytes
-rw-r--r--doc/build-unix.md11
-rw-r--r--doc/release-process.md2
-rwxr-xr-xqa/pull-tester/build-tests.sh.in3
-rw-r--r--qa/rpc-tests/README.md6
-rw-r--r--qa/rpc-tests/util.sh84
-rwxr-xr-xqa/rpc-tests/wallet.sh97
-rwxr-xr-xshare/genbuild.sh2
-rw-r--r--share/pixmaps/bitcoin128.pngbin12930 -> 10639 bytes
-rw-r--r--share/pixmaps/bitcoin16.pngbin1838 -> 827 bytes
-rw-r--r--share/pixmaps/bitcoin256.pngbin32814 -> 28182 bytes
-rw-r--r--share/pixmaps/bitcoin32.pngbin3038 -> 1982 bytes
-rw-r--r--share/pixmaps/bitcoin64.pngbin6026 -> 4592 bytes
-rw-r--r--share/qt/Info.plist.in13
-rw-r--r--src/Makefile.am82
-rw-r--r--src/Makefile.include5
-rw-r--r--src/bitcoin-cli.cpp10
-rw-r--r--src/bitcoind.cpp4
-rw-r--r--src/coins.cpp16
-rw-r--r--src/coins.h4
-rw-r--r--src/compat.h4
-rw-r--r--src/core.cpp33
-rw-r--r--src/core.h16
-rw-r--r--src/crypter.cpp157
-rw-r--r--src/crypter.h83
-rw-r--r--src/db.cpp110
-rw-r--r--src/db.h18
-rw-r--r--src/init.cpp194
-rw-r--r--src/init.h3
-rw-r--r--src/key.cpp7
-rw-r--r--src/keystore.cpp152
-rw-r--r--src/keystore.h83
-rw-r--r--src/m4/ax_boost_base.m48
-rw-r--r--src/m4/ax_boost_filesystem.m48
-rw-r--r--src/m4/ax_boost_program_options.m46
-rw-r--r--src/m4/ax_boost_system.m46
-rw-r--r--src/m4/ax_boost_thread.m470
-rw-r--r--src/m4/ax_pthread.m449
-rw-r--r--src/main.cpp219
-rw-r--r--src/main.h17
-rw-r--r--src/miner.cpp40
-rw-r--r--src/miner.h2
-rw-r--r--src/net.cpp143
-rw-r--r--src/net.h45
-rw-r--r--src/netbase.cpp2
-rw-r--r--src/protocol.cpp2
-rw-r--r--src/qt/Makefile.am2
-rw-r--r--src/qt/bitcoin.cpp13
-rw-r--r--src/qt/bitcoingui.cpp22
-rw-r--r--src/qt/clientmodel.h2
-rw-r--r--src/qt/coincontroldialog.cpp25
-rw-r--r--src/qt/forms/coincontroldialog.ui63
-rw-r--r--src/qt/forms/sendcoinsdialog.ui139
-rw-r--r--src/qt/forms/sendcoinsentry.ui242
-rw-r--r--src/qt/guiutil.cpp1
-rw-r--r--src/qt/macdockiconhandler.mm8
-rw-r--r--src/qt/notificator.cpp5
-rw-r--r--src/qt/notificator.h2
-rw-r--r--src/qt/openuridialog.cpp2
-rw-r--r--src/qt/paymentserver.cpp25
-rw-r--r--src/qt/paymentserver.h9
-rw-r--r--src/qt/receivecoinsdialog.cpp4
-rw-r--r--src/qt/res/icons/add.pngbin1279 -> 1112 bytes
-rw-r--r--src/qt/res/icons/address-book.pngbin1916 -> 1690 bytes
-rw-r--r--src/qt/res/icons/bitcoin.pngbin36486 -> 32547 bytes
-rw-r--r--src/qt/res/icons/bitcoin_testnet.pngbin34143 -> 28227 bytes
-rw-r--r--src/qt/res/icons/clock1.pngbin946 -> 864 bytes
-rw-r--r--src/qt/res/icons/clock2.pngbin944 -> 863 bytes
-rw-r--r--src/qt/res/icons/clock3.pngbin946 -> 856 bytes
-rw-r--r--src/qt/res/icons/clock4.pngbin962 -> 869 bytes
-rw-r--r--src/qt/res/icons/clock5.pngbin956 -> 858 bytes
-rw-r--r--src/qt/res/icons/configure.pngbin1055 -> 681 bytes
-rw-r--r--src/qt/res/icons/connect0_16.pngbin702 -> 631 bytes
-rw-r--r--src/qt/res/icons/connect1_16.pngbin612 -> 541 bytes
-rw-r--r--src/qt/res/icons/connect2_16.pngbin623 -> 582 bytes
-rw-r--r--src/qt/res/icons/connect3_16.pngbin625 -> 591 bytes
-rw-r--r--src/qt/res/icons/connect4_16.pngbin673 -> 596 bytes
-rw-r--r--src/qt/res/icons/debugwindow.pngbin5402 -> 2240 bytes
-rw-r--r--src/qt/res/icons/edit.pngbin1627 -> 1163 bytes
-rw-r--r--src/qt/res/icons/editcopy.pngbin879 -> 600 bytes
-rw-r--r--src/qt/res/icons/editpaste.pngbin1458 -> 1135 bytes
-rw-r--r--src/qt/res/icons/export.pngbin2148 -> 1931 bytes
-rw-r--r--src/qt/res/icons/filesave.pngbin1741 -> 1251 bytes
-rw-r--r--src/qt/res/icons/history.pngbin1432 -> 1343 bytes
-rw-r--r--src/qt/res/icons/key.pngbin1727 -> 1440 bytes
-rw-r--r--src/qt/res/icons/lock_closed.pngbin1679 -> 1401 bytes
-rw-r--r--src/qt/res/icons/lock_open.pngbin1644 -> 1359 bytes
-rw-r--r--src/qt/res/icons/notsynced.pngbin1013 -> 887 bytes
-rw-r--r--src/qt/res/icons/overview.pngbin7455 -> 6327 bytes
-rw-r--r--src/qt/res/icons/qrcode.pngbin237 -> 143 bytes
-rw-r--r--src/qt/res/icons/quit.pngbin2163 -> 1778 bytes
-rw-r--r--src/qt/res/icons/receive.pngbin1437 -> 1331 bytes
-rw-r--r--src/qt/res/icons/remove.pngbin1224 -> 649 bytes
-rw-r--r--src/qt/res/icons/send.pngbin1487 -> 1345 bytes
-rw-r--r--src/qt/res/icons/synced.pngbin781 -> 560 bytes
-rw-r--r--src/qt/res/icons/toolbar.pngbin1787 -> 815 bytes
-rw-r--r--src/qt/res/icons/toolbar_testnet.pngbin1748 -> 678 bytes
-rw-r--r--src/qt/res/icons/transaction0.pngbin569 -> 291 bytes
-rw-r--r--src/qt/res/icons/transaction2.pngbin413 -> 211 bytes
-rw-r--r--src/qt/res/icons/tx_inout.pngbin2442 -> 1252 bytes
-rw-r--r--src/qt/res/icons/tx_input.pngbin2152 -> 1114 bytes
-rw-r--r--src/qt/res/icons/tx_mined.pngbin3287 -> 1458 bytes
-rw-r--r--src/qt/res/icons/tx_output.pngbin2129 -> 1107 bytes
-rw-r--r--src/qt/res/images/about.pngbin3488 -> 1136 bytes
-rw-r--r--src/qt/res/images/splash.pngbin49338 -> 43398 bytes
-rw-r--r--src/qt/res/images/splash_testnet.pngbin45370 -> 34142 bytes
-rw-r--r--src/qt/rpcconsole.cpp3
-rw-r--r--src/qt/sendcoinsdialog.cpp69
-rw-r--r--src/qt/sendcoinsdialog.h2
-rw-r--r--src/qt/sendcoinsentry.cpp12
-rw-r--r--src/qt/sendcoinsentry.h3
-rw-r--r--src/qt/test/Makefile.am2
-rw-r--r--src/qt/test/paymentservertests.cpp14
-rw-r--r--src/qt/test/paymentservertests.h2
-rw-r--r--src/qt/test/test_main.cpp8
-rw-r--r--src/qt/transactiondesc.cpp2
-rw-r--r--src/qt/transactionrecord.cpp2
-rw-r--r--src/qt/walletview.cpp4
-rw-r--r--src/qt/walletview.h1
-rw-r--r--src/rpcblockchain.cpp79
-rw-r--r--src/rpcclient.cpp279
-rw-r--r--src/rpcclient.h25
-rw-r--r--src/rpcdump.cpp4
-rw-r--r--src/rpcmining.cpp47
-rw-r--r--src/rpcnet.cpp85
-rw-r--r--src/rpcprotocol.cpp262
-rw-r--r--src/rpcprotocol.h138
-rw-r--r--src/rpcrawtransaction.cpp21
-rw-r--r--src/rpcserver.cpp (renamed from src/bitcoinrpc.cpp)592
-rw-r--r--src/rpcserver.h (renamed from src/bitcoinrpc.h)62
-rw-r--r--src/rpcwallet.cpp84
-rw-r--r--src/script.cpp2
-rw-r--r--src/sync.cpp18
-rw-r--r--src/sync.h3
-rw-r--r--src/test/DoS_tests.cpp26
-rw-r--r--src/test/Makefile.am19
-rw-r--r--src/test/miner_tests.cpp22
-rw-r--r--src/test/rpc_tests.cpp74
-rw-r--r--src/test/rpc_wallet_tests.cpp82
-rw-r--r--src/test/test_bitcoin.cpp13
-rw-r--r--src/txmempool.cpp61
-rw-r--r--src/txmempool.h31
-rw-r--r--src/util.cpp4
-rw-r--r--src/wallet.cpp26
-rw-r--r--src/walletdb.cpp1
155 files changed, 2976 insertions, 1874 deletions
diff --git a/autogen.sh b/autogen.sh
index 4e7011a596..5b883a6a4c 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -1 +1,5 @@
-autoreconf -vif
+#!/bin/sh
+set -e
+srcdir="$(dirname $0)"
+cd "$srcdir"
+autoreconf --install --force
diff --git a/configure.ac b/configure.ac
index 647be8f2e6..34509993a0 100644
--- a/configure.ac
+++ b/configure.ac
@@ -37,6 +37,13 @@ AM_MAINTAINER_MODE([enable])
dnl make the compilation flags quiet unless V=1 is used
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
+# Enable wallet
+AC_ARG_ENABLE([wallet],
+ [AS_HELP_STRING([--enable-wallet],
+ [enable wallet (default is yes)])],
+ [enable_wallet=$enableval],
+ [enable_wallet=yes])
+
AC_ARG_WITH([miniupnpc],
[AS_HELP_STRING([--with-miniupnpc],
[enable UPNP (default is yes if libminiupnpc is found)])],
@@ -243,7 +250,7 @@ case $host in
bdb_prefix=`$BREW --prefix berkeley-db4`
export PKG_CONFIG_PATH="$openssl_prefix/lib/pkgconfig:$PKG_CONFIG_PATH"
CPPFLAGS="$CPPFLAGS -I$bdb_prefix/include"
- LIBS="$LIBS -L/$bdb_prefix/lib"
+ LIBS="$LIBS -L$bdb_prefix/lib"
fi
fi
@@ -362,12 +369,18 @@ AC_TRY_COMPILE([#include <sys/socket.h>],
[ AC_MSG_RESULT(no)]
)
-dnl Check for libdb_cxx
-BITCOIN_FIND_BDB48
+if test x$enable_wallet != xno; then
+ dnl Check for libdb_cxx only if wallet enabled
+ BITCOIN_FIND_BDB48
+fi
dnl Check for libminiupnpc (optional)
if test x$use_upnp != xno; then
- AC_CHECK_LIB([miniupnpc], [main],, [have_miniupnpc=no])
+ AC_CHECK_HEADERS(
+ [miniupnpc/miniwget.h miniupnpc/miniupnpc.h miniupnpc/upnpcommands.h miniupnpc/upnperrors.h],
+ [AC_CHECK_LIB([miniupnpc], [main],, [have_miniupnpc=no])],
+ [have_miniupnpc=no]
+ )
fi
dnl Check for boost libs
@@ -593,6 +606,20 @@ if test "x$use_ccache" != "xno"; then
AC_MSG_RESULT($use_ccache)
fi
+dnl enable wallet
+AC_MSG_CHECKING([if wallet should be enabled])
+if test x$enable_wallet != xno; then
+ AC_MSG_RESULT(yes)
+ AC_DEFINE_UNQUOTED([ENABLE_WALLET],[1],[Define to 1 to enable wallet functions])
+
+else
+ AC_MSG_RESULT(no)
+
+ if test "x$use_qt" != "xno"; then
+ AC_MSG_ERROR([Cannot currently build Qt GUI with wallet disabled. Use --without-qt.])
+ fi
+fi
+
dnl enable ipv6 support
AC_MSG_CHECKING([if ipv6 should be enabled])
if test x$have_ipv6 = xno; then
@@ -705,6 +732,7 @@ fi
AM_CONDITIONAL([TARGET_DARWIN], [test x$TARGET_OS = xdarwin])
AM_CONDITIONAL([TARGET_WINDOWS], [test x$TARGET_OS = xwindows])
+AM_CONDITIONAL([ENABLE_WALLET],[test x$enable_wallet == xyes])
AM_CONDITIONAL([USE_QRCODE], [test x$use_qr = xyes])
AM_CONDITIONAL([USE_LCOV],[test x$use_lcov == xyes])
AM_CONDITIONAL([USE_COMPARISON_TOOL],[test x$use_comparison_tool != xno])
diff --git a/contrib/README.md b/contrib/README.md
index eb0d3ee2c9..167b5df4e1 100644
--- a/contrib/README.md
+++ b/contrib/README.md
@@ -13,8 +13,8 @@ This is a 'getwork' CPU mining client for Bitcoin. It is pure-python, and theref
Use the raw transactions API to send coins received on a particular
address (or addresses).
-### [Wallet Tools](/contrib/wallettools) ###
-Contains a wallet change password and unlock script. Used to prevent users from having to enter their password as a command-line argument.
+### WalletTools
+Removed. Please see [/contrib/bitrpc](/contrib/bitrpc).
Repository Tools
---------------------
@@ -52,3 +52,7 @@ 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.
+### [Developer tools](/control/devtools) ###
+Specific tools for developers working on this repository.
+Contains the script `github-merge.sh` for merging github pull requests securely and signing them using GPG.
+
diff --git a/contrib/bitrpc/README.md b/contrib/bitrpc/README.md
index 2dde60a08e..f5ef2f0405 100644
--- a/contrib/bitrpc/README.md
+++ b/contrib/bitrpc/README.md
@@ -1,2 +1,8 @@
-### BitRPC ###
-Allows for sending of all standard Bitcoin commands via RPC rather than as command line args. \ No newline at end of file
+### BitRPC
+Allows for sending of all standard Bitcoin commands via RPC rather than as command line args.
+
+### Looking for Wallet Tools?
+BitRPC.py is able to do the exact same thing as `walletchangepass.py` and `walletunlock.py`. Their respective commands in BitRPC.py are:
+
+ bitrpc.py walletpassphrasechange
+ bitrpc.py walletpassphrase \ No newline at end of file
diff --git a/contrib/devtools/README.md b/contrib/devtools/README.md
new file mode 100644
index 0000000000..55d5d24cca
--- /dev/null
+++ b/contrib/devtools/README.md
@@ -0,0 +1,38 @@
+Contents
+===========
+This directory contains tools for developers working on this repository.
+
+github-merge.sh
+----------------
+
+A small script to automate merging pull-requests securely and sign them with GPG.
+
+For example:
+
+ ./github-merge.sh bitcoin/bitcoin 3077
+
+(in any git repository) will help you merge pull request #3077 for the
+bitcoin/bitcoin repository.
+
+What it does:
+* Fetch master and the pull request.
+* Locally construct a merge commit.
+* Show the diff that merge results in.
+* Ask you to verify the resulting source tree (so you can do a make
+check or whatever).
+* Ask you whether to GPG sign the merge commit.
+* Ask you whether to push the result upstream.
+
+This means that there are no potential race conditions (where a
+pullreq gets updated while you're reviewing it, but before you click
+merge), and when using GPG signatures, that even a compromised github
+couldn't mess with the sources.
+
+Setup
+---------
+Configuring the github-merge tool for the bitcoin repository is done in the following way:
+
+ git config githubmerge.repository bitcoin/bitcoin
+ git config githubmerge.testcmd "make -j4 check" (adapt to whatever you want to use for testing)
+ git config --global user.signingkey mykeyid (if you want to GPG sign)
+
diff --git a/contrib/devtools/github-merge.sh b/contrib/devtools/github-merge.sh
new file mode 100755
index 0000000000..e42b71a54a
--- /dev/null
+++ b/contrib/devtools/github-merge.sh
@@ -0,0 +1,173 @@
+#!/bin/bash
+
+# This script will locally construct a merge commit for a pull request on a
+# github repository, inspect it, sign it and optionally push it.
+
+# The following temporary branches are created/overwritten and deleted:
+# * pull/$PULL/base (the current master we're merging onto)
+# * pull/$PULL/head (the current state of the remote pull request)
+# * pull/$PULL/merge (github's merge)
+# * pull/$PULL/local-merge (our merge)
+
+# In case of a clean merge that is accepted by the user, the local branch with
+# name $BRANCH is overwritten with the merged result, and optionally pushed.
+
+REPO="$(git config --get githubmerge.repository)"
+if [[ "d$REPO" == "d" ]]; then
+ echo "ERROR: No repository configured. Use this command to set:" >&2
+ echo "git config githubmerge.repository <owner>/<repo>" >&2
+ echo "In addition, you can set the following variables:" >&2
+ echo "- githubmerge.host (default git@github.com)" >&2
+ echo "- githubmerge.branch (default master)" >&2
+ echo "- githubmerge.testcmd (default none)" >&2
+ exit 1
+fi
+
+HOST="$(git config --get githubmerge.host)"
+if [[ "d$HOST" == "d" ]]; then
+ HOST="git@github.com"
+fi
+
+BRANCH="$(git config --get githubmerge.branch)"
+if [[ "d$BRANCH" == "d" ]]; then
+ BRANCH="master"
+fi
+
+TESTCMD="$(git config --get githubmerge.testcmd)"
+
+PULL="$1"
+
+if [[ "d$PULL" == "d" ]]; then
+ echo "Usage: $0 pullnumber [branch]" >&2
+ exit 2
+fi
+
+if [[ "d$2" != "d" ]]; then
+ BRANCH="$2"
+fi
+
+# Initialize source branches.
+git checkout -q "$BRANCH"
+if git fetch -q "$HOST":"$REPO" "+refs/pull/$PULL/*:refs/heads/pull/$PULL/*"; then
+ if ! git log -1q "refs/heads/pull/$PULL/head" >/dev/null 2>&1; then
+ echo "ERROR: Cannot find head of pull request #$PULL on $HOST:$REPO." >&2
+ exit 3
+ fi
+ if ! git log -1q "refs/heads/pull/$PULL/merge" >/dev/null 2>&1; then
+ echo "ERROR: Cannot find merge of pull request #$PULL on $HOST:$REPO." >&2
+ exit 3
+ fi
+else
+ echo "ERROR: Cannot find pull request #$PULL on $HOST:$REPO." >&2
+ exit 3
+fi
+if git fetch -q "$HOST":"$REPO" +refs/heads/"$BRANCH":refs/heads/pull/"$PULL"/base; then
+ true
+else
+ echo "ERROR: Cannot find branch $BRANCH on $HOST:$REPO." >&2
+ exit 3
+fi
+git checkout -q pull/"$PULL"/base
+git branch -q -D pull/"$PULL"/local-merge 2>/dev/null
+git checkout -q -b pull/"$PULL"/local-merge
+TMPDIR="$(mktemp -d -t ghmXXXXX)"
+
+function cleanup() {
+ git checkout -q "$BRANCH"
+ git branch -q -D pull/"$PULL"/head 2>/dev/null
+ git branch -q -D pull/"$PULL"/base 2>/dev/null
+ git branch -q -D pull/"$PULL"/merge 2>/dev/null
+ git branch -q -D pull/"$PULL"/local-merge 2>/dev/null
+ rm -rf "$TMPDIR"
+}
+
+# Create unsigned merge commit.
+(
+ echo "Merge pull request #$PULL"
+ echo ""
+ git log --no-merges --topo-order --pretty='format:%h %s (%an)' pull/"$PULL"/base..pull/"$PULL"/head
+)>"$TMPDIR/message"
+if git merge -q --commit --no-edit --no-ff -m "$(<"$TMPDIR/message")" pull/"$PULL"/head; then
+ if [ "d$(git log --pretty='format:%s' -n 1)" != "dMerge pull request #$PULL" ]; then
+ echo "ERROR: Creating merge failed (already merged?)." >&2
+ cleanup
+ exit 4
+ fi
+else
+ echo "ERROR: Cannot be merged cleanly." >&2
+ git merge --abort
+ cleanup
+ exit 4
+fi
+
+# Run test command if configured.
+if [[ "d$TESTCMD" != "d" ]]; then
+ # Go up to the repository's root.
+ while [ ! -d .git ]; do cd ..; done
+ if ! $TESTCMD; then
+ echo "ERROR: Running $TESTCMD failed." >&2
+ cleanup
+ exit 5
+ fi
+ # Show the created merge.
+ git diff pull/"$PULL"/merge..pull/"$PULL"/local-merge >"$TMPDIR"/diff
+ git diff pull/"$PULL"/base..pull/"$PULL"/local-merge
+ if [[ "$(<"$TMPDIR"/diff)" != "" ]]; then
+ echo "WARNING: merge differs from github!" >&2
+ read -p "Type 'ignore' to continue. " -r >&2
+ if [[ "d$REPLY" =~ ^d[iI][gG][nN][oO][rR][eE]$ ]]; then
+ echo "Difference with github ignored." >&2
+ else
+ cleanup
+ exit 6
+ fi
+ fi
+ read -p "Press 'd' to accept the diff. " -n 1 -r >&2
+ echo
+ if [[ "d$REPLY" =~ ^d[dD]$ ]]; then
+ echo "Diff accepted." >&2
+ else
+ echo "ERROR: Diff rejected." >&2
+ cleanup
+ exit 6
+ fi
+else
+ # Verify the result.
+ echo "Dropping you on a shell so you can try building/testing the merged source." >&2
+ echo "Run 'git diff HEAD~' to show the changes being merged." >&2
+ echo "Type 'exit' when done." >&2
+ bash -i
+ read -p "Press 'm' to accept the merge. " -n 1 -r >&2
+ echo
+ if [[ "d$REPLY" =~ ^d[Mm]$ ]]; then
+ echo "Merge accepted." >&2
+ else
+ echo "ERROR: Merge rejected." >&2
+ cleanup
+ exit 7
+ fi
+fi
+
+# Sign the merge commit.
+read -p "Press 's' to sign off on the merge. " -n 1 -r >&2
+echo
+if [[ "d$REPLY" =~ ^d[Ss]$ ]]; then
+ if [[ "$(git config --get user.signingkey)" == "" ]]; then
+ echo "WARNING: No GPG signing key set, not signing. Set one using:" >&2
+ echo "git config --global user.signingkey <key>" >&2
+ git commit -q --signoff --amend --no-edit
+ else
+ git commit -q --gpg-sign --amend --no-edit
+ fi
+fi
+
+# Clean up temporary branches, and put the result in $BRANCH.
+git checkout -q "$BRANCH"
+git reset -q --hard pull/"$PULL"/local-merge
+cleanup
+
+# Push the result.
+read -p "Type 'push' to push the result to $HOST:$REPO, branch $BRANCH. " -r >&2
+if [[ "d$REPLY" =~ ^d[Pp][Uu][Ss][Hh]$ ]]; then
+ git push "$HOST":"$REPO" refs/heads/"$BRANCH"
+fi
diff --git a/contrib/gitian-descriptors/deps-win32.yml b/contrib/gitian-descriptors/deps-win32.yml
index 3f4e4e27f2..addb11d726 100644
--- a/contrib/gitian-descriptors/deps-win32.yml
+++ b/contrib/gitian-descriptors/deps-win32.yml
@@ -29,8 +29,8 @@ script: |
export HOST=i686-w64-mingw32
# Input Integrity Check
echo "2a9eb3cd4e8b114eb9179c0d3884d61658e7d8e8bf4984798a5f5bd48e325ebe openssl-1.0.1c.tar.gz" | sha256sum -c
- echo "b75dae26151f9b031062c8d2f577a094b08da0ae44fe8c11175d0b9ff434cc02 libpng-1.5.9.tar.gz" | sha256sum -c
echo "12edc0df75bf9abd7f82f821795bcee50f42cb2e5f76a6a281b85732798364ef db-4.8.30.NC.tar.gz" | sha256sum -c
+ echo "bbd6b756e6af44b5a5b0f9b93eada3fb8922ed1d6451b7d6f184d0ae0c813994 miniupnpc-1.6.tar.gz" | sha256sum -c
echo "21235e08552e6feba09ea5e8d750805b3391c62fb81c71a235c0044dc7a8a61b zlib-1.2.6.tar.gz" | sha256sum -c
echo "b75dae26151f9b031062c8d2f577a094b08da0ae44fe8c11175d0b9ff434cc02 libpng-1.5.9.tar.gz" | sha256sum -c
echo "03c4bc7cd9a75747c3815d509bbe061907d615764f2357923f0db948c567068f qrencode-3.2.0.tar.bz2" | sha256sum -c
diff --git a/contrib/wallettools/README.md b/contrib/wallettools/README.md
deleted file mode 100644
index 3a71ba1436..0000000000
--- a/contrib/wallettools/README.md
+++ /dev/null
@@ -1,4 +0,0 @@
-### Wallet Tools ###
-These are two simple python scripts which send the appropriate RPC commands to unlock a wallet and change a wallet password. **They are intended to prevent users from having to enter their password as a command-line argument which could then be stored in the console buffer/history in plaintext.**
-
-Both tools rely on bitcoin/bitcoind running with `server=1` and an `rpcuser` and `rpcpassword` set in `bitcoin.conf`. They can be easily modified for non-standard ports. [walletunlock.py](/contrib/wallettools/walletunlock.py) unlocks the wallet for 60 seconds by default, changeable in code, and both modules rely upon python-json-rpc.
diff --git a/contrib/wallettools/walletchangepass.py b/contrib/wallettools/walletchangepass.py
deleted file mode 100644
index 30f3f5b26a..0000000000
--- a/contrib/wallettools/walletchangepass.py
+++ /dev/null
@@ -1,5 +0,0 @@
-from jsonrpc import ServiceProxy
-access = ServiceProxy("http://127.0.0.1:8332")
-pwd = raw_input("Enter old wallet passphrase: ")
-pwd2 = raw_input("Enter new wallet passphrase: ")
-access.walletpassphrasechange(pwd, pwd2) \ No newline at end of file
diff --git a/contrib/wallettools/walletunlock.py b/contrib/wallettools/walletunlock.py
deleted file mode 100644
index f847c6fe61..0000000000
--- a/contrib/wallettools/walletunlock.py
+++ /dev/null
@@ -1,4 +0,0 @@
-from jsonrpc import ServiceProxy
-access = ServiceProxy("http://127.0.0.1:8332")
-pwd = raw_input("Enter wallet passphrase: ")
-access.walletpassphrase(pwd, 60) \ No newline at end of file
diff --git a/doc/bitcoin_logo_doxygen.png b/doc/bitcoin_logo_doxygen.png
index 2d62a8dc8a..258be86ede 100644
--- a/doc/bitcoin_logo_doxygen.png
+++ b/doc/bitcoin_logo_doxygen.png
Binary files differ
diff --git a/doc/build-unix.md b/doc/build-unix.md
index 27228cdc1b..1d9d96a1ca 100644
--- a/doc/build-unix.md
+++ b/doc/build-unix.md
@@ -22,7 +22,7 @@ Dependencies
Library Purpose Description
------- ------- -----------
libssl SSL Support Secure communications
- libdb4.8 Berkeley DB Blockchain & wallet storage
+ libdb4.8 Berkeley DB Wallet storage
libboost Boost C++ Library
miniupnpc UPnP Support Optional firewall-jumping support
qt GUI GUI toolkit
@@ -178,3 +178,12 @@ Hardening enables the following features:
RW- R-- RW-
The STK RW- means that the stack is readable and writeable but not executable.
+
+Disable-wallet mode
+--------------------
+When the intention is to run only a P2P node without a wallet, bitcoin may be compiled in
+disable-wallet mode with:
+
+ ./configure --disable-wallet
+
+In this case there is no dependency on Berkeley DB 4.8.
diff --git a/doc/release-process.md b/doc/release-process.md
index feadb3c1b0..3d5c577f86 100644
--- a/doc/release-process.md
+++ b/doc/release-process.md
@@ -17,7 +17,7 @@ Release Process
###tag version in git
- git tag -a v(new version, e.g. 0.8.0)
+ git tag -s v(new version, e.g. 0.8.0)
###write release notes. git shortlog helps a lot, for example:
diff --git a/qa/pull-tester/build-tests.sh.in b/qa/pull-tester/build-tests.sh.in
index 82ae60fdf1..86d4d9d0e9 100755
--- a/qa/pull-tester/build-tests.sh.in
+++ b/qa/pull-tester/build-tests.sh.in
@@ -68,6 +68,9 @@ fi
cd @abs_top_srcdir@/linux-build
make check
+# Run RPC integration test on Linux:
+@abs_top_srcdir@/qa/rpc-tests/wallet.sh @abs_top_srcdir@/linux-build/src
+
if [ $RUN_EXPENSIVE_TESTS = 1 ]; then
# Run unit tests and blockchain-tester on Windows:
cd @abs_top_srcdir@/win32-build
diff --git a/qa/rpc-tests/README.md b/qa/rpc-tests/README.md
new file mode 100644
index 0000000000..c8537247d9
--- /dev/null
+++ b/qa/rpc-tests/README.md
@@ -0,0 +1,6 @@
+Regression tests of RPC interface
+=================================
+
+wallet.sh : Test wallet send/receive code (see comments for details)
+
+util.sh : useful re-usable functions
diff --git a/qa/rpc-tests/util.sh b/qa/rpc-tests/util.sh
new file mode 100644
index 0000000000..dc2a319970
--- /dev/null
+++ b/qa/rpc-tests/util.sh
@@ -0,0 +1,84 @@
+#!/usr/bin/env bash
+
+# Functions used by more than one test
+
+function echoerr {
+ echo "$@" 1>&2;
+}
+
+# Usage: ExtractKey <key> "<json_object_string>"
+# Warning: this will only work for the very-well-behaved
+# JSON produced by bitcoind, do NOT use it to try to
+# parse arbitrary/nested/etc JSON.
+function ExtractKey {
+ echo $2 | tr -d ' "{}\n' | awk -v RS=',' -F: "\$1 ~ /$1/ { print \$2}"
+}
+
+function CreateDataDir {
+ DIR=$1
+ mkdir -p $DIR
+ CONF=$DIR/bitcoin.conf
+ echo "regtest=1" >> $CONF
+ echo "keypool=2" >> $CONF
+ echo "rpcuser=rt" >> $CONF
+ echo "rpcpassword=rt" >> $CONF
+ echo "rpcwait=1" >> $CONF
+ shift
+ while (( "$#" )); do
+ echo $1 >> $CONF
+ shift
+ done
+}
+
+function AssertEqual {
+ if (( $( echo "$1 == $2" | bc ) == 0 ))
+ then
+ echoerr "AssertEqual: $1 != $2"
+ exit 1
+ fi
+}
+
+# CheckBalance -datadir=... amount account minconf
+function CheckBalance {
+ B=$( $CLI $1 getbalance $3 $4 )
+ if (( $( echo "$B == $2" | bc ) == 0 ))
+ then
+ echoerr "bad balance: $B (expected $2)"
+ exit 1
+ fi
+}
+
+# Use: Address <datadir> [account]
+function Address {
+ $CLI $1 getnewaddress $2
+}
+
+# Send from to amount
+function Send {
+ from=$1
+ to=$2
+ amount=$3
+ address=$(Address $to)
+ txid=$( $CLI $from sendtoaddress $address $amount )
+}
+
+# Use: Unspent <datadir> <n'th-last-unspent> <var>
+function Unspent {
+ local r=$( $CLI $1 listunspent | awk -F'[ |:,"]+' "\$2 ~ /$3/ { print \$3 }" | tail -n $2 | head -n 1)
+ echo $r
+}
+
+# Use: CreateTxn1 <datadir> <n'th-last-unspent> <destaddress>
+# produces hex from signrawtransaction
+function CreateTxn1 {
+ TXID=$(Unspent $1 $2 txid)
+ AMOUNT=$(Unspent $1 $2 amount)
+ VOUT=$(Unspent $1 $2 vout)
+ RAWTXN=$( $CLI $1 createrawtransaction "[{\"txid\":\"$TXID\",\"vout\":$VOUT}]" "{\"$3\":$AMOUNT}")
+ ExtractKey hex "$( $CLI $1 signrawtransaction $RAWTXN )"
+}
+
+# Use: SendRawTxn <datadir> <hex_txn_data>
+function SendRawTxn {
+ $CLI $1 sendrawtransaction $2
+}
diff --git a/qa/rpc-tests/wallet.sh b/qa/rpc-tests/wallet.sh
new file mode 100755
index 0000000000..dd511782d0
--- /dev/null
+++ b/qa/rpc-tests/wallet.sh
@@ -0,0 +1,97 @@
+#!/usr/bin/env bash
+
+# Test block generation and basic wallet sending
+
+if [ $# -lt 1 ]; then
+ echo "Usage: $0 path_to_binaries"
+ echo "e.g. $0 ../../src"
+ exit 1
+fi
+
+BITCOIND=${1}/bitcoind
+CLI=${1}/bitcoin-cli
+
+DIR="${BASH_SOURCE%/*}"
+if [[ ! -d "$DIR" ]]; then DIR="$PWD"; fi
+. "$DIR/util.sh"
+
+D=$(mktemp -d test.XXXXX)
+
+D1=${D}/node1
+CreateDataDir $D1 port=11000 rpcport=11001
+B1ARGS="-datadir=$D1"
+$BITCOIND $B1ARGS &
+B1PID=$!
+
+D2=${D}/node2
+CreateDataDir $D2 port=11010 rpcport=11011 connect=127.0.0.1:11000
+B2ARGS="-datadir=$D2"
+$BITCOIND $B2ARGS &
+B2PID=$!
+
+D3=${D}/node3
+CreateDataDir $D3 port=11020 rpcport=11021 connect=127.0.0.1:11000
+B3ARGS="-datadir=$D3"
+$BITCOIND $BITCOINDARGS $B3ARGS &
+B3PID=$!
+
+trap "kill -9 $B1PID $B2PID $B3PID; rm -rf $D" EXIT
+
+# 1 block, 50 XBT each == 50 XBT
+$CLI $B1ARGS setgenerate true 1
+sleep 1 # sleep is necessary to let block broadcast
+# 101 blocks, 1 mature == 50 XBT
+$CLI $B2ARGS setgenerate true 101
+sleep 1
+
+CheckBalance $B1ARGS 50
+CheckBalance $B2ARGS 50
+
+# Send 21 XBT from 1 to 3. Second
+# transaction will be child of first, and
+# will require a fee
+Send $B1ARGS $B3ARGS 11
+Send $B1ARGS $B3ARGS 10
+
+# Have B1 mine a new block, and mature it
+# to recover transaction fees
+$CLI $B1ARGS setgenerate true 1
+sleep 1
+
+# Have B2 mine 100 blocks so B1's block is mature:
+$CLI $B2ARGS setgenerate true 100
+sleep 1
+
+# B1 should end up with 100 XBT in block rewards plus fees,
+# minus the 21 XBT sent to B3:
+CheckBalance $B1ARGS "100-21"
+CheckBalance $B3ARGS "21"
+
+# B1 should have two unspent outputs; create a couple
+# of raw transactions to send them to B3, submit them through
+# B2, and make sure both B1 and B3 pick them up properly:
+RAW1=$(CreateTxn1 $B1ARGS 1 $(Address $B3ARGS "from1" ) )
+RAW2=$(CreateTxn1 $B1ARGS 2 $(Address $B3ARGS "from1" ) )
+RAWTXID1=$(SendRawTxn $B2ARGS $RAW1)
+RAWTXID2=$(SendRawTxn $B2ARGS $RAW2)
+
+# Have B2 mine a block to confirm transactions:
+$CLI $B2ARGS setgenerate true 1
+sleep 1 # allow time for block to be relayed
+
+# Check balances after confirmation
+CheckBalance $B1ARGS 0
+CheckBalance $B3ARGS 100
+CheckBalance $B3ARGS "100-21" "from1"
+
+$CLI $B3ARGS stop > /dev/null 2>&1
+wait $B3PID
+$CLI $B2ARGS stop > /dev/null 2>&1
+wait $B2PID
+$CLI $B1ARGS stop > /dev/null 2>&1
+wait $B1PID
+
+echo "Tests successful, cleaning up"
+trap "" EXIT
+rm -rf $D
+exit 0
diff --git a/share/genbuild.sh b/share/genbuild.sh
index da50b0d109..edb847a242 100755
--- a/share/genbuild.sh
+++ b/share/genbuild.sh
@@ -13,6 +13,8 @@ else
exit 1
fi
+TIME=$(date '+%F %T %z')
+
if [ -e "$(which git)" -a -d ".git" ]; then
# clean 'dirty' status of touched files that haven't been modified
git diff >/dev/null 2>/dev/null
diff --git a/share/pixmaps/bitcoin128.png b/share/pixmaps/bitcoin128.png
index 04b56cf2a0..55039b1c92 100644
--- a/share/pixmaps/bitcoin128.png
+++ b/share/pixmaps/bitcoin128.png
Binary files differ
diff --git a/share/pixmaps/bitcoin16.png b/share/pixmaps/bitcoin16.png
index 16e240e79e..5537479095 100644
--- a/share/pixmaps/bitcoin16.png
+++ b/share/pixmaps/bitcoin16.png
Binary files differ
diff --git a/share/pixmaps/bitcoin256.png b/share/pixmaps/bitcoin256.png
index 0ba94fb46d..1d42116ef1 100644
--- a/share/pixmaps/bitcoin256.png
+++ b/share/pixmaps/bitcoin256.png
Binary files differ
diff --git a/share/pixmaps/bitcoin32.png b/share/pixmaps/bitcoin32.png
index 97a3f28029..367abfcc8e 100644
--- a/share/pixmaps/bitcoin32.png
+++ b/share/pixmaps/bitcoin32.png
Binary files differ
diff --git a/share/pixmaps/bitcoin64.png b/share/pixmaps/bitcoin64.png
index 8aedee811f..08c676ae4a 100644
--- a/share/pixmaps/bitcoin64.png
+++ b/share/pixmaps/bitcoin64.png
Binary files differ
diff --git a/share/qt/Info.plist.in b/share/qt/Info.plist.in
index d0dd796561..54ced278f2 100644
--- a/share/qt/Info.plist.in
+++ b/share/qt/Info.plist.in
@@ -4,18 +4,25 @@
<dict>
<key>CFBundleIconFile</key>
<string>bitcoin.icns</string>
+
<key>CFBundlePackageType</key>
<string>APPL</string>
+
<key>CFBundleGetInfoString</key>
<string>@CLIENT_VERSION_MAJOR@.@CLIENT_VERSION_MINOR@, Copyright © 2009-@COPYRIGHT_YEAR@ The Bitcoin developers</string>
+
<key>CFBundleShortVersionString</key>
<string>@CLIENT_VERSION_MAJOR@.@CLIENT_VERSION_MINOR@</string>
+
<key>CFBundleVersion</key>
<string>@CLIENT_VERSION_MAJOR@.@CLIENT_VERSION_MINOR@</string>
+
<key>CFBundleSignature</key>
<string>????</string>
+
<key>CFBundleExecutable</key>
<string>Bitcoin-Qt</string>
+
<key>CFBundleIdentifier</key>
<string>org.bitcoinfoundation.Bitcoin-Qt</string>
@@ -69,7 +76,11 @@
<string>Owner</string>
</dict>
</array>
+
+ <key>NSPrincipalClass</key>
+ <string>NSApplication</string>
+
<key>NSHighResolutionCapable</key>
- <true/>
+ <string>True</string>
</dict>
</plist>
diff --git a/src/Makefile.am b/src/Makefile.am
index 7450507b34..df4087c313 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -3,7 +3,10 @@ include Makefile.include
AM_CPPFLAGS += -I$(top_srcdir)/src/leveldb/helpers/memenv \
-I$(builddir)
-noinst_LIBRARIES = libbitcoin.a
+noinst_LIBRARIES = libbitcoin_server.a libbitcoin_common.a libbitcoin_cli.a
+if ENABLE_WALLET
+noinst_LIBRARIES += libbitcoin_wallet.a
+endif
bin_PROGRAMS = bitcoind bitcoin-cli
@@ -12,7 +15,10 @@ DIST_SUBDIRS = . qt test
.PHONY: FORCE
# bitcoin core #
BITCOIN_CORE_H = addrman.h alert.h allocators.h base58.h bignum.h \
- bitcoinrpc.h bloom.h chainparams.h checkpoints.h checkqueue.h \
+ rpcclient.h \
+ rpcprotocol.h \
+ rpcserver.h \
+ bloom.h chainparams.h checkpoints.h checkqueue.h \
clientversion.h coincontrol.h compat.h core.h coins.h crypter.h db.h hash.h init.h \
key.h keystore.h leveldbwrapper.h limitedmap.h main.h miner.h mruset.h \
netbase.h net.h noui.h protocol.h script.h serialize.h sync.h threadsafety.h \
@@ -30,20 +36,67 @@ obj/build.h: FORCE
$(abs_top_srcdir)
version.o: obj/build.h
-libbitcoin_a_SOURCES = addrman.cpp alert.cpp allocators.cpp bitcoinrpc.cpp bloom.cpp \
- chainparams.cpp checkpoints.cpp core.cpp coins.cpp crypter.cpp db.cpp hash.cpp \
- init.cpp key.cpp keystore.cpp leveldbwrapper.cpp main.cpp miner.cpp \
- netbase.cpp net.cpp noui.cpp protocol.cpp rpcblockchain.cpp rpcdump.cpp \
- rpcmining.cpp rpcnet.cpp rpcrawtransaction.cpp rpcwallet.cpp script.cpp \
- sync.cpp txdb.cpp txmempool.cpp util.cpp version.cpp wallet.cpp walletdb.cpp $(JSON_H) \
+libbitcoin_server_a_SOURCES = \
+ addrman.cpp \
+ alert.cpp \
+ rpcserver.cpp \
+ bloom.cpp \
+ chainparams.cpp \
+ checkpoints.cpp \
+ coins.cpp \
+ init.cpp \
+ keystore.cpp \
+ leveldbwrapper.cpp \
+ main.cpp \
+ net.cpp \
+ noui.cpp \
+ rpcblockchain.cpp \
+ rpcnet.cpp \
+ rpcrawtransaction.cpp \
+ txdb.cpp \
+ txmempool.cpp \
+ $(JSON_H) \
+ $(BITCOIN_CORE_H)
+
+libbitcoin_wallet_a_SOURCES = \
+ db.cpp \
+ crypter.cpp \
+ miner.cpp \
+ rpcdump.cpp \
+ rpcmining.cpp \
+ rpcwallet.cpp \
+ wallet.cpp \
+ walletdb.cpp \
+ $(BITCOIN_CORE_H)
+
+libbitcoin_common_a_SOURCES = \
+ allocators.cpp \
+ chainparams.cpp \
+ core.cpp \
+ hash.cpp \
+ key.cpp \
+ netbase.cpp \
+ protocol.cpp \
+ rpcprotocol.cpp \
+ script.cpp \
+ sync.cpp \
+ util.cpp \
+ version.cpp \
$(BITCOIN_CORE_H)
-nodist_libbitcoin_a_SOURCES = $(top_srcdir)/src/obj/build.h
+libbitcoin_cli_a_SOURCES = \
+ rpcclient.cpp \
+ $(BITCOIN_CORE_H)
+
+nodist_libbitcoin_common_a_SOURCES = $(top_srcdir)/src/obj/build.h
#
# bitcoind binary #
-bitcoind_LDADD = libbitcoin.a leveldb/libleveldb.a leveldb/libmemenv.a \
+bitcoind_LDADD = libbitcoin_server.a libbitcoin_cli.a libbitcoin_common.a leveldb/libleveldb.a leveldb/libmemenv.a \
$(BOOST_LIBS)
+if ENABLE_WALLET
+bitcoind_LDADD += libbitcoin_wallet.a
+endif
bitcoind_SOURCES = bitcoind.cpp
#
@@ -55,15 +108,13 @@ AM_CPPFLAGS += $(BDB_CPPFLAGS)
bitcoind_LDADD += $(BDB_LIBS)
# bitcoin-cli binary #
-bitcoin_cli_LDADD = libbitcoin.a leveldb/libleveldb.a leveldb/libmemenv.a \
- $(BOOST_LIBS)
+bitcoin_cli_LDADD = libbitcoin_cli.a libbitcoin_common.a $(BOOST_LIBS)
bitcoin_cli_SOURCES = bitcoin-cli.cpp
#
if TARGET_WINDOWS
bitcoin_cli_SOURCES += bitcoin-cli-res.rc
endif
-bitcoin_cli_LDADD += $(BDB_LIBS)
leveldb/libleveldb.a: leveldb/libmemenv.a
@@ -72,7 +123,7 @@ leveldb/%.a:
CC="$(CC)" PLATFORM=$(TARGET_OS) AR="$(AR)" $(LEVELDB_TARGET_FLAGS) \
OPT="$(CXXFLAGS) $(CPPFLAGS)"
-qt/bitcoinstrings.cpp: $(libbitcoin_a_SOURCES)
+qt/bitcoinstrings.cpp: $(libbitcoin_server_a_SOURCES) $(libbitcoin_common_a_SOURCES) $(libbitcoin_cli_a_SOURCES)
@test -n $(XGETTEXT) || echo "xgettext is required for updating translations"
@cd $(top_srcdir); XGETTEXT=$(XGETTEXT) share/qt/extract_strings_qt.py
@@ -84,5 +135,4 @@ EXTRA_DIST = leveldb Makefile.include
clean-local:
-$(MAKE) -C leveldb clean
- rm -f leveldb/port/*.gcno leveldb/db/*.gcno leveldb/table/*.gcno leveldb/helpers/*.gcno
- rm -f leveldb/util/*.gcno leveldb/helpers/memenv/*.gcno
+ rm -f leveldb/*/*.gcno leveldb/helpers/memenv/*.gcno
diff --git a/src/Makefile.include b/src/Makefile.include
index 8c2274a287..13cffd29bc 100644
--- a/src/Makefile.include
+++ b/src/Makefile.include
@@ -5,7 +5,10 @@ AM_CPPFLAGS = $(INCLUDES) \
$(BOOST_INCLUDES)
AM_LDFLAGS = $(PTHREAD_CFLAGS)
-LIBBITCOIN=$(top_builddir)/src/libbitcoin.a
+LIBBITCOIN_SERVER=$(top_builddir)/src/libbitcoin_server.a
+LIBBITCOIN_WALLET=$(top_builddir)/src/libbitcoin_wallet.a
+LIBBITCOIN_COMMON=$(top_builddir)/src/libbitcoin_common.a
+LIBBITCOIN_CLI=$(top_builddir)/src/libbitcoin_cli.a
LIBLEVELDB=$(top_builddir)/src/leveldb/libleveldb.a
LIBMEMENV=$(top_builddir)/src/leveldb/libmemenv.a
LIBBITCOINQT=$(top_builddir)/src/qt/libbitcoinqt.a
diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp
index aa6ce27c52..04b75e7f1c 100644
--- a/src/bitcoin-cli.cpp
+++ b/src/bitcoin-cli.cpp
@@ -5,8 +5,9 @@
#include "util.h"
#include "init.h"
-#include "bitcoinrpc.h"
+#include "rpcclient.h"
#include "ui_interface.h" /* for _(...) */
+#include "chainparams.h"
#include <boost/filesystem/operations.hpp>
@@ -26,6 +27,11 @@ static bool AppInitRPC(int argc, char* argv[])
return false;
}
ReadConfigFile(mapArgs, mapMultiArgs);
+ // Check for -testnet or -regtest parameter (TestNet() calls are only valid after this clause)
+ if (!SelectParamsFromCommandLine()) {
+ fprintf(stderr, "Error: Invalid combination of -regtest and -testnet.\n");
+ return false;
+ }
if (argc<2 || mapArgs.count("-?") || mapArgs.count("--help"))
{
@@ -36,7 +42,7 @@ static bool AppInitRPC(int argc, char* argv[])
" bitcoin-cli [options] help " + _("List commands") + "\n" +
" bitcoin-cli [options] help <command> " + _("Get help for a command") + "\n";
- strUsage += "\n" + HelpMessage(HMM_BITCOIN_CLI);
+ strUsage += "\n" + HelpMessageCli(true);
fprintf(stdout, "%s", strUsage.c_str());
return false;
diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp
index 6dbab240bf..e13d688158 100644
--- a/src/bitcoind.cpp
+++ b/src/bitcoind.cpp
@@ -3,7 +3,8 @@
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "bitcoinrpc.h"
+#include "rpcserver.h"
+#include "rpcclient.h"
#include "init.h"
#include "main.h"
#include "noui.h"
@@ -86,6 +87,7 @@ bool AppInit(int argc, char* argv[])
" bitcoind [options] help <command> " + _("Get help for a command") + "\n";
strUsage += "\n" + HelpMessage(HMM_BITCOIND);
+ strUsage += "\n" + HelpMessageCli(false);
fprintf(stdout, "%s", strUsage.c_str());
return false;
diff --git a/src/coins.cpp b/src/coins.cpp
index ed82c9df8b..86b2a6ef17 100644
--- a/src/coins.cpp
+++ b/src/coins.cpp
@@ -178,3 +178,19 @@ bool CCoinsViewCache::HaveInputs(const CTransaction& tx)
}
return true;
}
+
+double CCoinsViewCache::GetPriority(const CTransaction &tx, int nHeight)
+{
+ if (tx.IsCoinBase())
+ return 0.0;
+ double dResult = 0.0;
+ BOOST_FOREACH(const CTxIn& txin, tx.vin)
+ {
+ const CCoins &coins = GetCoins(txin.prevout.hash);
+ if (!coins.IsAvailable(txin.prevout.n)) continue;
+ if (coins.nHeight < nHeight) {
+ dResult += coins.vout[txin.prevout.n].nValue * (nHeight-coins.nHeight);
+ }
+ }
+ return tx.ComputePriority(dResult);
+}
diff --git a/src/coins.h b/src/coins.h
index 2c72ee88e1..0ad28524a1 100644
--- a/src/coins.h
+++ b/src/coins.h
@@ -340,13 +340,15 @@ public:
@param[in] tx transaction for which we are checking input total
@return Sum of value of all inputs (scriptSigs)
- @see CTransaction::FetchInputs
*/
int64_t GetValueIn(const CTransaction& tx);
// Check whether all prevouts of the transaction are present in the UTXO set represented by this view
bool HaveInputs(const CTransaction& tx);
+ // Return priority of tx at height nHeight
+ double GetPriority(const CTransaction &tx, int nHeight);
+
const CTxOut &GetOutputFor(const CTxIn& input);
private:
diff --git a/src/compat.h b/src/compat.h
index 1deef493c2..3924445b1a 100644
--- a/src/compat.h
+++ b/src/compat.h
@@ -11,7 +11,9 @@
#undef _WIN32_WINNT
#endif
#define _WIN32_WINNT 0x0501
+#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN 1
+#endif
#ifndef NOMINMAX
#define NOMINMAX
#endif
@@ -26,6 +28,7 @@
#include <windows.h>
#include <ws2tcpip.h>
#else
+#include <sys/types.h>
#include <arpa/inet.h>
#include <ifaddrs.h>
#include <limits.h>
@@ -35,7 +38,6 @@
#include <sys/fcntl.h>
#include <sys/mman.h>
#include <sys/socket.h>
-#include <sys/types.h>
#include <unistd.h>
#endif
diff --git a/src/core.cpp b/src/core.cpp
index 80cdcb0849..f41ea87fea 100644
--- a/src/core.cpp
+++ b/src/core.cpp
@@ -7,8 +7,6 @@
#include "util.h"
-#include <stdint.h>
-
std::string COutPoint::ToString() const
{
return strprintf("COutPoint(%s, %u)", hash.ToString().substr(0,10).c_str(), n);
@@ -108,6 +106,37 @@ bool CTransaction::IsNewerThan(const CTransaction& old) const
return fNewer;
}
+int64_t CTransaction::GetValueOut() const
+{
+ int64_t nValueOut = 0;
+ BOOST_FOREACH(const CTxOut& txout, vout)
+ {
+ nValueOut += txout.nValue;
+ if (!MoneyRange(txout.nValue) || !MoneyRange(nValueOut))
+ throw std::runtime_error("CTransaction::GetValueOut() : value out of range");
+ }
+ return nValueOut;
+}
+
+double CTransaction::ComputePriority(double dPriorityInputs, unsigned int nTxSize) const
+{
+ // In order to avoid disincentivizing cleaning up the UTXO set we don't count
+ // the constant overhead for each txin and up to 110 bytes of scriptSig (which
+ // is enough to cover a compressed pubkey p2sh redemption) for priority.
+ // Providing any more cleanup incentive than making additional inputs free would
+ // risk encouraging people to create junk outputs to redeem later.
+ if (nTxSize == 0)
+ nTxSize = ::GetSerializeSize(*this, SER_NETWORK, PROTOCOL_VERSION);
+ BOOST_FOREACH(const CTxIn& txin, vin)
+ {
+ unsigned int offset = 41U + std::min(110U, (unsigned int)txin.scriptSig.size());
+ if (nTxSize > offset)
+ nTxSize -= offset;
+ }
+ if (nTxSize == 0) return 0.0;
+ return dPriorityInputs / nTxSize;
+}
+
std::string CTransaction::ToString() const
{
std::string str;
diff --git a/src/core.h b/src/core.h
index e31a7e6582..e61cad90ec 100644
--- a/src/core.h
+++ b/src/core.h
@@ -14,6 +14,10 @@
class CTransaction;
+/** No amount larger than this (in satoshi) is valid */
+static const int64_t MAX_MONEY = 21000000 * COIN;
+inline bool MoneyRange(int64_t nValue) { return (nValue >= 0 && nValue <= MAX_MONEY); }
+
/** An outpoint - a combination of a transaction hash and an index n into its vout */
class COutPoint
{
@@ -50,11 +54,11 @@ public:
class CInPoint
{
public:
- CTransaction* ptx;
+ const CTransaction* ptx;
unsigned int n;
CInPoint() { SetNull(); }
- CInPoint(CTransaction* ptxIn, unsigned int nIn) { ptx = ptxIn; n = nIn; }
+ CInPoint(const CTransaction* ptxIn, unsigned int nIn) { ptx = ptxIn; n = nIn; }
void SetNull() { ptx = NULL; n = (unsigned int) -1; }
bool IsNull() const { return (ptx == NULL && n == (unsigned int) -1); }
};
@@ -217,6 +221,14 @@ public:
uint256 GetHash() const;
bool IsNewerThan(const CTransaction& old) const;
+ // Return sum of txouts.
+ int64_t GetValueOut() const;
+ // GetValueIn() is a method on CCoinsViewCache, because
+ // inputs must be known to compute value in.
+
+ // Compute priority, given priority of inputs and (optionally) tx size
+ double ComputePriority(double dPriorityInputs, unsigned int nTxSize=0) const;
+
bool IsCoinBase() const
{
return (vin.size() == 1 && vin[0].prevout.IsNull());
diff --git a/src/crypter.cpp b/src/crypter.cpp
index 10a34ae24a..4c43e3a798 100644
--- a/src/crypter.cpp
+++ b/src/crypter.cpp
@@ -4,9 +4,11 @@
#include "crypter.h"
+#include "script.h"
+
#include <string>
#include <vector>
-
+#include <boost/foreach.hpp>
#include <openssl/aes.h>
#include <openssl/evp.h>
@@ -117,3 +119,156 @@ bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector<unsigned
return false;
return cKeyCrypter.Decrypt(vchCiphertext, *((CKeyingMaterial*)&vchPlaintext));
}
+
+bool CCryptoKeyStore::SetCrypted()
+{
+ LOCK(cs_KeyStore);
+ if (fUseCrypto)
+ return true;
+ if (!mapKeys.empty())
+ return false;
+ fUseCrypto = true;
+ return true;
+}
+
+bool CCryptoKeyStore::Lock()
+{
+ if (!SetCrypted())
+ return false;
+
+ {
+ LOCK(cs_KeyStore);
+ vMasterKey.clear();
+ }
+
+ NotifyStatusChanged(this);
+ return true;
+}
+
+bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn)
+{
+ {
+ LOCK(cs_KeyStore);
+ if (!SetCrypted())
+ return false;
+
+ CryptedKeyMap::const_iterator mi = mapCryptedKeys.begin();
+ for (; mi != mapCryptedKeys.end(); ++mi)
+ {
+ const CPubKey &vchPubKey = (*mi).second.first;
+ const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second;
+ CKeyingMaterial vchSecret;
+ if(!DecryptSecret(vMasterKeyIn, vchCryptedSecret, vchPubKey.GetHash(), vchSecret))
+ return false;
+ if (vchSecret.size() != 32)
+ return false;
+ CKey key;
+ key.Set(vchSecret.begin(), vchSecret.end(), vchPubKey.IsCompressed());
+ if (key.GetPubKey() == vchPubKey)
+ break;
+ return false;
+ }
+ vMasterKey = vMasterKeyIn;
+ }
+ NotifyStatusChanged(this);
+ return true;
+}
+
+bool CCryptoKeyStore::AddKeyPubKey(const CKey& key, const CPubKey &pubkey)
+{
+ {
+ LOCK(cs_KeyStore);
+ if (!IsCrypted())
+ return CBasicKeyStore::AddKeyPubKey(key, pubkey);
+
+ if (IsLocked())
+ return false;
+
+ std::vector<unsigned char> vchCryptedSecret;
+ CKeyingMaterial vchSecret(key.begin(), key.end());
+ if (!EncryptSecret(vMasterKey, vchSecret, pubkey.GetHash(), vchCryptedSecret))
+ return false;
+
+ if (!AddCryptedKey(pubkey, vchCryptedSecret))
+ return false;
+ }
+ return true;
+}
+
+
+bool CCryptoKeyStore::AddCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret)
+{
+ {
+ LOCK(cs_KeyStore);
+ if (!SetCrypted())
+ return false;
+
+ mapCryptedKeys[vchPubKey.GetID()] = make_pair(vchPubKey, vchCryptedSecret);
+ }
+ return true;
+}
+
+bool CCryptoKeyStore::GetKey(const CKeyID &address, CKey& keyOut) const
+{
+ {
+ LOCK(cs_KeyStore);
+ if (!IsCrypted())
+ return CBasicKeyStore::GetKey(address, keyOut);
+
+ CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address);
+ if (mi != mapCryptedKeys.end())
+ {
+ const CPubKey &vchPubKey = (*mi).second.first;
+ const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second;
+ CKeyingMaterial vchSecret;
+ if (!DecryptSecret(vMasterKey, vchCryptedSecret, vchPubKey.GetHash(), vchSecret))
+ return false;
+ if (vchSecret.size() != 32)
+ return false;
+ keyOut.Set(vchSecret.begin(), vchSecret.end(), vchPubKey.IsCompressed());
+ return true;
+ }
+ }
+ return false;
+}
+
+bool CCryptoKeyStore::GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const
+{
+ {
+ LOCK(cs_KeyStore);
+ if (!IsCrypted())
+ return CKeyStore::GetPubKey(address, vchPubKeyOut);
+
+ CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address);
+ if (mi != mapCryptedKeys.end())
+ {
+ vchPubKeyOut = (*mi).second.first;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool CCryptoKeyStore::EncryptKeys(CKeyingMaterial& vMasterKeyIn)
+{
+ {
+ LOCK(cs_KeyStore);
+ if (!mapCryptedKeys.empty() || IsCrypted())
+ return false;
+
+ fUseCrypto = true;
+ BOOST_FOREACH(KeyMap::value_type& mKey, mapKeys)
+ {
+ const CKey &key = mKey.second;
+ CPubKey vchPubKey = key.GetPubKey();
+ CKeyingMaterial vchSecret(key.begin(), key.end());
+ std::vector<unsigned char> vchCryptedSecret;
+ if (!EncryptSecret(vMasterKeyIn, vchSecret, vchPubKey.GetHash(), vchCryptedSecret))
+ return false;
+ if (!AddCryptedKey(vchPubKey, vchCryptedSecret))
+ return false;
+ }
+ mapKeys.clear();
+ }
+ return true;
+}
diff --git a/src/crypter.h b/src/crypter.h
index 861c4f9441..4791428b48 100644
--- a/src/crypter.h
+++ b/src/crypter.h
@@ -7,6 +7,7 @@
#include "allocators.h"
#include "serialize.h"
+#include "keystore.h"
class uint256;
@@ -106,4 +107,86 @@ public:
bool EncryptSecret(const CKeyingMaterial& vMasterKey, const CKeyingMaterial &vchPlaintext, const uint256& nIV, std::vector<unsigned char> &vchCiphertext);
bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char>& vchCiphertext, const uint256& nIV, CKeyingMaterial& vchPlaintext);
+/** Keystore which keeps the private keys encrypted.
+ * It derives from the basic key store, which is used if no encryption is active.
+ */
+class CCryptoKeyStore : public CBasicKeyStore
+{
+private:
+ CryptedKeyMap mapCryptedKeys;
+
+ CKeyingMaterial vMasterKey;
+
+ // if fUseCrypto is true, mapKeys must be empty
+ // if fUseCrypto is false, vMasterKey must be empty
+ bool fUseCrypto;
+
+protected:
+ bool SetCrypted();
+
+ // will encrypt previously unencrypted keys
+ bool EncryptKeys(CKeyingMaterial& vMasterKeyIn);
+
+ bool Unlock(const CKeyingMaterial& vMasterKeyIn);
+
+public:
+ CCryptoKeyStore() : fUseCrypto(false)
+ {
+ }
+
+ bool IsCrypted() const
+ {
+ return fUseCrypto;
+ }
+
+ bool IsLocked() const
+ {
+ if (!IsCrypted())
+ return false;
+ bool result;
+ {
+ LOCK(cs_KeyStore);
+ result = vMasterKey.empty();
+ }
+ return result;
+ }
+
+ bool Lock();
+
+ virtual bool AddCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret);
+ bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey);
+ bool HaveKey(const CKeyID &address) const
+ {
+ {
+ LOCK(cs_KeyStore);
+ if (!IsCrypted())
+ return CBasicKeyStore::HaveKey(address);
+ return mapCryptedKeys.count(address) > 0;
+ }
+ return false;
+ }
+ bool GetKey(const CKeyID &address, CKey& keyOut) const;
+ bool GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const;
+ void GetKeys(std::set<CKeyID> &setAddress) const
+ {
+ if (!IsCrypted())
+ {
+ CBasicKeyStore::GetKeys(setAddress);
+ return;
+ }
+ setAddress.clear();
+ CryptedKeyMap::const_iterator mi = mapCryptedKeys.begin();
+ while (mi != mapCryptedKeys.end())
+ {
+ setAddress.insert((*mi).first);
+ mi++;
+ }
+ }
+
+ /* Wallet status (encrypted, locked) changed.
+ * Note: Called without locks held.
+ */
+ boost::signals2::signal<void (CCryptoKeyStore* wallet)> NotifyStatusChanged;
+};
+
#endif
diff --git a/src/db.cpp b/src/db.cpp
index a286d9f726..1f2ee1c554 100644
--- a/src/db.cpp
+++ b/src/db.cpp
@@ -479,113 +479,3 @@ void CDBEnv::Flush(bool fShutdown)
}
}
-
-
-
-
-
-
-
-
-
-
-//
-// CAddrDB
-//
-
-CAddrDB::CAddrDB()
-{
- pathAddr = GetDataDir() / "peers.dat";
-}
-
-bool CAddrDB::Write(const CAddrMan& addr)
-{
- // Generate random temporary filename
- unsigned short randv = 0;
- RAND_bytes((unsigned char *)&randv, sizeof(randv));
- std::string tmpfn = strprintf("peers.dat.%04x", randv);
-
- // serialize addresses, checksum data up to that point, then append csum
- CDataStream ssPeers(SER_DISK, CLIENT_VERSION);
- ssPeers << FLATDATA(Params().MessageStart());
- ssPeers << addr;
- uint256 hash = Hash(ssPeers.begin(), ssPeers.end());
- ssPeers << hash;
-
- // open temp output file, and associate with CAutoFile
- boost::filesystem::path pathTmp = GetDataDir() / tmpfn;
- FILE *file = fopen(pathTmp.string().c_str(), "wb");
- CAutoFile fileout = CAutoFile(file, SER_DISK, CLIENT_VERSION);
- if (!fileout)
- return error("CAddrman::Write() : open failed");
-
- // Write and commit header, data
- try {
- fileout << ssPeers;
- }
- catch (std::exception &e) {
- return error("CAddrman::Write() : I/O error");
- }
- FileCommit(fileout);
- fileout.fclose();
-
- // replace existing peers.dat, if any, with new peers.dat.XXXX
- if (!RenameOver(pathTmp, pathAddr))
- return error("CAddrman::Write() : Rename-into-place failed");
-
- return true;
-}
-
-bool CAddrDB::Read(CAddrMan& addr)
-{
- // open input file, and associate with CAutoFile
- FILE *file = fopen(pathAddr.string().c_str(), "rb");
- CAutoFile filein = CAutoFile(file, SER_DISK, CLIENT_VERSION);
- if (!filein)
- return error("CAddrman::Read() : open failed");
-
- // use file size to size memory buffer
- int fileSize = GetFilesize(filein);
- int dataSize = fileSize - sizeof(uint256);
- //Don't try to resize to a negative number if file is small
- if ( dataSize < 0 ) dataSize = 0;
- vector<unsigned char> vchData;
- vchData.resize(dataSize);
- uint256 hashIn;
-
- // read data and checksum from file
- try {
- filein.read((char *)&vchData[0], dataSize);
- filein >> hashIn;
- }
- catch (std::exception &e) {
- return error("CAddrman::Read() 2 : I/O error or stream data corrupted");
- }
- filein.fclose();
-
- CDataStream ssPeers(vchData, SER_DISK, CLIENT_VERSION);
-
- // verify stored checksum matches input data
- uint256 hashTmp = Hash(ssPeers.begin(), ssPeers.end());
- if (hashIn != hashTmp)
- return error("CAddrman::Read() : checksum mismatch; data corrupted");
-
- unsigned char pchMsgTmp[4];
- try {
- // de-serialize file header (network specific magic number) and ..
- ssPeers >> FLATDATA(pchMsgTmp);
-
- // ... verify the network matches ours
- if (memcmp(pchMsgTmp, Params().MessageStart(), sizeof(pchMsgTmp)))
- return error("CAddrman::Read() : invalid network magic number");
-
- // de-serialize address data into one CAddrMan object
- ssPeers >> addr;
- }
- catch (std::exception &e) {
- return error("CAddrman::Read() : I/O error or stream data corrupted");
- }
-
- return true;
-}
-
diff --git a/src/db.h b/src/db.h
index e041a59300..66d7f31917 100644
--- a/src/db.h
+++ b/src/db.h
@@ -305,22 +305,4 @@ public:
bool static Rewrite(const std::string& strFile, const char* pszSkip = NULL);
};
-
-
-
-
-
-
-
-/** Access to the (IP) address database (peers.dat) */
-class CAddrDB
-{
-private:
- boost::filesystem::path pathAddr;
-public:
- CAddrDB();
- bool Write(const CAddrMan& addr);
- bool Read(CAddrMan& addr);
-};
-
#endif // BITCOIN_DB_H
diff --git a/src/init.cpp b/src/init.cpp
index d930f6f693..df3cedc202 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -10,15 +10,18 @@
#include "init.h"
#include "addrman.h"
-#include "bitcoinrpc.h"
+#include "db.h"
+#include "rpcserver.h"
#include "checkpoints.h"
#include "miner.h"
#include "net.h"
#include "txdb.h"
#include "ui_interface.h"
#include "util.h"
+#ifdef ENABLE_WALLET
#include "wallet.h"
#include "walletdb.h"
+#endif
#include <inttypes.h>
#include <stdint.h>
@@ -35,9 +38,10 @@
using namespace std;
using namespace boost;
+#ifdef ENABLE_WALLET
std::string strWalletFile;
CWallet* pwalletMain;
-CClientUIInterface uiInterface;
+#endif
#ifdef WIN32
// Win32 LevelDB doesn't use filedescriptors, and the ones used for
@@ -109,15 +113,20 @@ void Shutdown()
RenameThread("bitcoin-shutoff");
mempool.AddTransactionsUpdated(1);
StopRPCThreads();
+#ifdef ENABLE_WALLET
ShutdownRPCMining();
if (pwalletMain)
bitdb.Flush(false);
- GenerateBitcoins(false, NULL);
+ GenerateBitcoins(false, NULL, 0);
+#endif
StopNode();
+ UnregisterNodeSignals(GetNodeSignals());
{
LOCK(cs_main);
+#ifdef ENABLE_WALLET
if (pwalletMain)
pwalletMain->SetBestChain(chainActive.GetLocator());
+#endif
if (pblocktree)
pblocktree->Flush();
if (pcoinsTip)
@@ -126,12 +135,16 @@ void Shutdown()
delete pcoinsdbview; pcoinsdbview = NULL;
delete pblocktree; pblocktree = NULL;
}
+#ifdef ENABLE_WALLET
if (pwalletMain)
bitdb.Flush(true);
+#endif
boost::filesystem::remove(GetPidFile());
UnregisterAllWallets();
+#ifdef ENABLE_WALLET
if (pwalletMain)
delete pwalletMain;
+#endif
LogPrintf("Shutdown : done\n");
}
@@ -181,45 +194,43 @@ std::string HelpMessage(HelpMessageMode hmm)
strUsage += " -datadir=<dir> " + _("Specify data directory") + "\n";
strUsage += " -testnet " + _("Use the test network") + "\n";
- if(hmm == HMM_BITCOIND || hmm == HMM_BITCOIN_QT)
- {
- strUsage += " -pid=<file> " + _("Specify pid file (default: bitcoind.pid)") + "\n";
- strUsage += " -gen " + _("Generate coins (default: 0)") + "\n";
- strUsage += " -wallet=<file> " + _("Specify wallet file (within data directory)") + "\n";
- strUsage += " -dbcache=<n> " + _("Set database cache size in megabytes (default: 25)") + "\n";
- strUsage += " -timeout=<n> " + _("Specify connection timeout in milliseconds (default: 5000)") + "\n";
- strUsage += " -proxy=<ip:port> " + _("Connect through socks proxy") + "\n";
- strUsage += " -socks=<n> " + _("Select the version of socks proxy to use (4-5, default: 5)") + "\n";
- strUsage += " -onion=<ip:port> " + _("Use proxy to reach tor hidden services (default: same as -proxy)") + "\n";
- strUsage += " -dns " + _("Allow DNS lookups for -addnode, -seednode and -connect") + "\n";
- strUsage += " -port=<port> " + _("Listen for connections on <port> (default: 8333 or testnet: 18333)") + "\n";
- strUsage += " -maxconnections=<n> " + _("Maintain at most <n> connections to peers (default: 125)") + "\n";
- strUsage += " -addnode=<ip> " + _("Add a node to connect to and attempt to keep the connection open") + "\n";
- strUsage += " -connect=<ip> " + _("Connect only to the specified node(s)") + "\n";
- strUsage += " -seednode=<ip> " + _("Connect to a node to retrieve peer addresses, and disconnect") + "\n";
- strUsage += " -externalip=<ip> " + _("Specify your own public address") + "\n";
- strUsage += " -onlynet=<net> " + _("Only connect to nodes in network <net> (IPv4, IPv6 or Tor)") + "\n";
- strUsage += " -discover " + _("Discover own IP address (default: 1 when listening and no -externalip)") + "\n";
- strUsage += " -checkpoints " + _("Only accept block chain matching built-in checkpoints (default: 1)") + "\n";
- strUsage += " -listen " + _("Accept connections from outside (default: 1 if no -proxy or -connect)") + "\n";
- strUsage += " -bind=<addr> " + _("Bind to given address and always listen on it. Use [host]:port notation for IPv6") + "\n";
- strUsage += " -dnsseed " + _("Find peers using DNS lookup (default: 1 unless -connect)") + "\n";
- strUsage += " -banscore=<n> " + _("Threshold for disconnecting misbehaving peers (default: 100)") + "\n";
- strUsage += " -bantime=<n> " + _("Number of seconds to keep misbehaving peers from reconnecting (default: 86400)") + "\n";
- strUsage += " -maxreceivebuffer=<n> " + _("Maximum per-connection receive buffer, <n>*1000 bytes (default: 5000)") + "\n";
- strUsage += " -maxsendbuffer=<n> " + _("Maximum per-connection send buffer, <n>*1000 bytes (default: 1000)") + "\n";
+ strUsage += " -pid=<file> " + _("Specify pid file (default: bitcoind.pid)") + "\n";
+ strUsage += " -gen " + _("Generate coins (default: 0)") + "\n";
+ strUsage += " -wallet=<file> " + _("Specify wallet file (within data directory)") + "\n";
+ strUsage += " -dbcache=<n> " + _("Set database cache size in megabytes (default: 25)") + "\n";
+ strUsage += " -timeout=<n> " + _("Specify connection timeout in milliseconds (default: 5000)") + "\n";
+ strUsage += " -proxy=<ip:port> " + _("Connect through socks proxy") + "\n";
+ strUsage += " -socks=<n> " + _("Select the version of socks proxy to use (4-5, default: 5)") + "\n";
+ strUsage += " -onion=<ip:port> " + _("Use proxy to reach tor hidden services (default: same as -proxy)") + "\n";
+ strUsage += " -dns " + _("Allow DNS lookups for -addnode, -seednode and -connect") + "\n";
+ strUsage += " -port=<port> " + _("Listen for connections on <port> (default: 8333 or testnet: 18333)") + "\n";
+ strUsage += " -maxconnections=<n> " + _("Maintain at most <n> connections to peers (default: 125)") + "\n";
+ strUsage += " -addnode=<ip> " + _("Add a node to connect to and attempt to keep the connection open") + "\n";
+ strUsage += " -connect=<ip> " + _("Connect only to the specified node(s)") + "\n";
+ strUsage += " -seednode=<ip> " + _("Connect to a node to retrieve peer addresses, and disconnect") + "\n";
+ strUsage += " -externalip=<ip> " + _("Specify your own public address") + "\n";
+ strUsage += " -onlynet=<net> " + _("Only connect to nodes in network <net> (IPv4, IPv6 or Tor)") + "\n";
+ strUsage += " -discover " + _("Discover own IP address (default: 1 when listening and no -externalip)") + "\n";
+ strUsage += " -checkpoints " + _("Only accept block chain matching built-in checkpoints (default: 1)") + "\n";
+ strUsage += " -listen " + _("Accept connections from outside (default: 1 if no -proxy or -connect)") + "\n";
+ strUsage += " -bind=<addr> " + _("Bind to given address and always listen on it. Use [host]:port notation for IPv6") + "\n";
+ strUsage += " -dnsseed " + _("Find peers using DNS lookup (default: 1 unless -connect)") + "\n";
+ strUsage += " -banscore=<n> " + _("Threshold for disconnecting misbehaving peers (default: 100)") + "\n";
+ strUsage += " -bantime=<n> " + _("Number of seconds to keep misbehaving peers from reconnecting (default: 86400)") + "\n";
+ strUsage += " -maxreceivebuffer=<n> " + _("Maximum per-connection receive buffer, <n>*1000 bytes (default: 5000)") + "\n";
+ strUsage += " -maxsendbuffer=<n> " + _("Maximum per-connection send buffer, <n>*1000 bytes (default: 1000)") + "\n";
#ifdef USE_UPNP
#if USE_UPNP
- strUsage += " -upnp " + _("Use UPnP to map the listening port (default: 1 when listening)") + "\n";
+ strUsage += " -upnp " + _("Use UPnP to map the listening port (default: 1 when listening)") + "\n";
#else
- strUsage += " -upnp " + _("Use UPnP to map the listening port (default: 0)") + "\n";
+ strUsage += " -upnp " + _("Use UPnP to map the listening port (default: 0)") + "\n";
#endif
#endif
- strUsage += " -paytxfee=<amt> " + _("Fee per KB to add to transactions you send") + "\n";
- strUsage += " -debug=<category> " + _("Output debugging information (default: 0, supplying <category> is optional)") + "\n";
- strUsage += _("If <category> is not supplied, output all debugging information.") + "\n";
- strUsage += _("<category> can be:");
- strUsage += " addrman, alert, coindb, db, lock, rand, rpc, selectcoins, mempool, net"; // Don't translate these and qt below
+ strUsage += " -paytxfee=<amt> " + _("Fee per KB to add to transactions you send") + "\n";
+ strUsage += " -debug=<category> " + _("Output debugging information (default: 0, supplying <category> is optional)") + "\n";
+ strUsage += _("If <category> is not supplied, output all debugging information.") + "\n";
+ strUsage += _("<category> can be:");
+ strUsage += " addrman, alert, coindb, db, lock, rand, rpc, selectcoins, mempool, net"; // Don't translate these and qt below
if (hmm == HMM_BITCOIN_QT)
{
strUsage += ", qt.\n";
@@ -228,15 +239,14 @@ std::string HelpMessage(HelpMessageMode hmm)
{
strUsage += ".\n";
}
- strUsage += " -logtimestamps " + _("Prepend debug output with timestamp (default: 1)") + "\n";
- strUsage += " -shrinkdebugfile " + _("Shrink debug.log file on client startup (default: 1 when no -debug)") + "\n";
- strUsage += " -printtoconsole " + _("Send trace/debug info to console instead of debug.log file") + "\n";
- strUsage += " -regtest " + _("Enter regression test mode, which uses a special chain in which blocks can be "
- "solved instantly. This is intended for regression testing tools and app development.") + "\n";
+ strUsage += " -logtimestamps " + _("Prepend debug output with timestamp (default: 1)") + "\n";
+ strUsage += " -shrinkdebugfile " + _("Shrink debug.log file on client startup (default: 1 when no -debug)") + "\n";
+ strUsage += " -printtoconsole " + _("Send trace/debug info to console instead of debug.log file") + "\n";
+ strUsage += " -regtest " + _("Enter regression test mode, which uses a special chain in which blocks can be "
+ "solved instantly. This is intended for regression testing tools and app development.") + "\n";
#ifdef WIN32
- strUsage += " -printtodebugger " + _("Send trace/debug info to debugger") + "\n";
+ strUsage += " -printtodebugger " + _("Send trace/debug info to debugger") + "\n";
#endif
- }
if (hmm == HMM_BITCOIN_QT)
{
@@ -250,52 +260,36 @@ std::string HelpMessage(HelpMessageMode hmm)
#endif
}
- if (hmm == HMM_BITCOIND || hmm == HMM_BITCOIN_CLI)
- {
- strUsage += " -rpcconnect=<ip> " + _("Send commands to node running on <ip> (default: 127.0.0.1)") + "\n";
- }
-
strUsage += " -rpcuser=<user> " + _("Username for JSON-RPC connections") + "\n";
strUsage += " -rpcpassword=<pw> " + _("Password for JSON-RPC connections") + "\n";
- if (hmm == HMM_BITCOIND || hmm == HMM_BITCOIN_QT)
- {
- strUsage += " -rpcport=<port> " + _("Listen for JSON-RPC connections on <port> (default: 8332 or testnet: 18332)") + "\n";
- } else {
- strUsage += " -rpcport=<port> " + _("Connect to JSON-RPC on <port> (default: 8332 or testnet: 18332)") + "\n";
- }
-
- if(hmm == HMM_BITCOIND || hmm == HMM_BITCOIN_QT)
- {
- strUsage += " -rpcallowip=<ip> " + _("Allow JSON-RPC connections from specified IP address") + "\n";
- strUsage += " -rpcthreads=<n> " + _("Set the number of threads to service RPC calls (default: 4)") + "\n";
- strUsage += " -blocknotify=<cmd> " + _("Execute command when the best block changes (%s in cmd is replaced by block hash)") + "\n";
- strUsage += " -walletnotify=<cmd> " + _("Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)") + "\n";
- strUsage += " -alertnotify=<cmd> " + _("Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message)") + "\n";
- strUsage += " -upgradewallet " + _("Upgrade wallet to latest format") + "\n";
- strUsage += " -keypool=<n> " + _("Set key pool size to <n> (default: 100)") + "\n";
- strUsage += " -rescan " + _("Rescan the block chain for missing wallet transactions") + "\n";
- strUsage += " -salvagewallet " + _("Attempt to recover private keys from a corrupt wallet.dat") + "\n";
- strUsage += " -checkblocks=<n> " + _("How many blocks to check at startup (default: 288, 0 = all)") + "\n";
- strUsage += " -checklevel=<n> " + _("How thorough the block verification is (0-4, default: 3)") + "\n";
- strUsage += " -txindex " + _("Maintain a full transaction index (default: 0)") + "\n";
- strUsage += " -loadblock=<file> " + _("Imports blocks from external blk000??.dat file") + "\n";
- strUsage += " -reindex " + _("Rebuild block chain index from current blk000??.dat files") + "\n";
- strUsage += " -par=<n> " + _("Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0)") + "\n";
-
- strUsage += "\n" + _("Block creation options:") + "\n";
- strUsage += " -blockminsize=<n> " + _("Set minimum block size in bytes (default: 0)") + "\n";
- strUsage += " -blockmaxsize=<n> " + _("Set maximum block size in bytes (default: 250000)") + "\n";
- strUsage += " -blockprioritysize=<n> " + _("Set maximum size of high-priority/low-fee transactions in bytes (default: 27000)") + "\n";
- }
+ strUsage += " -rpcport=<port> " + _("Listen for JSON-RPC connections on <port> (default: 8332 or testnet: 18332)") + "\n";
+
+ strUsage += " -rpcallowip=<ip> " + _("Allow JSON-RPC connections from specified IP address") + "\n";
+ strUsage += " -rpcthreads=<n> " + _("Set the number of threads to service RPC calls (default: 4)") + "\n";
+ strUsage += " -blocknotify=<cmd> " + _("Execute command when the best block changes (%s in cmd is replaced by block hash)") + "\n";
+ strUsage += " -walletnotify=<cmd> " + _("Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)") + "\n";
+ strUsage += " -alertnotify=<cmd> " + _("Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message)") + "\n";
+ strUsage += " -upgradewallet " + _("Upgrade wallet to latest format") + "\n";
+ strUsage += " -keypool=<n> " + _("Set key pool size to <n> (default: 100)") + "\n";
+ strUsage += " -rescan " + _("Rescan the block chain for missing wallet transactions") + "\n";
+ strUsage += " -salvagewallet " + _("Attempt to recover private keys from a corrupt wallet.dat") + "\n";
+ strUsage += " -checkblocks=<n> " + _("How many blocks to check at startup (default: 288, 0 = all)") + "\n";
+ strUsage += " -checklevel=<n> " + _("How thorough the block verification is (0-4, default: 3)") + "\n";
+ strUsage += " -txindex " + _("Maintain a full transaction index (default: 0)") + "\n";
+ strUsage += " -loadblock=<file> " + _("Imports blocks from external blk000??.dat file") + "\n";
+ strUsage += " -reindex " + _("Rebuild block chain index from current blk000??.dat files") + "\n";
+ strUsage += " -par=<n> " + _("Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0)") + "\n";
+
+ strUsage += "\n" + _("Block creation options:") + "\n";
+ strUsage += " -blockminsize=<n> " + _("Set minimum block size in bytes (default: 0)") + "\n";
+ strUsage += " -blockmaxsize=<n> " + _("Set maximum block size in bytes (default: 250000)") + "\n";
+ strUsage += " -blockprioritysize=<n> " + _("Set maximum size of high-priority/low-fee transactions in bytes (default: 27000)") + "\n";
strUsage += "\n" + _("SSL options: (see the Bitcoin Wiki for SSL setup instructions)") + "\n";
strUsage += " -rpcssl " + _("Use OpenSSL (https) for JSON-RPC connections") + "\n";
- if (hmm == HMM_BITCOIND || hmm == HMM_BITCOIN_QT)
- {
- strUsage += " -rpcsslcertificatechainfile=<file.cert> " + _("Server certificate file (default: server.cert)") + "\n";
- strUsage += " -rpcsslprivatekeyfile=<file.pem> " + _("Server private key (default: server.pem)") + "\n";
- strUsage += " -rpcsslciphers=<ciphers> " + _("Acceptable ciphers (default: TLSv1.2+HIGH:TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!3DES:@STRENGTH)") + "\n";
- }
+ strUsage += " -rpcsslcertificatechainfile=<file.cert> " + _("Server certificate file (default: server.cert)") + "\n";
+ strUsage += " -rpcsslprivatekeyfile=<file.pem> " + _("Server private key (default: server.pem)") + "\n";
+ strUsage += " -rpcsslciphers=<ciphers> " + _("Acceptable ciphers (default: TLSv1.2+HIGH:TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!3DES:@STRENGTH)") + "\n";
return strUsage;
}
@@ -499,7 +493,9 @@ bool AppInit2(boost::thread_group& threadGroup, bool fForceServer)
fPrintToConsole = GetBoolArg("-printtoconsole", false);
fPrintToDebugger = GetBoolArg("-printtodebugger", false);
fLogTimestamps = GetBoolArg("-logtimestamps", true);
+#ifdef ENABLE_WALLET
bool fDisableWallet = GetBoolArg("-disablewallet", false);
+#endif
if (mapArgs.count("-timeout"))
{
@@ -545,16 +541,17 @@ bool AppInit2(boost::thread_group& threadGroup, bool fForceServer)
InitWarning(_("Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction."));
}
+#ifdef ENABLE_WALLET
strWalletFile = GetArg("-wallet", "wallet.dat");
-
+#endif
// ********************************************************* Step 4: application initialization: dir lock, daemonize, pidfile, debug log
std::string strDataDir = GetDataDir().string();
-
+#ifdef ENABLE_WALLET
// Wallet file must be a plain filename without a directory
if (strWalletFile != boost::filesystem::basename(strWalletFile) + boost::filesystem::extension(strWalletFile))
return InitError(strprintf(_("Wallet %s resides outside data directory %s"), strWalletFile.c_str(), strDataDir.c_str()));
-
+#endif
// Make sure only a single Bitcoin process is using the data directory.
boost::filesystem::path pathLockFile = GetDataDir() / ".lock";
FILE* file = fopen(pathLockFile.string().c_str(), "a"); // empty lock file; created if it doesn't exist.
@@ -587,7 +584,7 @@ bool AppInit2(boost::thread_group& threadGroup, bool fForceServer)
int64_t nStart;
// ********************************************************* Step 5: verify wallet database integrity
-
+#ifdef ENABLE_WALLET
if (!fDisableWallet) {
uiInterface.InitMessage(_("Verifying wallet..."));
@@ -633,7 +630,7 @@ bool AppInit2(boost::thread_group& threadGroup, bool fForceServer)
return InitError(_("wallet.dat corrupt, salvage failed"));
}
} // (!fDisableWallet)
-
+#endif // ENABLE_WALLET
// ********************************************************* Step 6: network initialization
RegisterNodeSignals(GetNodeSignals());
@@ -900,7 +897,7 @@ bool AppInit2(boost::thread_group& threadGroup, bool fForceServer)
}
// ********************************************************* Step 8: load wallet
-
+#ifdef ENABLE_WALLET
if (fDisableWallet) {
pwalletMain = NULL;
LogPrintf("Wallet disabled!\n");
@@ -992,7 +989,9 @@ bool AppInit2(boost::thread_group& threadGroup, bool fForceServer)
nWalletDBUpdated++;
}
} // (!fDisableWallet)
-
+#else // ENABLE_WALLET
+ LogPrintf("No wallet compiled in!\n");
+#endif // !ENABLE_WALLET
// ********************************************************* Step 9: import blocks
// scan for better chains in the block chain database, that are not yet connected in the active best chain
@@ -1036,25 +1035,31 @@ bool AppInit2(boost::thread_group& threadGroup, bool fForceServer)
//// debug print
LogPrintf("mapBlockIndex.size() = %"PRIszu"\n", mapBlockIndex.size());
LogPrintf("nBestHeight = %d\n", chainActive.Height());
+#ifdef ENABLE_WALLET
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);
+#endif
StartNode(threadGroup);
-
+#ifdef ENABLE_WALLET
// InitRPCMining is needed here so getwork/getblocktemplate in the GUI debug console works properly.
InitRPCMining();
+#endif
if (fServer)
StartRPCThreads();
+#ifdef ENABLE_WALLET
// Generate coins in the background
if (pwalletMain)
- GenerateBitcoins(GetBoolArg("-gen", false), pwalletMain);
+ GenerateBitcoins(GetBoolArg("-gen", false), pwalletMain, GetArg("-genproclimit", -1));
+#endif
// ********************************************************* Step 12: finished
uiInterface.InitMessage(_("Done loading"));
+#ifdef ENABLE_WALLET
if (pwalletMain) {
// Add wallet transactions that aren't already in a block to mapTransactions
pwalletMain->ReacceptWalletTransactions();
@@ -1062,6 +1067,7 @@ bool AppInit2(boost::thread_group& threadGroup, bool fForceServer)
// Run a thread to flush wallet periodically
threadGroup.create_thread(boost::bind(&ThreadFlushWalletDB, boost::ref(pwalletMain->strWalletFile)));
}
+#endif
return !fRequestShutdown;
}
diff --git a/src/init.h b/src/init.h
index 864f2f4614..018d2d5ea3 100644
--- a/src/init.h
+++ b/src/init.h
@@ -26,8 +26,7 @@ bool AppInit2(boost::thread_group& threadGroup, bool fForceServer);
enum HelpMessageMode
{
HMM_BITCOIND,
- HMM_BITCOIN_QT,
- HMM_BITCOIN_CLI
+ HMM_BITCOIN_QT
};
std::string HelpMessage(HelpMessageMode mode);
diff --git a/src/key.cpp b/src/key.cpp
index 2fd68fa56b..b57b7c506c 100644
--- a/src/key.cpp
+++ b/src/key.cpp
@@ -148,10 +148,13 @@ public:
}
void SetSecretBytes(const unsigned char vch[32]) {
+ bool ret;
BIGNUM bn;
BN_init(&bn);
- assert(BN_bin2bn(vch, 32, &bn));
- assert(EC_KEY_regenerate_key(pkey, &bn));
+ ret = BN_bin2bn(vch, 32, &bn);
+ assert(ret);
+ ret = EC_KEY_regenerate_key(pkey, &bn);
+ assert(ret);
BN_clear_free(&bn);
}
diff --git a/src/keystore.cpp b/src/keystore.cpp
index 05427291e0..46402ea25b 100644
--- a/src/keystore.cpp
+++ b/src/keystore.cpp
@@ -56,155 +56,3 @@ bool CBasicKeyStore::GetCScript(const CScriptID &hash, CScript& redeemScriptOut)
return false;
}
-bool CCryptoKeyStore::SetCrypted()
-{
- LOCK(cs_KeyStore);
- if (fUseCrypto)
- return true;
- if (!mapKeys.empty())
- return false;
- fUseCrypto = true;
- return true;
-}
-
-bool CCryptoKeyStore::Lock()
-{
- if (!SetCrypted())
- return false;
-
- {
- LOCK(cs_KeyStore);
- vMasterKey.clear();
- }
-
- NotifyStatusChanged(this);
- return true;
-}
-
-bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn)
-{
- {
- LOCK(cs_KeyStore);
- if (!SetCrypted())
- return false;
-
- CryptedKeyMap::const_iterator mi = mapCryptedKeys.begin();
- for (; mi != mapCryptedKeys.end(); ++mi)
- {
- const CPubKey &vchPubKey = (*mi).second.first;
- const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second;
- CKeyingMaterial vchSecret;
- if(!DecryptSecret(vMasterKeyIn, vchCryptedSecret, vchPubKey.GetHash(), vchSecret))
- return false;
- if (vchSecret.size() != 32)
- return false;
- CKey key;
- key.Set(vchSecret.begin(), vchSecret.end(), vchPubKey.IsCompressed());
- if (key.GetPubKey() == vchPubKey)
- break;
- return false;
- }
- vMasterKey = vMasterKeyIn;
- }
- NotifyStatusChanged(this);
- return true;
-}
-
-bool CCryptoKeyStore::AddKeyPubKey(const CKey& key, const CPubKey &pubkey)
-{
- {
- LOCK(cs_KeyStore);
- if (!IsCrypted())
- return CBasicKeyStore::AddKeyPubKey(key, pubkey);
-
- if (IsLocked())
- return false;
-
- std::vector<unsigned char> vchCryptedSecret;
- CKeyingMaterial vchSecret(key.begin(), key.end());
- if (!EncryptSecret(vMasterKey, vchSecret, pubkey.GetHash(), vchCryptedSecret))
- return false;
-
- if (!AddCryptedKey(pubkey, vchCryptedSecret))
- return false;
- }
- return true;
-}
-
-
-bool CCryptoKeyStore::AddCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret)
-{
- {
- LOCK(cs_KeyStore);
- if (!SetCrypted())
- return false;
-
- mapCryptedKeys[vchPubKey.GetID()] = make_pair(vchPubKey, vchCryptedSecret);
- }
- return true;
-}
-
-bool CCryptoKeyStore::GetKey(const CKeyID &address, CKey& keyOut) const
-{
- {
- LOCK(cs_KeyStore);
- if (!IsCrypted())
- return CBasicKeyStore::GetKey(address, keyOut);
-
- CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address);
- if (mi != mapCryptedKeys.end())
- {
- const CPubKey &vchPubKey = (*mi).second.first;
- const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second;
- CKeyingMaterial vchSecret;
- if (!DecryptSecret(vMasterKey, vchCryptedSecret, vchPubKey.GetHash(), vchSecret))
- return false;
- if (vchSecret.size() != 32)
- return false;
- keyOut.Set(vchSecret.begin(), vchSecret.end(), vchPubKey.IsCompressed());
- return true;
- }
- }
- return false;
-}
-
-bool CCryptoKeyStore::GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const
-{
- {
- LOCK(cs_KeyStore);
- if (!IsCrypted())
- return CKeyStore::GetPubKey(address, vchPubKeyOut);
-
- CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address);
- if (mi != mapCryptedKeys.end())
- {
- vchPubKeyOut = (*mi).second.first;
- return true;
- }
- }
- return false;
-}
-
-bool CCryptoKeyStore::EncryptKeys(CKeyingMaterial& vMasterKeyIn)
-{
- {
- LOCK(cs_KeyStore);
- if (!mapCryptedKeys.empty() || IsCrypted())
- return false;
-
- fUseCrypto = true;
- BOOST_FOREACH(KeyMap::value_type& mKey, mapKeys)
- {
- const CKey &key = mKey.second;
- CPubKey vchPubKey = key.GetPubKey();
- CKeyingMaterial vchSecret(key.begin(), key.end());
- std::vector<unsigned char> vchCryptedSecret;
- if (!EncryptSecret(vMasterKeyIn, vchSecret, vchPubKey.GetHash(), vchCryptedSecret))
- return false;
- if (!AddCryptedKey(vchPubKey, vchCryptedSecret))
- return false;
- }
- mapKeys.clear();
- }
- return true;
-}
diff --git a/src/keystore.h b/src/keystore.h
index 8d936bcab7..0d55e6c81e 100644
--- a/src/keystore.h
+++ b/src/keystore.h
@@ -93,87 +93,4 @@ public:
typedef std::vector<unsigned char, secure_allocator<unsigned char> > CKeyingMaterial;
typedef std::map<CKeyID, std::pair<CPubKey, std::vector<unsigned char> > > CryptedKeyMap;
-
-/** Keystore which keeps the private keys encrypted.
- * It derives from the basic key store, which is used if no encryption is active.
- */
-class CCryptoKeyStore : public CBasicKeyStore
-{
-private:
- CryptedKeyMap mapCryptedKeys;
-
- CKeyingMaterial vMasterKey;
-
- // if fUseCrypto is true, mapKeys must be empty
- // if fUseCrypto is false, vMasterKey must be empty
- bool fUseCrypto;
-
-protected:
- bool SetCrypted();
-
- // will encrypt previously unencrypted keys
- bool EncryptKeys(CKeyingMaterial& vMasterKeyIn);
-
- bool Unlock(const CKeyingMaterial& vMasterKeyIn);
-
-public:
- CCryptoKeyStore() : fUseCrypto(false)
- {
- }
-
- bool IsCrypted() const
- {
- return fUseCrypto;
- }
-
- bool IsLocked() const
- {
- if (!IsCrypted())
- return false;
- bool result;
- {
- LOCK(cs_KeyStore);
- result = vMasterKey.empty();
- }
- return result;
- }
-
- bool Lock();
-
- virtual bool AddCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret);
- bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey);
- bool HaveKey(const CKeyID &address) const
- {
- {
- LOCK(cs_KeyStore);
- if (!IsCrypted())
- return CBasicKeyStore::HaveKey(address);
- return mapCryptedKeys.count(address) > 0;
- }
- return false;
- }
- bool GetKey(const CKeyID &address, CKey& keyOut) const;
- bool GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const;
- void GetKeys(std::set<CKeyID> &setAddress) const
- {
- if (!IsCrypted())
- {
- CBasicKeyStore::GetKeys(setAddress);
- return;
- }
- setAddress.clear();
- CryptedKeyMap::const_iterator mi = mapCryptedKeys.begin();
- while (mi != mapCryptedKeys.end())
- {
- setAddress.insert((*mi).first);
- mi++;
- }
- }
-
- /* Wallet status (encrypted, locked) changed.
- * Note: Called without locks held.
- */
- boost::signals2::signal<void (CCryptoKeyStore* wallet)> NotifyStatusChanged;
-};
-
#endif
diff --git a/src/m4/ax_boost_base.m4 b/src/m4/ax_boost_base.m4
index 54a2a1bee7..57d14fe48d 100644
--- a/src/m4/ax_boost_base.m4
+++ b/src/m4/ax_boost_base.m4
@@ -33,7 +33,7 @@
# and this notice are preserved. This file is offered as-is, without any
# warranty.
-#serial 20
+#serial 21
AC_DEFUN([AX_BOOST_BASE],
[
@@ -91,9 +91,11 @@ if test "x$want_boost" = "xyes"; then
dnl are found, e.g. when only header-only libraries are installed!
libsubdirs="lib"
ax_arch=`uname -m`
- if test $ax_arch = x86_64 -o $ax_arch = ppc64 -o $ax_arch = s390x -o $ax_arch = sparc64; then
+ case $ax_arch in
+ x86_64|ppc64|s390x|sparc64|aarch64)
libsubdirs="lib64 lib lib64"
- fi
+ ;;
+ esac
dnl first we check the system location for boost libraries
dnl this location ist chosen if boost libraries are installed with the --layout=system option
diff --git a/src/m4/ax_boost_filesystem.m4 b/src/m4/ax_boost_filesystem.m4
index 2a62da8d89..f162163cdc 100644
--- a/src/m4/ax_boost_filesystem.m4
+++ b/src/m4/ax_boost_filesystem.m4
@@ -31,7 +31,7 @@
# and this notice are preserved. This file is offered as-is, without any
# warranty.
-#serial 21
+#serial 26
AC_DEFUN([AX_BOOST_FILESYSTEM],
[
@@ -81,14 +81,14 @@ AC_DEFUN([AX_BOOST_FILESYSTEM],
AC_DEFINE(HAVE_BOOST_FILESYSTEM,,[define if the Boost::Filesystem library is available])
BOOSTLIBDIR=`echo $BOOST_LDFLAGS | sed -e 's/@<:@^\/@:>@*//'`
if test "x$ax_boost_user_filesystem_lib" = "x"; then
- for libextension in `ls $BOOSTLIBDIR/libboost_filesystem*.so* $BOOSTLIBDIR/libboost_filesystem*.dylib* $BOOSTLIBDIR/libboost_filesystem*.a* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^lib\(boost_filesystem.*\)\.so.*$;\1;' -e 's;^lib\(boost_filesystem.*\)\.a*$;\1;' -e 's;^lib\(boost_filesystem.*\)\.dylib$;\1;'` ; do
+ for libextension in `ls -r $BOOSTLIBDIR/libboost_filesystem* 2>/dev/null | sed 's,.*/lib,,' | sed 's,\..*,,'` ; do
ax_lib=${libextension}
AC_CHECK_LIB($ax_lib, exit,
[BOOST_FILESYSTEM_LIB="-l$ax_lib"; AC_SUBST(BOOST_FILESYSTEM_LIB) link_filesystem="yes"; break],
[link_filesystem="no"])
done
- if test "x$link_program_options" != "xyes"; then
- for libextension in `ls $BOOSTLIBDIR/boost_filesystem*.{dll,a}* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^\(boost_filesystem.*\)\.dll.*$;\1;' -e 's;^\(boost_filesystem.*\)\.a*$;\1;'` ; do
+ if test "x$link_filesystem" != "xyes"; then
+ for libextension in `ls -r $BOOSTLIBDIR/boost_filesystem* 2>/dev/null | sed 's,.*/,,' | sed -e 's,\..*,,'` ; do
ax_lib=${libextension}
AC_CHECK_LIB($ax_lib, exit,
[BOOST_FILESYSTEM_LIB="-l$ax_lib"; AC_SUBST(BOOST_FILESYSTEM_LIB) link_filesystem="yes"; break],
diff --git a/src/m4/ax_boost_program_options.m4 b/src/m4/ax_boost_program_options.m4
index d612f91da3..65a39c8c70 100644
--- a/src/m4/ax_boost_program_options.m4
+++ b/src/m4/ax_boost_program_options.m4
@@ -29,7 +29,7 @@
# and this notice are preserved. This file is offered as-is, without any
# warranty.
-#serial 20
+#serial 22
AC_DEFUN([AX_BOOST_PROGRAM_OPTIONS],
[
@@ -74,14 +74,14 @@ AC_DEFUN([AX_BOOST_PROGRAM_OPTIONS],
AC_DEFINE(HAVE_BOOST_PROGRAM_OPTIONS,,[define if the Boost::PROGRAM_OPTIONS library is available])
BOOSTLIBDIR=`echo $BOOST_LDFLAGS | sed -e 's/@<:@^\/@:>@*//'`
if test "x$ax_boost_user_program_options_lib" = "x"; then
- for libextension in `ls $BOOSTLIBDIR/libboost_program_options*.so* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^lib\(boost_program_options.*\)\.so.*$;\1;'` `ls $BOOSTLIBDIR/libboost_program_options*.a* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^lib\(boost_program_options.*\)\.a*$;\1;'` ; do
+ for libextension in `ls $BOOSTLIBDIR/libboost_program_options*.so* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^lib\(boost_program_options.*\)\.so.*$;\1;'` `ls $BOOSTLIBDIR/libboost_program_options*.dylib* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^lib\(boost_program_options.*\)\.dylib.*$;\1;'` `ls $BOOSTLIBDIR/libboost_program_options*.a* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^lib\(boost_program_options.*\)\.a.*$;\1;'` ; do
ax_lib=${libextension}
AC_CHECK_LIB($ax_lib, exit,
[BOOST_PROGRAM_OPTIONS_LIB="-l$ax_lib"; AC_SUBST(BOOST_PROGRAM_OPTIONS_LIB) link_program_options="yes"; break],
[link_program_options="no"])
done
if test "x$link_program_options" != "xyes"; then
- for libextension in `ls $BOOSTLIBDIR/boost_program_options*.dll* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^\(boost_program_options.*\)\.dll.*$;\1;'` `ls $BOOSTLIBDIR/boost_program_options*.a* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^\(boost_program_options.*\)\.a*$;\1;'` ; do
+ for libextension in `ls $BOOSTLIBDIR/boost_program_options*.dll* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^\(boost_program_options.*\)\.dll.*$;\1;'` `ls $BOOSTLIBDIR/boost_program_options*.a* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^\(boost_program_options.*\)\.a.*$;\1;'` ; do
ax_lib=${libextension}
AC_CHECK_LIB($ax_lib, exit,
[BOOST_PROGRAM_OPTIONS_LIB="-l$ax_lib"; AC_SUBST(BOOST_PROGRAM_OPTIONS_LIB) link_program_options="yes"; break],
diff --git a/src/m4/ax_boost_system.m4 b/src/m4/ax_boost_system.m4
index 7fbf6d360d..c4c45559d8 100644
--- a/src/m4/ax_boost_system.m4
+++ b/src/m4/ax_boost_system.m4
@@ -31,7 +31,7 @@
# and this notice are preserved. This file is offered as-is, without any
# warranty.
-#serial 14
+#serial 17
AC_DEFUN([AX_BOOST_SYSTEM],
[
@@ -83,14 +83,14 @@ AC_DEFUN([AX_BOOST_SYSTEM],
LDFLAGS_SAVE=$LDFLAGS
if test "x$ax_boost_user_system_lib" = "x"; then
- for libextension in `ls $BOOSTLIBDIR/libboost_system*.so* $BOOSTLIBDIR/libboost_system*.a* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^lib\(boost_system.*\)\.so.*$;\1;' -e 's;^lib\(boost_system.*\)\.a*$;\1;'` ; do
+ for libextension in `ls -r $BOOSTLIBDIR/libboost_system* 2>/dev/null | sed 's,.*/lib,,' | sed 's,\..*,,'` ; do
ax_lib=${libextension}
AC_CHECK_LIB($ax_lib, exit,
[BOOST_SYSTEM_LIB="-l$ax_lib"; AC_SUBST(BOOST_SYSTEM_LIB) link_system="yes"; break],
[link_system="no"])
done
if test "x$link_system" != "xyes"; then
- for libextension in `ls $BOOSTLIBDIR/boost_system*.{dll,a}* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^\(boost_system.*\)\.dll.*$;\1;' -e 's;^\(boost_system.*\)\.a*$;\1;'` ; do
+ for libextension in `ls -r $BOOSTLIBDIR/boost_system* 2>/dev/null | sed 's,.*/,,' | sed -e 's,\..*,,'` ; do
ax_lib=${libextension}
AC_CHECK_LIB($ax_lib, exit,
[BOOST_SYSTEM_LIB="-l$ax_lib"; AC_SUBST(BOOST_SYSTEM_LIB) link_system="yes"; break],
diff --git a/src/m4/ax_boost_thread.m4 b/src/m4/ax_boost_thread.m4
index d9cd8a1d1d..79e12cdb4e 100644
--- a/src/m4/ax_boost_thread.m4
+++ b/src/m4/ax_boost_thread.m4
@@ -30,7 +30,7 @@
# and this notice are preserved. This file is offered as-is, without any
# warranty.
-#serial 22
+#serial 27
AC_DEFUN([AX_BOOST_THREAD],
[
@@ -68,17 +68,13 @@ AC_DEFUN([AX_BOOST_THREAD],
[AC_LANG_PUSH([C++])
CXXFLAGS_SAVE=$CXXFLAGS
- # let us handle platform dependent issues in
- # configure.ac
-
- # if test "x$build_os" = "xsolaris" ; then
- # CXXFLAGS="-pthreads $CXXFLAGS"
- # elif test "x$build_os" = "xming32" ; then
- # CXXFLAGS="-mthreads $CXXFLAGS"
- # else
- # CXXFLAGS="-pthread $CXXFLAGS"
- # fi
-
+ if test "x$host_os" = "xsolaris" ; then
+ CXXFLAGS="-pthreads $CXXFLAGS"
+ elif test "x$host_os" = "xmingw32" ; then
+ CXXFLAGS="-mthreads $CXXFLAGS"
+ else
+ CXXFLAGS="-pthread $CXXFLAGS"
+ fi
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[@%:@include <boost/thread/thread.hpp>]],
[[boost::thread_group thrds;
return 0;]])],
@@ -87,13 +83,13 @@ AC_DEFUN([AX_BOOST_THREAD],
AC_LANG_POP([C++])
])
if test "x$ax_cv_boost_thread" = "xyes"; then
- # if test "x$build_os" = "xsolaris" ; then
- # BOOST_CPPFLAGS="-pthreads $BOOST_CPPFLAGS"
- # elif test "x$build_os" = "xming32" ; then
- # BOOST_CPPFLAGS="-mthreads $BOOST_CPPFLAGS"
- # else
- # BOOST_CPPFLAGS="-pthread $BOOST_CPPFLAGS"
- # fi
+ if test "x$host_os" = "xsolaris" ; then
+ BOOST_CPPFLAGS="-pthreads $BOOST_CPPFLAGS"
+ elif test "x$host_os" = "xmingw32" ; then
+ BOOST_CPPFLAGS="-mthreads $BOOST_CPPFLAGS"
+ else
+ BOOST_CPPFLAGS="-pthread $BOOST_CPPFLAGS"
+ fi
AC_SUBST(BOOST_CPPFLAGS)
@@ -101,21 +97,21 @@ AC_DEFUN([AX_BOOST_THREAD],
BOOSTLIBDIR=`echo $BOOST_LDFLAGS | sed -e 's/@<:@^\/@:>@*//'`
LDFLAGS_SAVE=$LDFLAGS
- # case "x$build_os" in
- # *bsd* )
- # LDFLAGS="-pthread $LDFLAGS"
- # break;
- # ;;
- # esac
+ case "x$host_os" in
+ *bsd* )
+ LDFLAGS="-pthread $LDFLAGS"
+ break;
+ ;;
+ esac
if test "x$ax_boost_user_thread_lib" = "x"; then
- for libextension in `ls $BOOSTLIBDIR/libboost_thread*.so* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^lib\(boost_thread.*\)\.so.*$;\1;'` `ls $BOOSTLIBDIR/libboost_thread*.a* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^lib\(boost_thread.*\)\.a*$;\1;'`; do
+ for libextension in `ls -r $BOOSTLIBDIR/libboost_thread* 2>/dev/null | sed 's,.*/lib,,' | sed 's,\..*,,'`; do
ax_lib=${libextension}
AC_CHECK_LIB($ax_lib, exit,
[BOOST_THREAD_LIB="-l$ax_lib"; AC_SUBST(BOOST_THREAD_LIB) link_thread="yes"; break],
[link_thread="no"])
done
if test "x$link_thread" != "xyes"; then
- for libextension in `ls $BOOSTLIBDIR/boost_thread*.dll* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^\(boost_thread.*\)\.dll.*$;\1;'` `ls $BOOSTLIBDIR/boost_thread*.a* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^\(boost_thread.*\)\.a*$;\1;'` ; do
+ for libextension in `ls -r $BOOSTLIBDIR/boost_thread* 2>/dev/null | sed 's,.*/,,' | sed 's,\..*,,'`; do
ax_lib=${libextension}
AC_CHECK_LIB($ax_lib, exit,
[BOOST_THREAD_LIB="-l$ax_lib"; AC_SUBST(BOOST_THREAD_LIB) link_thread="yes"; break],
@@ -134,17 +130,17 @@ AC_DEFUN([AX_BOOST_THREAD],
if test "x$ax_lib" = "x"; then
AC_MSG_ERROR(Could not find a version of the library!)
fi
- # if test "x$link_thread" = "xno"; then
- # AC_MSG_ERROR(Could not link against $ax_lib !)
- # else
- # case "x$build_os" in
- # *bsd* )
- # BOOST_LDFLAGS="-pthread $BOOST_LDFLAGS"
- # break;
- # ;;
- # esac
+ if test "x$link_thread" = "xno"; then
+ AC_MSG_ERROR(Could not link against $ax_lib !)
+ else
+ case "x$host_os" in
+ *bsd* )
+ BOOST_LDFLAGS="-pthread $BOOST_LDFLAGS"
+ break;
+ ;;
+ esac
- # fi
+ fi
fi
CPPFLAGS="$CPPFLAGS_SAVED"
diff --git a/src/m4/ax_pthread.m4 b/src/m4/ax_pthread.m4
index 6d400ed4e8..d383ad5c6d 100644
--- a/src/m4/ax_pthread.m4
+++ b/src/m4/ax_pthread.m4
@@ -82,7 +82,7 @@
# modified version of the Autoconf Macro, you may extend this special
# exception to the GPL to apply to your modified version as well.
-#serial 20
+#serial 21
AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD])
AC_DEFUN([AX_PTHREAD], [
@@ -103,8 +103,8 @@ if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then
save_LIBS="$LIBS"
LIBS="$PTHREAD_LIBS $LIBS"
AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS])
- AC_TRY_LINK_FUNC(pthread_join, ax_pthread_ok=yes)
- AC_MSG_RESULT($ax_pthread_ok)
+ AC_TRY_LINK_FUNC([pthread_join], [ax_pthread_ok=yes])
+ AC_MSG_RESULT([$ax_pthread_ok])
if test x"$ax_pthread_ok" = xno; then
PTHREAD_LIBS=""
PTHREAD_CFLAGS=""
@@ -164,6 +164,20 @@ case ${host_os} in
;;
esac
+# Clang doesn't consider unrecognized options an error unless we specify
+# -Werror. We throw in some extra Clang-specific options to ensure that
+# this doesn't happen for GCC, which also accepts -Werror.
+
+AC_MSG_CHECKING([if compiler needs -Werror to reject unknown flags])
+save_CFLAGS="$CFLAGS"
+ax_pthread_extra_flags="-Werror"
+CFLAGS="$CFLAGS $ax_pthread_extra_flags -Wunknown-warning-option -Wsizeof-array-argument"
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([int foo(void);],[foo()])],
+ [AC_MSG_RESULT([yes])],
+ [ax_pthread_extra_flags=
+ AC_MSG_RESULT([no])])
+CFLAGS="$save_CFLAGS"
+
if test x"$ax_pthread_ok" = xno; then
for flag in $ax_pthread_flags; do
@@ -178,7 +192,7 @@ for flag in $ax_pthread_flags; do
;;
pthread-config)
- AC_CHECK_PROG(ax_pthread_config, pthread-config, yes, no)
+ AC_CHECK_PROG([ax_pthread_config], [pthread-config], [yes], [no])
if test x"$ax_pthread_config" = xno; then continue; fi
PTHREAD_CFLAGS="`pthread-config --cflags`"
PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`"
@@ -193,7 +207,7 @@ for flag in $ax_pthread_flags; do
save_LIBS="$LIBS"
save_CFLAGS="$CFLAGS"
LIBS="$PTHREAD_LIBS $LIBS"
- CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+ CFLAGS="$CFLAGS $PTHREAD_CFLAGS $ax_pthread_extra_flags"
# Check for various functions. We must include pthread.h,
# since some functions may be macros. (On the Sequent, we
@@ -219,7 +233,7 @@ for flag in $ax_pthread_flags; do
LIBS="$save_LIBS"
CFLAGS="$save_CFLAGS"
- AC_MSG_RESULT($ax_pthread_ok)
+ AC_MSG_RESULT([$ax_pthread_ok])
if test "x$ax_pthread_ok" = xyes; then
break;
fi
@@ -245,9 +259,9 @@ if test "x$ax_pthread_ok" = xyes; then
[attr_name=$attr; break],
[])
done
- AC_MSG_RESULT($attr_name)
+ AC_MSG_RESULT([$attr_name])
if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then
- AC_DEFINE_UNQUOTED(PTHREAD_CREATE_JOINABLE, $attr_name,
+ AC_DEFINE_UNQUOTED([PTHREAD_CREATE_JOINABLE], [$attr_name],
[Define to necessary symbol if this constant
uses a non-standard name on your system.])
fi
@@ -261,24 +275,25 @@ if test "x$ax_pthread_ok" = xyes; then
if test "$GCC" = "yes"; then
flag="-D_REENTRANT"
else
+ # TODO: What about Clang on Solaris?
flag="-mt -D_REENTRANT"
fi
;;
esac
- AC_MSG_RESULT(${flag})
+ AC_MSG_RESULT([$flag])
if test "x$flag" != xno; then
PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS"
fi
AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT],
- ax_cv_PTHREAD_PRIO_INHERIT, [
- AC_LINK_IFELSE([
- AC_LANG_PROGRAM([[#include <pthread.h>]], [[int i = PTHREAD_PRIO_INHERIT;]])],
+ [ax_cv_PTHREAD_PRIO_INHERIT], [
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <pthread.h>]],
+ [[int i = PTHREAD_PRIO_INHERIT;]])],
[ax_cv_PTHREAD_PRIO_INHERIT=yes],
[ax_cv_PTHREAD_PRIO_INHERIT=no])
])
AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes"],
- AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], 1, [Have PTHREAD_PRIO_INHERIT.]))
+ [AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], [1], [Have PTHREAD_PRIO_INHERIT.])])
LIBS="$save_LIBS"
CFLAGS="$save_CFLAGS"
@@ -301,13 +316,13 @@ fi
test -n "$PTHREAD_CC" || PTHREAD_CC="$CC"
-AC_SUBST(PTHREAD_LIBS)
-AC_SUBST(PTHREAD_CFLAGS)
-AC_SUBST(PTHREAD_CC)
+AC_SUBST([PTHREAD_LIBS])
+AC_SUBST([PTHREAD_CFLAGS])
+AC_SUBST([PTHREAD_CC])
# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
if test x"$ax_pthread_ok" = xyes; then
- ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1])
+ ifelse([$1],,[AC_DEFINE([HAVE_PTHREAD],[1],[Define if you have POSIX threads libraries and header files.])],[$1])
:
else
ax_pthread_ok=no
diff --git a/src/main.cpp b/src/main.cpp
index 15fc8a24c3..d130e9705e 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -19,7 +19,6 @@
#include <inttypes.h>
#include <sstream>
-#include <stdint.h>
#include <boost/algorithm/string/replace.hpp>
#include <boost/filesystem.hpp>
@@ -28,6 +27,10 @@
using namespace std;
using namespace boost;
+#if defined(NDEBUG)
+# error "Bitcoin cannot be compiled without assertions."
+#endif
+
//
// Global state
//
@@ -150,17 +153,66 @@ void SyncWithWallets(const uint256 &hash, const CTransaction &tx, const CBlock *
// Registration of network node signals.
//
-int static GetHeight()
+namespace {
+// Maintain validation-specific state about nodes, protected by cs_main, instead
+// by CNode's own locks. This simplifies asynchronous operation, where
+// processing of incoming data is done after the ProcessMessage call returns,
+// and we're no longer holding the node's locks.
+struct CNodeState {
+ int nMisbehavior;
+ bool fShouldBan;
+ std::string name;
+
+ CNodeState() {
+ nMisbehavior = 0;
+ fShouldBan = false;
+ }
+};
+
+map<NodeId, CNodeState> mapNodeState;
+
+// Requires cs_main.
+CNodeState *State(NodeId pnode) {
+ map<NodeId, CNodeState>::iterator it = mapNodeState.find(pnode);
+ if (it == mapNodeState.end())
+ return NULL;
+ return &it->second;
+}
+
+int GetHeight()
{
LOCK(cs_main);
return chainActive.Height();
}
+void InitializeNode(NodeId nodeid, const CNode *pnode) {
+ LOCK(cs_main);
+ CNodeState &state = mapNodeState.insert(std::make_pair(nodeid, CNodeState())).first->second;
+ state.name = pnode->addrName;
+}
+
+void FinalizeNode(NodeId nodeid) {
+ LOCK(cs_main);
+ mapNodeState.erase(nodeid);
+}
+}
+
+bool GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats) {
+ LOCK(cs_main);
+ CNodeState *state = State(nodeid);
+ if (state == NULL)
+ return false;
+ stats.nMisbehavior = state->nMisbehavior;
+ return true;
+}
+
void RegisterNodeSignals(CNodeSignals& nodeSignals)
{
nodeSignals.GetHeight.connect(&GetHeight);
nodeSignals.ProcessMessages.connect(&ProcessMessages);
nodeSignals.SendMessages.connect(&SendMessages);
+ nodeSignals.InitializeNode.connect(&InitializeNode);
+ nodeSignals.FinalizeNode.connect(&FinalizeNode);
}
void UnregisterNodeSignals(CNodeSignals& nodeSignals)
@@ -168,6 +220,8 @@ void UnregisterNodeSignals(CNodeSignals& nodeSignals)
nodeSignals.GetHeight.disconnect(&GetHeight);
nodeSignals.ProcessMessages.disconnect(&ProcessMessages);
nodeSignals.SendMessages.disconnect(&SendMessages);
+ nodeSignals.InitializeNode.disconnect(&InitializeNode);
+ nodeSignals.FinalizeNode.disconnect(&FinalizeNode);
}
//////////////////////////////////////////////////////////////////////////////
@@ -380,21 +434,6 @@ bool IsFinalTx(const CTransaction &tx, int nBlockHeight, int64_t nBlockTime)
return true;
}
-/** Amount of bitcoins spent by the transaction.
- @return sum of all outputs (note: does not include fees)
- */
-int64_t GetValueOut(const CTransaction& tx)
-{
- int64_t nValueOut = 0;
- BOOST_FOREACH(const CTxOut& txout, tx.vout)
- {
- nValueOut += txout.nValue;
- if (!MoneyRange(txout.nValue) || !MoneyRange(nValueOut))
- throw std::runtime_error("GetValueOut() : value out of range");
- }
- return nValueOut;
-}
-
//
// Check transaction inputs, and make sure any
// pay-to-script-hash transactions are evaluating IsStandard scripts
@@ -553,7 +592,7 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state)
REJECT_INVALID, "vout empty");
// Size limits
if (::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE)
- return state.DoS(100, error("CTransaction::CheckTransaction() : size limits failed"),
+ return state.DoS(100, error("CheckTransaction() : size limits failed"),
REJECT_INVALID, "oversize");
// Check for negative or overflow output values
@@ -568,7 +607,7 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state)
REJECT_INVALID, "vout too large");
nValueOut += txout.nValue;
if (!MoneyRange(nValueOut))
- return state.DoS(100, error("CTransaction::CheckTransaction() : txout total out of range"),
+ return state.DoS(100, error("CheckTransaction() : txout total out of range"),
REJECT_INVALID, "txout total too large");
}
@@ -577,7 +616,7 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state)
BOOST_FOREACH(const CTxIn& txin, tx.vin)
{
if (vInOutPoints.count(txin.prevout))
- return state.DoS(100, error("CTransaction::CheckTransaction() : duplicate inputs"),
+ return state.DoS(100, error("CheckTransaction() : duplicate inputs"),
REJECT_INVALID, "duplicate inputs");
vInOutPoints.insert(txin.prevout);
}
@@ -661,7 +700,6 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
return false;
// Check for conflicts with in-memory transactions
- CTransaction* ptxOld = NULL;
{
LOCK(pool.cs); // protect pool.mapNextTx
for (unsigned int i = 0; i < tx.vin.size(); i++)
@@ -671,22 +709,6 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
{
// Disable replacement feature for now
return false;
-
- // Allow replacing with a newer version of the same transaction
- if (i != 0)
- return false;
- ptxOld = pool.mapNextTx[outpoint].ptx;
- if (IsFinalTx(*ptxOld))
- return false;
- if (!tx.IsNewerThan(*ptxOld))
- return false;
- for (unsigned int i = 0; i < tx.vin.size(); i++)
- {
- COutPoint outpoint = tx.vin[i].prevout;
- if (!pool.mapNextTx.count(outpoint) || pool.mapNextTx[outpoint].ptx != ptxOld)
- return false;
- }
- break;
}
}
}
@@ -735,8 +757,13 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
// you should add code here to check that the transaction does a
// reasonable number of ECDSA signature verifications.
- int64_t nFees = view.GetValueIn(tx)-GetValueOut(tx);
- unsigned int nSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);
+ int64_t nValueIn = view.GetValueIn(tx);
+ int64_t nValueOut = tx.GetValueOut();
+ int64_t nFees = nValueIn-nValueOut;
+ double dPriority = view.GetPriority(tx, chainActive.Height());
+
+ CTxMemPoolEntry entry(tx, nFees, GetTime(), dPriority, chainActive.Height());
+ unsigned int nSize = entry.GetTxSize();
// Don't accept it if it can't get into a block
int64_t txMinFee = GetMinFee(tx, nSize, true, GMF_RELAY);
@@ -780,27 +807,12 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
{
return error("AcceptToMemoryPool: : ConnectInputs failed %s", hash.ToString().c_str());
}
+ // Store transaction in memory
+ pool.addUnchecked(hash, entry);
}
- // Store transaction in memory
- {
- if (ptxOld)
- {
- LogPrint("mempool", "AcceptToMemoryPool: : replacing tx %s with new version\n", ptxOld->GetHash().ToString().c_str());
- pool.remove(*ptxOld);
- }
- pool.addUnchecked(hash, tx);
- }
-
- ///// are we sure this is ok when loading transactions or restoring block txes
- // If updated, erase old tx from wallet
- if (ptxOld)
- g_signals.EraseTransaction(ptxOld->GetHash());
g_signals.SyncTransaction(hash, tx, NULL);
- LogPrint("mempool", "AcceptToMemoryPool: : accepted %s (poolsz %"PRIszu")\n",
- hash.ToString().c_str(),
- pool.mapTx.size());
return true;
}
@@ -1309,18 +1321,21 @@ void UpdateTime(CBlockHeader& block, const CBlockIndex* pindexPrev)
void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCache &inputs, CTxUndo &txundo, int nHeight, const uint256 &txhash)
{
+ bool ret;
// mark inputs spent
if (!tx.IsCoinBase()) {
BOOST_FOREACH(const CTxIn &txin, tx.vin) {
CCoins &coins = inputs.GetCoins(txin.prevout.hash);
CTxInUndo undo;
- assert(coins.Spend(txin.prevout, undo));
+ ret = coins.Spend(txin.prevout, undo);
+ assert(ret);
txundo.vprevout.push_back(undo);
}
}
// add outputs
- assert(inputs.SetCoins(txhash, CCoins(tx, nHeight)));
+ ret = inputs.SetCoins(txhash, CCoins(tx, nHeight));
+ assert(ret);
}
bool CScriptCheck::operator()() const {
@@ -1374,12 +1389,12 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, CCoinsViewCach
}
- if (nValueIn < GetValueOut(tx))
+ if (nValueIn < tx.GetValueOut())
return state.DoS(100, error("CheckInputs() : %s value in < value out", tx.GetHash().ToString().c_str()),
REJECT_INVALID, "in < out");
// Tally transaction fees
- int64_t nTxFee = nValueIn - GetValueOut(tx);
+ int64_t nTxFee = nValueIn - tx.GetValueOut();
if (nTxFee < 0)
return state.DoS(100, error("CheckInputs() : %s nTxFee < 0", tx.GetHash().ToString().c_str()),
REJECT_INVALID, "fee < 0");
@@ -1632,7 +1647,7 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C
REJECT_INVALID, "too many sigops");
}
- nFees += view.GetValueIn(tx)-GetValueOut(tx);
+ nFees += view.GetValueIn(tx)-tx.GetValueOut();
std::vector<CScriptCheck> vChecks;
if (!CheckInputs(tx, state, view, fScriptChecks, flags, nScriptCheckThreads ? &vChecks : NULL))
@@ -1652,10 +1667,10 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C
if (fBenchmark)
LogPrintf("- Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin)\n", (unsigned)block.vtx.size(), 0.001 * nTime, 0.001 * nTime / block.vtx.size(), nInputs <= 1 ? 0 : 0.001 * nTime / (nInputs-1));
- if (GetValueOut(block.vtx[0]) > GetBlockValue(pindex->nHeight, nFees))
+ if (block.vtx[0].GetValueOut() > GetBlockValue(pindex->nHeight, nFees))
return state.DoS(100,
error("ConnectBlock() : coinbase pays too much (actual=%"PRId64" vs limit=%"PRId64")",
- GetValueOut(block.vtx[0]), GetBlockValue(pindex->nHeight, nFees)),
+ block.vtx[0].GetValueOut(), GetBlockValue(pindex->nHeight, nFees)),
REJECT_INVALID, "coinbase too large");
if (!control.Wait())
@@ -1694,7 +1709,9 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C
return state.Abort(_("Failed to write transaction index"));
// add this block to the view's block chain
- assert(view.SetBestBlock(pindex->GetBlockHash()));
+ bool ret;
+ ret = view.SetBestBlock(pindex->GetBlockHash());
+ assert(ret);
// Watch for transactions paying to me
for (unsigned int i = 0; i < block.vtx.size(); i++)
@@ -1789,7 +1806,9 @@ bool SetBestChain(CValidationState &state, CBlockIndex* pindexNew)
// Flush changes to global coin state
int64_t nStart = GetTimeMicros();
int nModified = view.GetCacheSize();
- assert(view.Flush());
+ bool ret;
+ ret = view.Flush();
+ assert(ret);
int64_t nTime = GetTimeMicros() - nStart;
if (fBenchmark)
LogPrintf("- Flush %i transactions: %.2fms (%.4fms/tx)\n", nModified, 0.001 * nTime, 0.001 * nTime / nModified);
@@ -2219,6 +2238,8 @@ void PushGetBlocks(CNode* pnode, CBlockIndex* pindexBegin, uint256 hashEnd)
bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBlockPos *dbp)
{
+ AssertLockHeld("cs_main");
+
// Check for duplicate
uint256 hash = pblock->GetHash();
if (mapBlockIndex.count(hash))
@@ -2945,6 +2966,23 @@ bool static AlreadyHave(const CInv& inv)
}
+void Misbehaving(NodeId pnode, int howmuch)
+{
+ if (howmuch == 0)
+ return;
+
+ CNodeState *state = State(pnode);
+ if (state == NULL)
+ return;
+
+ state->nMisbehavior += howmuch;
+ if (state->nMisbehavior >= GetArg("-banscore", 100))
+ {
+ LogPrintf("Misbehaving: %s (%d -> %d) BAN THRESHOLD EXCEEDED\n", state->name.c_str(), state->nMisbehavior-howmuch, state->nMisbehavior);
+ state->fShouldBan = true;
+ } else
+ LogPrintf("Misbehaving: %s (%d -> %d)\n", state->name.c_str(), state->nMisbehavior-howmuch, state->nMisbehavior);
+}
void static ProcessGetData(CNode* pfrom)
{
@@ -3078,7 +3116,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
if (pfrom->nVersion != 0)
{
pfrom->PushMessage("reject", strCommand, REJECT_DUPLICATE, string("Duplicate version message"));
- pfrom->Misbehaving(1);
+ Misbehaving(pfrom->GetId(), 1);
return false;
}
@@ -3101,8 +3139,10 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
pfrom->nVersion = 300;
if (!vRecv.empty())
vRecv >> addrFrom >> nNonce;
- if (!vRecv.empty())
+ if (!vRecv.empty()) {
vRecv >> pfrom->strSubVer;
+ pfrom->cleanSubVer = SanitizeString(pfrom->strSubVer);
+ }
if (!vRecv.empty())
vRecv >> pfrom->nStartingHeight;
if (!vRecv.empty())
@@ -3169,7 +3209,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
pfrom->fSuccessfullyConnected = true;
- LogPrintf("receive version message: version %d, blocks=%d, us=%s, them=%s, peer=%s\n", pfrom->nVersion, pfrom->nStartingHeight, addrMe.ToString().c_str(), addrFrom.ToString().c_str(), pfrom->addr.ToString().c_str());
+ LogPrintf("receive version message: %s: version %d, blocks=%d, us=%s, them=%s, peer=%s\n", pfrom->cleanSubVer.c_str(), pfrom->nVersion, pfrom->nStartingHeight, addrMe.ToString().c_str(), addrFrom.ToString().c_str(), pfrom->addr.ToString().c_str());
AddTimeData(pfrom->addr, nTime);
@@ -3181,7 +3221,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
else if (pfrom->nVersion == 0)
{
// Must have a version message before anything else
- pfrom->Misbehaving(1);
+ Misbehaving(pfrom->GetId(), 1);
return false;
}
@@ -3202,7 +3242,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
return true;
if (vAddr.size() > 1000)
{
- pfrom->Misbehaving(20);
+ Misbehaving(pfrom->GetId(), 20);
return error("message addr size() = %"PRIszu"", vAddr.size());
}
@@ -3265,7 +3305,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
vRecv >> vInv;
if (vInv.size() > MAX_INV_SZ)
{
- pfrom->Misbehaving(20);
+ Misbehaving(pfrom->GetId(), 20);
return error("message inv size() = %"PRIszu"", vInv.size());
}
@@ -3316,7 +3356,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
vRecv >> vInv;
if (vInv.size() > MAX_INV_SZ)
{
- pfrom->Misbehaving(20);
+ Misbehaving(pfrom->GetId(), 20);
return error("message getdata size() = %"PRIszu"", vInv.size());
}
@@ -3428,6 +3468,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
vWorkQueue.push_back(inv.hash);
vEraseQueue.push_back(inv.hash);
+
+ LogPrint("mempool", "AcceptToMemoryPool: %s %s : accepted %s (poolsz %"PRIszu")\n",
+ pfrom->addr.ToString().c_str(), pfrom->cleanSubVer.c_str(),
+ tx.GetHash().ToString().c_str(),
+ mempool.mapTx.size());
+
// Recursively process any orphan transactions that depended on this one
for (unsigned int i = 0; i < vWorkQueue.size(); i++)
{
@@ -3476,11 +3522,14 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
}
int nDoS = 0;
if (state.IsInvalid(nDoS))
- {
+ {
+ LogPrint("mempool", "%s from %s %s was not accepted into the memory pool: %s\n", tx.GetHash().ToString().c_str(),
+ pfrom->addr.ToString().c_str(), pfrom->cleanSubVer.c_str(),
+ state.GetRejectReason().c_str());
pfrom->PushMessage("reject", strCommand, state.GetRejectCode(),
state.GetRejectReason(), inv.hash);
if (nDoS > 0)
- pfrom->Misbehaving(nDoS);
+ Misbehaving(pfrom->GetId(), nDoS);
}
}
@@ -3507,7 +3556,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
pfrom->PushMessage("reject", strCommand, state.GetRejectCode(),
state.GetRejectReason(), inv.hash);
if (nDoS > 0)
- pfrom->Misbehaving(nDoS);
+ Misbehaving(pfrom->GetId(), nDoS);
}
}
@@ -3613,7 +3662,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
if (!(sProblem.empty())) {
LogPrint("net", "pong %s %s: %s, %"PRIx64" expected, %"PRIx64" received, %"PRIszu" bytes\n",
pfrom->addr.ToString().c_str(),
- pfrom->strSubVer.c_str(),
+ pfrom->cleanSubVer.c_str(),
sProblem.c_str(),
pfrom->nPingNonceSent,
nonce,
@@ -3650,7 +3699,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
// This isn't a Misbehaving(100) (immediate ban) because the
// peer might be an older or different implementation with
// a different signature key, etc.
- pfrom->Misbehaving(10);
+ Misbehaving(pfrom->GetId(), 10);
}
}
}
@@ -3663,7 +3712,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
if (!filter.IsWithinSizeConstraints())
// There is no excuse for sending a too-large filter
- pfrom->Misbehaving(100);
+ Misbehaving(pfrom->GetId(), 100);
else
{
LOCK(pfrom->cs_filter);
@@ -3684,13 +3733,13 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
// and thus, the maximum size any matched object can have) in a filteradd message
if (vData.size() > MAX_SCRIPT_ELEMENT_SIZE)
{
- pfrom->Misbehaving(100);
+ Misbehaving(pfrom->GetId(), 100);
} else {
LOCK(pfrom->cs_filter);
if (pfrom->pfilter)
pfrom->pfilter->insert(vData);
else
- pfrom->Misbehaving(100);
+ Misbehaving(pfrom->GetId(), 100);
}
}
@@ -3955,6 +4004,16 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
if (!lockMain)
return true;
+ if (State(pto->GetId())->fShouldBan) {
+ if (pto->addr.IsLocal())
+ LogPrintf("Warning: not banning local node %s!\n", pto->addr.ToString().c_str());
+ else {
+ pto->fDisconnect = true;
+ CNode::Ban(pto->addr);
+ }
+ State(pto->GetId())->fShouldBan = false;
+ }
+
// Start block sync
if (pto->fStartSync && !fImporting && !fReindex) {
pto->fStartSync = false;
diff --git a/src/main.h b/src/main.h
index cf803ae25e..c52f37cc87 100644
--- a/src/main.h
+++ b/src/main.h
@@ -49,9 +49,6 @@ static const unsigned int MAX_BLOCKFILE_SIZE = 0x8000000; // 128 MiB
static const unsigned int BLOCKFILE_CHUNK_SIZE = 0x1000000; // 16 MiB
/** The pre-allocation chunk size for rev?????.dat files (since 0.8) */
static const unsigned int UNDOFILE_CHUNK_SIZE = 0x100000; // 1 MiB
-/** No amount larger than this (in satoshi) is valid */
-static const int64_t MAX_MONEY = 21000000 * COIN;
-inline bool MoneyRange(int64_t nValue) { return (nValue >= 0 && nValue <= MAX_MONEY); }
/** Coinbase transaction outputs can only be spent after this number of new blocks (network rule) */
static const int COINBASE_MATURITY = 100;
/** Threshold for nLockTime: below this value it is interpreted as block number, otherwise as UNIX timestamp. */
@@ -113,6 +110,7 @@ class CTxUndo;
class CScriptCheck;
class CValidationState;
class CWalletInterface;
+struct CNodeStateStats;
struct CBlockTemplate;
@@ -185,6 +183,8 @@ CBlockIndex * InsertBlockIndex(uint256 hash);
bool VerifySignature(const CCoins& txFrom, const CTransaction& txTo, unsigned int nIn, unsigned int flags, int nHashType);
/** Abort with a message */
bool AbortNode(const std::string &msg);
+/** Get statistics from node state */
+bool GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats);
/** (try to) add transaction to memory pool **/
bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree,
@@ -197,6 +197,10 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
+struct CNodeStateStats {
+ int nMisbehavior;
+};
+
struct CDiskBlockPos
{
int nFile;
@@ -320,11 +324,6 @@ bool IsStandardTx(const CTransaction& tx, std::string& reason);
bool IsFinalTx(const CTransaction &tx, int nBlockHeight = 0, int64_t nBlockTime = 0);
-/** Amount of bitcoins spent by the transaction.
- @return sum of all outputs (note: does not include fees)
- */
-int64_t GetValueOut(const CTransaction& tx);
-
/** Undo information for a CBlock */
class CBlockUndo
{
@@ -937,7 +936,7 @@ private:
unsigned char chRejectCode;
bool corruptionPossible;
public:
- CValidationState() : mode(MODE_VALID), nDoS(0) {}
+ CValidationState() : mode(MODE_VALID), nDoS(0), corruptionPossible(false) {}
bool DoS(int level, bool ret = false,
unsigned char chRejectCodeIn=0, std::string strRejectReasonIn="",
bool corruptionIn=false) {
diff --git a/src/miner.cpp b/src/miner.cpp
index 397c95c624..ecc40ac708 100644
--- a/src/miner.cpp
+++ b/src/miner.cpp
@@ -10,8 +10,6 @@
#include "net.h"
#include "wallet.h"
-#include <stdint.h>
-
double dHashesPerSec = 0.0;
int64_t nHPSTimerStart = 0;
@@ -95,12 +93,12 @@ unsigned int static ScanHash_CryptoPP(char* pmidstate, char* pdata, char* phash1
class COrphan
{
public:
- CTransaction* ptx;
+ const CTransaction* ptx;
set<uint256> setDependsOn;
double dPriority;
double dFeePerKb;
- COrphan(CTransaction* ptxIn)
+ COrphan(const CTransaction* ptxIn)
{
ptx = ptxIn;
dPriority = dFeePerKb = 0;
@@ -120,7 +118,7 @@ uint64_t nLastBlockTx = 0;
uint64_t nLastBlockSize = 0;
// We want to sort transactions by priority and fee, so:
-typedef boost::tuple<double, double, CTransaction*> TxPriority;
+typedef boost::tuple<double, double, const CTransaction*> TxPriority;
class TxPriorityCompare
{
bool byFee;
@@ -193,9 +191,10 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
// This vector will be sorted into a priority queue:
vector<TxPriority> vecPriority;
vecPriority.reserve(mempool.mapTx.size());
- for (map<uint256, CTransaction>::iterator mi = mempool.mapTx.begin(); mi != mempool.mapTx.end(); ++mi)
+ for (map<uint256, CTxMemPoolEntry>::iterator mi = mempool.mapTx.begin();
+ mi != mempool.mapTx.end(); ++mi)
{
- CTransaction& tx = (*mi).second;
+ const CTransaction& tx = mi->second.GetTx();
if (tx.IsCoinBase() || !IsFinalTx(tx))
continue;
@@ -230,7 +229,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
}
mapDependers[txin.prevout.hash].push_back(porphan);
porphan->setDependsOn.insert(txin.prevout.hash);
- nTotalIn += mempool.mapTx[txin.prevout.hash].vout[txin.prevout.n].nValue;
+ nTotalIn += mempool.mapTx[txin.prevout.hash].GetTx().vout[txin.prevout.n].nValue;
continue;
}
const CCoins &coins = view.GetCoins(txin.prevout.hash);
@@ -246,24 +245,12 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
// Priority is sum(valuein * age) / modified_txsize
unsigned int nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);
- unsigned int nTxSizeMod = nTxSize;
- // In order to avoid disincentivizing cleaning up the UTXO set we don't count
- // the constant overhead for each txin and up to 110 bytes of scriptSig (which
- // is enough to cover a compressed pubkey p2sh redemption) for priority.
- // Providing any more cleanup incentive than making additional inputs free would
- // risk encouraging people to create junk outputs to redeem later.
- BOOST_FOREACH(const CTxIn& txin, tx.vin)
- {
- unsigned int offset = 41U + min(110U, (unsigned int)txin.scriptSig.size());
- if (nTxSizeMod > offset)
- nTxSizeMod -= offset;
- }
- dPriority /= nTxSizeMod;
+ dPriority = tx.ComputePriority(dPriority, nTxSize);
// This is a more accurate fee-per-kilobyte than is used by the client code, because the
// client code rounds up the size to the nearest 1K. That's good, because it gives an
// incentive to create smaller transactions.
- double dFeePerKb = double(nTotalIn-GetValueOut(tx)) / (double(nTxSize)/1000.0);
+ double dFeePerKb = double(nTotalIn-tx.GetValueOut()) / (double(nTxSize)/1000.0);
if (porphan)
{
@@ -271,7 +258,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
porphan->dFeePerKb = dFeePerKb;
}
else
- vecPriority.push_back(TxPriority(dPriority, dFeePerKb, &(*mi).second));
+ vecPriority.push_back(TxPriority(dPriority, dFeePerKb, &mi->second.GetTx()));
}
// Collect transactions into block
@@ -288,7 +275,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
// Take highest priority transaction off the priority queue:
double dPriority = vecPriority.front().get<0>();
double dFeePerKb = vecPriority.front().get<1>();
- CTransaction& tx = *(vecPriority.front().get<2>());
+ const CTransaction& tx = *(vecPriority.front().get<2>());
std::pop_heap(vecPriority.begin(), vecPriority.end(), comparer);
vecPriority.pop_back();
@@ -320,7 +307,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
if (!view.HaveInputs(tx))
continue;
- int64_t nTxFees = view.GetValueIn(tx)-GetValueOut(tx);
+ int64_t nTxFees = view.GetValueIn(tx)-tx.GetValueOut();
nTxSigOps += GetP2SHSigOpCount(tx, view);
if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS)
@@ -652,11 +639,10 @@ void static BitcoinMiner(CWallet *pwallet)
}
}
-void GenerateBitcoins(bool fGenerate, CWallet* pwallet)
+void GenerateBitcoins(bool fGenerate, CWallet* pwallet, int nThreads)
{
static boost::thread_group* minerThreads = NULL;
- int nThreads = GetArg("-genproclimit", -1);
if (nThreads < 0) {
if (Params().NetworkID() == CChainParams::REGTEST)
nThreads = 1;
diff --git a/src/miner.h b/src/miner.h
index 4879f55d51..26151f6cd5 100644
--- a/src/miner.h
+++ b/src/miner.h
@@ -16,7 +16,7 @@ class CScript;
class CWallet;
/** Run the miner threads */
-void GenerateBitcoins(bool fGenerate, CWallet* pwallet);
+void GenerateBitcoins(bool fGenerate, CWallet* pwallet, int nThreads);
/** Generate a new block, without valid proof-of-work */
CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn);
CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey);
diff --git a/src/net.cpp b/src/net.cpp
index 59982b4066..6ae749c657 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -15,9 +15,6 @@
#include "db.h"
#include "ui_interface.h"
-#include <inttypes.h>
-#include <stdint.h>
-
#ifdef WIN32
#include <string.h>
#else
@@ -83,6 +80,9 @@ CCriticalSection cs_setservAddNodeAddresses;
vector<std::string> vAddedNodes;
CCriticalSection cs_vAddedNodes;
+NodeId nLastNodeId = 0;
+CCriticalSection cs_nLastNodeId;
+
static CSemaphore *semOutbound = NULL;
// Signals for message handling
@@ -584,45 +584,30 @@ bool CNode::IsBanned(CNetAddr ip)
return fResult;
}
-bool CNode::Misbehaving(int howmuch)
-{
- if (addr.IsLocal())
+bool CNode::Ban(const CNetAddr &addr) {
+ int64_t banTime = GetTime()+GetArg("-bantime", 60*60*24); // Default 24-hour ban
{
- LogPrintf("Warning: Local node %s misbehaving (delta: %d)!\n", addrName.c_str(), howmuch);
- return false;
+ LOCK(cs_setBanned);
+ if (setBanned[addr] < banTime)
+ setBanned[addr] = banTime;
}
-
- nMisbehavior += howmuch;
- if (nMisbehavior >= GetArg("-banscore", 100))
- {
- int64_t banTime = GetTime()+GetArg("-bantime", 60*60*24); // Default 24-hour ban
- LogPrintf("Misbehaving: %s (%d -> %d) DISCONNECTING\n", addr.ToString().c_str(), nMisbehavior-howmuch, nMisbehavior);
- {
- LOCK(cs_setBanned);
- if (setBanned[addr] < banTime)
- setBanned[addr] = banTime;
- }
- CloseSocketDisconnect();
- return true;
- } else
- LogPrintf("Misbehaving: %s (%d -> %d)\n", addr.ToString().c_str(), nMisbehavior-howmuch, nMisbehavior);
- return false;
+ return true;
}
#undef X
#define X(name) stats.name = name
void CNode::copyStats(CNodeStats &stats)
{
+ stats.nodeid = this->GetId();
X(nServices);
X(nLastSend);
X(nLastRecv);
X(nTimeConnected);
X(addrName);
X(nVersion);
- X(strSubVer);
+ X(cleanSubVer);
X(fInbound);
X(nStartingHeight);
- X(nMisbehavior);
X(nSendBytes);
X(nRecvBytes);
stats.fSyncNode = (this == pnodeSync);
@@ -1693,7 +1678,7 @@ bool BindListenPort(const CService &addrBind, string& strError)
return true;
}
-void static Discover()
+void static Discover(boost::thread_group& threadGroup)
{
if (!fDiscover)
return;
@@ -1746,7 +1731,7 @@ void static Discover()
// Don't use external IPv4 discovery, when -onlynet="IPv6"
if (!IsLimited(NET_IPV4))
- boost::thread(boost::bind(&TraceThread<void (*)()>, "ext-ip", &ThreadGetMyExternalIP));
+ threadGroup.create_thread(boost::bind(&TraceThread<void (*)()>, "ext-ip", &ThreadGetMyExternalIP));
}
void StartNode(boost::thread_group& threadGroup)
@@ -1760,7 +1745,7 @@ void StartNode(boost::thread_group& threadGroup)
if (pnodeLocalHost == NULL)
pnodeLocalHost = new CNode(INVALID_SOCKET, CAddress(CService("127.0.0.1", 0), nLocalServices));
- Discover();
+ Discover(threadGroup);
//
// Start threads
@@ -1945,3 +1930,103 @@ void CNode::Fuzz(int nChance)
// (more changes exponentially less likely):
Fuzz(2);
}
+
+//
+// CAddrDB
+//
+
+CAddrDB::CAddrDB()
+{
+ pathAddr = GetDataDir() / "peers.dat";
+}
+
+bool CAddrDB::Write(const CAddrMan& addr)
+{
+ // Generate random temporary filename
+ unsigned short randv = 0;
+ RAND_bytes((unsigned char *)&randv, sizeof(randv));
+ std::string tmpfn = strprintf("peers.dat.%04x", randv);
+
+ // serialize addresses, checksum data up to that point, then append csum
+ CDataStream ssPeers(SER_DISK, CLIENT_VERSION);
+ ssPeers << FLATDATA(Params().MessageStart());
+ ssPeers << addr;
+ uint256 hash = Hash(ssPeers.begin(), ssPeers.end());
+ ssPeers << hash;
+
+ // open temp output file, and associate with CAutoFile
+ boost::filesystem::path pathTmp = GetDataDir() / tmpfn;
+ FILE *file = fopen(pathTmp.string().c_str(), "wb");
+ CAutoFile fileout = CAutoFile(file, SER_DISK, CLIENT_VERSION);
+ if (!fileout)
+ return error("CAddrman::Write() : open failed");
+
+ // Write and commit header, data
+ try {
+ fileout << ssPeers;
+ }
+ catch (std::exception &e) {
+ return error("CAddrman::Write() : I/O error");
+ }
+ FileCommit(fileout);
+ fileout.fclose();
+
+ // replace existing peers.dat, if any, with new peers.dat.XXXX
+ if (!RenameOver(pathTmp, pathAddr))
+ return error("CAddrman::Write() : Rename-into-place failed");
+
+ return true;
+}
+
+bool CAddrDB::Read(CAddrMan& addr)
+{
+ // open input file, and associate with CAutoFile
+ FILE *file = fopen(pathAddr.string().c_str(), "rb");
+ CAutoFile filein = CAutoFile(file, SER_DISK, CLIENT_VERSION);
+ if (!filein)
+ return error("CAddrman::Read() : open failed");
+
+ // use file size to size memory buffer
+ int fileSize = GetFilesize(filein);
+ int dataSize = fileSize - sizeof(uint256);
+ //Don't try to resize to a negative number if file is small
+ if ( dataSize < 0 ) dataSize = 0;
+ vector<unsigned char> vchData;
+ vchData.resize(dataSize);
+ uint256 hashIn;
+
+ // read data and checksum from file
+ try {
+ filein.read((char *)&vchData[0], dataSize);
+ filein >> hashIn;
+ }
+ catch (std::exception &e) {
+ return error("CAddrman::Read() 2 : I/O error or stream data corrupted");
+ }
+ filein.fclose();
+
+ CDataStream ssPeers(vchData, SER_DISK, CLIENT_VERSION);
+
+ // verify stored checksum matches input data
+ uint256 hashTmp = Hash(ssPeers.begin(), ssPeers.end());
+ if (hashIn != hashTmp)
+ return error("CAddrman::Read() : checksum mismatch; data corrupted");
+
+ unsigned char pchMsgTmp[4];
+ try {
+ // de-serialize file header (network specific magic number) and ..
+ ssPeers >> FLATDATA(pchMsgTmp);
+
+ // ... verify the network matches ours
+ if (memcmp(pchMsgTmp, Params().MessageStart(), sizeof(pchMsgTmp)))
+ return error("CAddrman::Read() : invalid network magic number");
+
+ // de-serialize address data into one CAddrMan object
+ ssPeers >> addr;
+ }
+ catch (std::exception &e) {
+ return error("CAddrman::Read() : I/O error or stream data corrupted");
+ }
+
+ return true;
+}
diff --git a/src/net.h b/src/net.h
index 278462a0bc..5835001739 100644
--- a/src/net.h
+++ b/src/net.h
@@ -57,14 +57,19 @@ void StartNode(boost::thread_group& threadGroup);
bool StopNode();
void SocketSendData(CNode *pnode);
+typedef int NodeId;
+
// Signals for message handling
struct CNodeSignals
{
boost::signals2::signal<int ()> GetHeight;
boost::signals2::signal<bool (CNode*)> ProcessMessages;
boost::signals2::signal<bool (CNode*, bool)> SendMessages;
+ boost::signals2::signal<void (NodeId, const CNode*)> InitializeNode;
+ boost::signals2::signal<void (NodeId)> FinalizeNode;
};
+
CNodeSignals& GetNodeSignals();
@@ -109,22 +114,23 @@ extern limitedmap<CInv, int64_t> mapAlreadyAskedFor;
extern std::vector<std::string> vAddedNodes;
extern CCriticalSection cs_vAddedNodes;
-
+extern NodeId nLastNodeId;
+extern CCriticalSection cs_nLastNodeId;
class CNodeStats
{
public:
+ NodeId nodeid;
uint64_t nServices;
int64_t nLastSend;
int64_t nLastRecv;
int64_t nTimeConnected;
std::string addrName;
int nVersion;
- std::string strSubVer;
+ std::string cleanSubVer;
bool fInbound;
int nStartingHeight;
- int nMisbehavior;
uint64_t nSendBytes;
uint64_t nRecvBytes;
bool fSyncNode;
@@ -203,7 +209,11 @@ public:
std::string addrName;
CService addrLocal;
int nVersion;
- std::string strSubVer;
+ // strSubVer is whatever byte array we read from the wire. However, this field is intended
+ // to be printed out, displayed to humans in various forms and so on. So we sanitize it and
+ // store the sanitized version in cleanSubVer. The original should be used when dealing with
+ // the network or wire types and the cleaned string used when displayed or logged.
+ std::string strSubVer, cleanSubVer;
bool fOneShot;
bool fClient;
bool fInbound;
@@ -219,13 +229,13 @@ public:
CCriticalSection cs_filter;
CBloomFilter* pfilter;
int nRefCount;
+ NodeId id;
protected:
// Denial-of-service detection/prevention
// Key is IP address, value is banned-until-time
static std::map<CNetAddr, int64_t> setBanned;
static CCriticalSection cs_setBanned;
- int nMisbehavior;
// Basic fuzz-testing
void Fuzz(int nChance); // modifies ssSend
@@ -285,7 +295,6 @@ public:
nStartingHeight = -1;
fStartSync = false;
fGetAddr = false;
- nMisbehavior = 0;
fRelayTxes = false;
setInventoryKnown.max_size(SendBufferSize() / 1000);
pfilter = new CBloomFilter();
@@ -294,9 +303,16 @@ public:
nPingUsecTime = 0;
fPingQueued = false;
+ {
+ LOCK(cs_nLastNodeId);
+ id = nLastNodeId++;
+ }
+
// Be shy and don't send version until we hear
if (hSocket != INVALID_SOCKET && !fInbound)
PushVersion();
+
+ GetNodeSignals().InitializeNode(GetId(), this);
}
~CNode()
@@ -308,6 +324,7 @@ public:
}
if (pfilter)
delete pfilter;
+ GetNodeSignals().FinalizeNode(GetId());
}
private:
@@ -322,6 +339,9 @@ private:
public:
+ NodeId GetId() const {
+ return id;
+ }
int GetRefCount()
{
@@ -669,7 +689,7 @@ public:
// new code.
static void ClearBanned(); // needed for unit testing
static bool IsBanned(CNetAddr ip);
- bool Misbehaving(int howmuch); // 1 == a little, 100 == a lot
+ static bool Ban(const CNetAddr &ip);
void copyStats(CNodeStats &stats);
// Network stats
@@ -686,4 +706,15 @@ class CTransaction;
void RelayTransaction(const CTransaction& tx, const uint256& hash);
void RelayTransaction(const CTransaction& tx, const uint256& hash, const CDataStream& ss);
+/** Access to the (IP) address database (peers.dat) */
+class CAddrDB
+{
+private:
+ boost::filesystem::path pathAddr;
+public:
+ CAddrDB();
+ bool Write(const CAddrMan& addr);
+ bool Read(CAddrMan& addr);
+};
+
#endif
diff --git a/src/netbase.cpp b/src/netbase.cpp
index 1392fa8233..37e1df9138 100644
--- a/src/netbase.cpp
+++ b/src/netbase.cpp
@@ -10,8 +10,6 @@
#include "uint256.h"
#include "util.h"
-#include <stdint.h>
-
#ifndef WIN32
#include <fcntl.h>
#endif
diff --git a/src/protocol.cpp b/src/protocol.cpp
index 798227581e..be835507ab 100644
--- a/src/protocol.cpp
+++ b/src/protocol.cpp
@@ -7,8 +7,6 @@
#include "util.h"
-#include <stdint.h>
-
#ifndef WIN32
# include <arpa/inet.h>
#endif
diff --git a/src/qt/Makefile.am b/src/qt/Makefile.am
index 91e4edc33b..434373da29 100644
--- a/src/qt/Makefile.am
+++ b/src/qt/Makefile.am
@@ -200,7 +200,7 @@ endif
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) \
+bitcoin_qt_LDADD = libbitcoinqt.a $(LIBBITCOIN_SERVER) $(LIBBITCOIN_WALLET) $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBLEVELDB) $(LIBMEMENV) \
$(BOOST_LIBS) $(QT_LIBS) $(QT_DBUS_LIBS) $(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS)
# forms/foo.h -> forms/ui_foo.h
diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp
index 57ce7da361..2b3bf3bfb5 100644
--- a/src/qt/bitcoin.cpp
+++ b/src/qt/bitcoin.cpp
@@ -53,7 +53,6 @@ static SplashScreen *splashref;
static bool ThreadSafeMessageBox(const std::string& message, const std::string& caption, unsigned int style)
{
- // Message from network thread
if(guiref)
{
bool modal = (style & CClientUIInterface::MODAL);
@@ -160,7 +159,7 @@ static void initTranslations(QTranslator &qtTranslatorBase, QTranslator &qtTrans
/* qDebug() message handler --> debug.log */
#if QT_VERSION < 0x050000
-void DebugMessageHandler(QtMsgType type, const char * msg)
+void DebugMessageHandler(QtMsgType type, const char *msg)
{
Q_UNUSED(type);
LogPrint("qt", "Bitcoin-Qt: %s\n", msg);
@@ -201,6 +200,13 @@ int main(int argc, char *argv[])
Q_INIT_RESOURCE(bitcoin);
QApplication app(argc, argv);
+#if QT_VERSION > 0x050100
+ // Generate high-dpi pixmaps
+ QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
+#endif
+#ifdef Q_OS_MAC
+ QApplication::setAttribute(Qt::AA_DontShowIconsInMenus);
+#endif
// Register meta types used for QMetaObject::invokeMethod
qRegisterMetaType< bool* >();
@@ -313,11 +319,12 @@ int main(int argc, char *argv[])
splash.finish(&window);
ClientModel clientModel(&optionsModel);
+ window.setClientModel(&clientModel);
+
WalletModel *walletModel = 0;
if(pwalletMain)
walletModel = new WalletModel(pwalletMain, &optionsModel);
- window.setClientModel(&clientModel);
if(walletModel)
{
window.addWallet("~Default", walletModel);
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index a44627690f..b1daba5cba 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -69,28 +69,32 @@ BitcoinGUI::BitcoinGUI(bool fIsTestnet, QWidget *parent) :
{
GUIUtil::restoreWindowGeometry("nWindow", QSize(850, 550), this);
-#ifndef Q_OS_MAC
if (!fIsTestnet)
{
setWindowTitle(tr("Bitcoin") + " - " + tr("Wallet"));
+#ifndef Q_OS_MAC
QApplication::setWindowIcon(QIcon(":icons/bitcoin"));
setWindowIcon(QIcon(":icons/bitcoin"));
+#else
+ MacDockIconHandler::instance()->setIcon(QIcon(":icons/bitcoin"));
+#endif
}
else
{
setWindowTitle(tr("Bitcoin") + " - " + tr("Wallet") + " " + tr("[testnet]"));
+#ifndef Q_OS_MAC
QApplication::setWindowIcon(QIcon(":icons/bitcoin_testnet"));
setWindowIcon(QIcon(":icons/bitcoin_testnet"));
- }
#else
- setUnifiedTitleAndToolBarOnMac(true);
- QApplication::setAttribute(Qt::AA_DontShowIconsInMenus);
-
- if (!fIsTestnet)
- MacDockIconHandler::instance()->setIcon(QIcon(":icons/bitcoin"));
- else
MacDockIconHandler::instance()->setIcon(QIcon(":icons/bitcoin_testnet"));
#endif
+ }
+
+#if defined(Q_OS_MAC) && QT_VERSION < 0x050000
+ // This property is not implemented in Qt 5. Setting it has no effect.
+ // A replacement API (QtMacUnifiedToolBar) is available in QtMacExtras.
+ setUnifiedTitleAndToolBarOnMac(true);
+#endif
// Create wallet frame and make it the central widget
walletFrame = new WalletFrame(this);
@@ -405,7 +409,7 @@ void BitcoinGUI::createTrayIcon(bool fIsTestnet)
trayIcon->show();
#endif
- notificator = new Notificator(QApplication::applicationName(), trayIcon);
+ notificator = new Notificator(QApplication::applicationName(), trayIcon, this);
}
void BitcoinGUI::createTrayIconMenu()
diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h
index dcc528f4fd..05e8412528 100644
--- a/src/qt/clientmodel.h
+++ b/src/qt/clientmodel.h
@@ -84,7 +84,7 @@ signals:
void alertsChanged(const QString &warnings);
void bytesChanged(quint64 totalBytesIn, quint64 totalBytesOut);
- //! Asynchronous message notification
+ //! Fired when a message should be reported to the user
void message(const QString &title, const QString &message, unsigned int style);
public slots:
diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp
index 4ecc040bfb..14e5b07133 100644
--- a/src/qt/coincontroldialog.cpp
+++ b/src/qt/coincontroldialog.cpp
@@ -590,7 +590,7 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
l4->setText(BitcoinUnits::formatWithUnit(nDisplayUnit, nAfterFee)); // After Fee
l5->setText(((nBytes > 0) ? "~" : "") + QString::number(nBytes)); // Bytes
l6->setText(sPriorityLabel); // Priority
- l7->setText((fLowOutput ? (fDust ? tr("DUST") : tr("yes")) : tr("no"))); // Low Output / Dust
+ l7->setText((fLowOutput ? (fDust ? tr("Dust") : tr("yes")) : tr("no"))); // Low Output / Dust
l8->setText(BitcoinUnits::formatWithUnit(nDisplayUnit, nChange)); // Change
// turn labels "red"
@@ -600,10 +600,25 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
l8->setStyleSheet((nChange > 0 && nChange < CENT) ? "color:red;" : ""); // Change < 0.01BTC
// tool tips
- l5->setToolTip(tr("This label turns red, if the transaction size is bigger than 1000 bytes.\n\n This means a fee of at least %1 per kb is required.\n\n Can vary +/- 1 Byte per input.").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, CTransaction::nMinTxFee)));
- l6->setToolTip(tr("Transactions with higher priority get more likely into a block.\n\nThis label turns red, if the priority is smaller than \"medium\".\n\n This means a fee of at least %1 per kb is required.").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, CTransaction::nMinTxFee)));
- l7->setToolTip(tr("This label turns red, if any recipient receives an amount smaller than %1.\n\n This means a fee of at least %2 is required. \n\n Amounts below 0.546 times the minimum relay fee are shown as DUST.").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, CENT)).arg(BitcoinUnits::formatWithUnit(nDisplayUnit, CTransaction::nMinTxFee)));
- l8->setToolTip(tr("This label turns red, if the change is smaller than %1.\n\n This means a fee of at least %2 is required.").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, CENT)).arg(BitcoinUnits::formatWithUnit(nDisplayUnit, CTransaction::nMinTxFee)));
+ QString toolTip1 = tr("This label turns red, if the transaction size is greater than 1000 bytes.") + "<br /><br />";
+ toolTip1 += tr("This means a fee of at least %1 per kB is required.").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, CTransaction::nMinTxFee)) + "<br /><br />";
+ toolTip1 += tr("Can vary +/- 1 byte per input.");
+
+ QString toolTip2 = tr("Transactions with higher priority are more likely to get included into a block.") + "<br /><br />";
+ toolTip2 += tr("This label turns red, if the priority is smaller than \"medium\"") + "<br /><br />";
+ toolTip2 += tr("This means a fee of at least %1 per kB is required.").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, CTransaction::nMinTxFee));
+
+ QString toolTip3 = tr("This label turns red, if any recipient receives an amount smaller than %1.").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, CENT)) + "<br /><br />";
+ toolTip3 += tr("This means a fee of at least %1 is required.").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, CTransaction::nMinTxFee)) + "<br /><br />";
+ toolTip3 += tr("Amounts below 0.546 times the minimum relay fee are shown as dust.");
+
+ QString toolTip4 = tr("This label turns red, if the change is smaller than %1.").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, CENT)) + "<br /><br />";
+ toolTip4 += tr("This means a fee of at least %1 is required.").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, CTransaction::nMinTxFee));
+
+ l5->setToolTip(toolTip1);
+ l6->setToolTip(toolTip2);
+ l7->setToolTip(toolTip3);
+ l8->setToolTip(toolTip4);
dialog->findChild<QLabel *>("labelCoinControlBytesText") ->setToolTip(l5->toolTip());
dialog->findChild<QLabel *>("labelCoinControlPriorityText") ->setToolTip(l6->toolTip());
dialog->findChild<QLabel *>("labelCoinControlLowOutputText")->setToolTip(l7->toolTip());
diff --git a/src/qt/forms/coincontroldialog.ui b/src/qt/forms/coincontroldialog.ui
index 055dd1f98d..e4faa312d4 100644
--- a/src/qt/forms/coincontroldialog.ui
+++ b/src/qt/forms/coincontroldialog.ui
@@ -38,8 +38,11 @@
</property>
<item row="0" column="0">
<widget class="QLabel" name="labelCoinControlQuantityText">
- <property name="styleSheet">
- <string notr="true">font-weight:bold;</string>
+ <property name="font">
+ <font>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
</property>
<property name="text">
<string>Quantity:</string>
@@ -64,8 +67,11 @@
</item>
<item row="1" column="0">
<widget class="QLabel" name="labelCoinControlBytesText">
- <property name="styleSheet">
- <string notr="true">font-weight:bold;</string>
+ <property name="font">
+ <font>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
</property>
<property name="text">
<string>Bytes:</string>
@@ -106,8 +112,11 @@
</property>
<item row="0" column="0">
<widget class="QLabel" name="labelCoinControlAmountText">
- <property name="styleSheet">
- <string notr="true">font-weight:bold;</string>
+ <property name="font">
+ <font>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
</property>
<property name="text">
<string>Amount:</string>
@@ -132,8 +141,11 @@
</item>
<item row="1" column="0">
<widget class="QLabel" name="labelCoinControlPriorityText">
- <property name="styleSheet">
- <string notr="true">font-weight:bold;</string>
+ <property name="font">
+ <font>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
</property>
<property name="text">
<string>Priority:</string>
@@ -148,6 +160,9 @@
<property name="contextMenuPolicy">
<enum>Qt::ActionsContextMenu</enum>
</property>
+ <property name="text">
+ <string notr="true">medium</string>
+ </property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
@@ -171,8 +186,11 @@
</property>
<item row="0" column="0">
<widget class="QLabel" name="labelCoinControlFeeText">
- <property name="styleSheet">
- <string notr="true">font-weight:bold;</string>
+ <property name="font">
+ <font>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
</property>
<property name="text">
<string>Fee:</string>
@@ -200,8 +218,11 @@
<property name="enabled">
<bool>false</bool>
</property>
- <property name="styleSheet">
- <string notr="true">font-weight:bold;</string>
+ <property name="font">
+ <font>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
</property>
<property name="text">
<string>Low Output:</string>
@@ -220,7 +241,7 @@
<enum>Qt::ActionsContextMenu</enum>
</property>
<property name="text">
- <string>no</string>
+ <string notr="true">no</string>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
@@ -245,8 +266,11 @@
</property>
<item row="0" column="0">
<widget class="QLabel" name="labelCoinControlAfterFeeText">
- <property name="styleSheet">
- <string notr="true">font-weight:bold;</string>
+ <property name="font">
+ <font>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
</property>
<property name="text">
<string>After Fee:</string>
@@ -274,8 +298,11 @@
<property name="enabled">
<bool>false</bool>
</property>
- <property name="styleSheet">
- <string notr="true">font-weight:bold;</string>
+ <property name="font">
+ <font>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
</property>
<property name="text">
<string>Change:</string>
@@ -377,7 +404,7 @@
<item>
<widget class="QLabel" name="labelLocked">
<property name="text">
- <string>(1 locked)</string>
+ <string notr="true">(1 locked)</string>
</property>
</widget>
</item>
diff --git a/src/qt/forms/sendcoinsdialog.ui b/src/qt/forms/sendcoinsdialog.ui
index 790d5d6c39..db8271b016 100644
--- a/src/qt/forms/sendcoinsdialog.ui
+++ b/src/qt/forms/sendcoinsdialog.ui
@@ -39,7 +39,7 @@
</property>
<layout class="QVBoxLayout" name="verticalLayoutCoinControl2">
<property name="spacing">
- <number>-1</number>
+ <number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
@@ -173,7 +173,16 @@
<string notr="true"/>
</property>
<layout class="QHBoxLayout" name="horizontalLayoutCoinControl5">
- <property name="margin">
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
<number>0</number>
</property>
<item>
@@ -206,8 +215,11 @@
</property>
<item row="0" column="0">
<widget class="QLabel" name="labelCoinControlQuantityText">
- <property name="styleSheet">
- <string notr="true">font-weight:bold;</string>
+ <property name="font">
+ <font>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
</property>
<property name="text">
<string>Quantity:</string>
@@ -219,12 +231,6 @@
</item>
<item row="0" column="1">
<widget class="QLabel" name="labelCoinControlQuantity">
- <property name="font">
- <font>
- <family>Monospace</family>
- <pointsize>10</pointsize>
- </font>
- </property>
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
</property>
@@ -244,8 +250,11 @@
</item>
<item row="1" column="0">
<widget class="QLabel" name="labelCoinControlBytesText">
- <property name="styleSheet">
- <string notr="true">font-weight:bold;</string>
+ <property name="font">
+ <font>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
</property>
<property name="text">
<string>Bytes:</string>
@@ -254,12 +263,6 @@
</item>
<item row="1" column="1">
<widget class="QLabel" name="labelCoinControlBytes">
- <property name="font">
- <font>
- <family>Monospace</family>
- <pointsize>10</pointsize>
- </font>
- </property>
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
</property>
@@ -295,8 +298,11 @@
</property>
<item row="0" column="0">
<widget class="QLabel" name="labelCoinControlAmountText">
- <property name="styleSheet">
- <string notr="true">font-weight:bold;</string>
+ <property name="font">
+ <font>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
</property>
<property name="text">
<string>Amount:</string>
@@ -308,12 +314,6 @@
</item>
<item row="0" column="1">
<widget class="QLabel" name="labelCoinControlAmount">
- <property name="font">
- <font>
- <family>Monospace</family>
- <pointsize>10</pointsize>
- </font>
- </property>
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
</property>
@@ -330,8 +330,11 @@
</item>
<item row="1" column="0">
<widget class="QLabel" name="labelCoinControlPriorityText">
- <property name="styleSheet">
- <string notr="true">font-weight:bold;</string>
+ <property name="font">
+ <font>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
</property>
<property name="text">
<string>Priority:</string>
@@ -340,12 +343,6 @@
</item>
<item row="1" column="1">
<widget class="QLabel" name="labelCoinControlPriority">
- <property name="font">
- <font>
- <family>Monospace</family>
- <pointsize>10</pointsize>
- </font>
- </property>
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
</property>
@@ -353,7 +350,7 @@
<enum>Qt::ActionsContextMenu</enum>
</property>
<property name="text">
- <string>medium</string>
+ <string notr="true">medium</string>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
@@ -381,8 +378,11 @@
</property>
<item row="0" column="0">
<widget class="QLabel" name="labelCoinControlFeeText">
- <property name="styleSheet">
- <string notr="true">font-weight:bold;</string>
+ <property name="font">
+ <font>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
</property>
<property name="text">
<string>Fee:</string>
@@ -394,12 +394,6 @@
</item>
<item row="0" column="1">
<widget class="QLabel" name="labelCoinControlFee">
- <property name="font">
- <font>
- <family>Monospace</family>
- <pointsize>10</pointsize>
- </font>
- </property>
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
</property>
@@ -416,8 +410,11 @@
</item>
<item row="1" column="0">
<widget class="QLabel" name="labelCoinControlLowOutputText">
- <property name="styleSheet">
- <string notr="true">font-weight:bold;</string>
+ <property name="font">
+ <font>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
</property>
<property name="text">
<string>Low Output:</string>
@@ -426,12 +423,6 @@
</item>
<item row="1" column="1">
<widget class="QLabel" name="labelCoinControlLowOutput">
- <property name="font">
- <font>
- <family>Monospace</family>
- <pointsize>10</pointsize>
- </font>
- </property>
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
</property>
@@ -439,7 +430,7 @@
<enum>Qt::ActionsContextMenu</enum>
</property>
<property name="text">
- <string>no</string>
+ <string notr="true">no</string>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
@@ -467,8 +458,11 @@
</property>
<item row="0" column="0">
<widget class="QLabel" name="labelCoinControlAfterFeeText">
- <property name="styleSheet">
- <string notr="true">font-weight:bold;</string>
+ <property name="font">
+ <font>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
</property>
<property name="text">
<string>After Fee:</string>
@@ -480,12 +474,6 @@
</item>
<item row="0" column="1">
<widget class="QLabel" name="labelCoinControlAfterFee">
- <property name="font">
- <font>
- <family>Monospace</family>
- <pointsize>10</pointsize>
- </font>
- </property>
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
</property>
@@ -502,8 +490,11 @@
</item>
<item row="1" column="0">
<widget class="QLabel" name="labelCoinControlChangeText">
- <property name="styleSheet">
- <string notr="true">font-weight:bold;</string>
+ <property name="font">
+ <font>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
</property>
<property name="text">
<string>Change:</string>
@@ -512,12 +503,6 @@
</item>
<item row="1" column="1">
<widget class="QLabel" name="labelCoinControlChange">
- <property name="font">
- <font>
- <family>Monospace</family>
- <pointsize>10</pointsize>
- </font>
- </property>
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
</property>
@@ -555,13 +540,16 @@
</property>
<item>
<widget class="QCheckBox" name="checkBoxCoinControlChange">
+ <property name="toolTip">
+ <string>If this is activated, but the change address is empty or invalid, change will be sent to a newly generated address.</string>
+ </property>
<property name="text">
- <string>custom change address</string>
+ <string>Custom change address</string>
</property>
</widget>
</item>
<item>
- <widget class="QLineEdit" name="lineEditCoinControlChange">
+ <widget class="QValidatedLineEdit" name="lineEditCoinControlChange">
<property name="enabled">
<bool>false</bool>
</property>
@@ -626,7 +614,7 @@
<x>0</x>
<y>0</y>
<width>830</width>
- <height>165</height>
+ <height>178</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2" stretch="0,1">
@@ -729,7 +717,7 @@
<cursorShape>IBeamCursor</cursorShape>
</property>
<property name="text">
- <string>123.456 BTC</string>
+ <string notr="true">123.456 BTC</string>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
@@ -778,6 +766,13 @@
</item>
</layout>
</widget>
+ <customwidgets>
+ <customwidget>
+ <class>QValidatedLineEdit</class>
+ <extends>QLineEdit</extends>
+ <header>qvalidatedlineedit.h</header>
+ </customwidget>
+ </customwidgets>
<resources>
<include location="../bitcoin.qrc"/>
</resources>
diff --git a/src/qt/forms/sendcoinsentry.ui b/src/qt/forms/sendcoinsentry.ui
index 199a14598a..b6cec5baf0 100644
--- a/src/qt/forms/sendcoinsentry.ui
+++ b/src/qt/forms/sendcoinsentry.ui
@@ -16,9 +16,6 @@
<property name="autoFillBackground">
<bool>false</bool>
</property>
- <property name="currentIndex">
- <number>0</number>
- </property>
<widget class="QFrame" name="SendCoins">
<property name="toolTip">
<string>This is a normal payment.</string>
@@ -33,20 +30,7 @@
<property name="spacing">
<number>12</number>
</property>
- <item row="5" column="0">
- <widget class="QLabel" name="amountLabel">
- <property name="text">
- <string>A&amp;mount:</string>
- </property>
- <property name="alignment">
- <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
- </property>
- <property name="buddy">
- <cstring>payAmount</cstring>
- </property>
- </widget>
- </item>
- <item row="3" column="0">
+ <item row="0" column="0">
<widget class="QLabel" name="payToLabel">
<property name="text">
<string>Pay &amp;To:</string>
@@ -59,23 +43,7 @@
</property>
</widget>
</item>
- <item row="5" column="1">
- <widget class="BitcoinAmountField" name="payAmount"/>
- </item>
- <item row="4" column="0">
- <widget class="QLabel" name="labellLabel">
- <property name="text">
- <string>&amp;Label:</string>
- </property>
- <property name="alignment">
- <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
- </property>
- <property name="buddy">
- <cstring>addAsLabel</cstring>
- </property>
- </widget>
- </item>
- <item row="3" column="1">
+ <item row="0" column="1">
<layout class="QHBoxLayout" name="payToLayout">
<property name="spacing">
<number>0</number>
@@ -85,9 +53,6 @@
<property name="toolTip">
<string>The address to send the payment to (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</string>
</property>
- <property name="maxLength">
- <number>34</number>
- </property>
</widget>
</item>
<item>
@@ -127,7 +92,7 @@
<item>
<widget class="QToolButton" name="deleteButton">
<property name="toolTip">
- <string>Remove this recipient</string>
+ <string>Remove this entry</string>
</property>
<property name="text">
<string/>
@@ -140,13 +105,42 @@
</item>
</layout>
</item>
- <item row="4" column="1">
- <widget class="QValidatedLineEdit" name="addAsLabel">
+ <item row="1" column="0">
+ <widget class="QLabel" name="labellLabel">
+ <property name="text">
+ <string>&amp;Label:</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ <property name="buddy">
+ <cstring>addAsLabel</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLineEdit" name="addAsLabel">
<property name="toolTip">
<string>Enter a label for this address to add it to the list of used addresses</string>
</property>
</widget>
</item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="amountLabel">
+ <property name="text">
+ <string>A&amp;mount:</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ <property name="buddy">
+ <cstring>payAmount</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="BitcoinAmountField" name="payAmount"/>
+ </item>
</layout>
</widget>
<widget class="QFrame" name="SendCoins_InsecurePaymentRequest">
@@ -581,60 +575,77 @@
<property name="spacing">
<number>12</number>
</property>
- <item row="4" column="0">
- <widget class="QLabel" name="memoLabel_is">
+ <item row="0" column="0">
+ <widget class="QLabel" name="payToLabel_is">
<property name="text">
- <string>Memo:</string>
+ <string>Pay To:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
- <item row="5" column="0">
- <widget class="QLabel" name="amountLabel_is">
+ <item row="0" column="1">
+ <layout class="QHBoxLayout" name="payToLayout_is">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="payTo_is"/>
+ </item>
+ <item>
+ <widget class="QToolButton" name="deleteButton_is">
+ <property name="toolTip">
+ <string>Remove this entry</string>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ <property name="icon">
+ <iconset resource="../bitcoin.qrc">
+ <normaloff>:/icons/remove</normaloff>:/icons/remove</iconset>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="memoLabel_is">
<property name="text">
- <string>Amount:</string>
+ <string>Memo:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
- <item row="3" column="0">
- <widget class="QLabel" name="payToLabel_is">
+ <item row="1" column="1">
+ <widget class="QLabel" name="memoTextLabel_is">
+ <property name="textFormat">
+ <enum>Qt::PlainText</enum>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="amountLabel_is">
<property name="text">
- <string>Pay To:</string>
+ <string>A&amp;mount:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
+ <property name="buddy">
+ <cstring>payAmount_is</cstring>
+ </property>
</widget>
</item>
- <item row="5" column="2">
+ <item row="2" column="1">
<widget class="BitcoinAmountField" name="payAmount_is">
<property name="acceptDrops">
<bool>false</bool>
</property>
</widget>
</item>
- <item row="3" column="2">
- <layout class="QHBoxLayout" name="payToLayout_is">
- <property name="spacing">
- <number>0</number>
- </property>
- <item>
- <widget class="QLabel" name="payTo_is"/>
- </item>
- </layout>
- </item>
- <item row="4" column="2">
- <widget class="QLabel" name="memoTextLabel_is">
- <property name="textFormat">
- <enum>Qt::PlainText</enum>
- </property>
- </widget>
- </item>
</layout>
</widget>
<widget class="QFrame" name="SendCoins_SecurePaymentRequest">
@@ -1096,27 +1107,7 @@
<property name="spacing">
<number>12</number>
</property>
- <item row="4" column="0">
- <widget class="QLabel" name="memoLabel_s">
- <property name="text">
- <string>Memo:</string>
- </property>
- <property name="alignment">
- <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
- </property>
- </widget>
- </item>
- <item row="5" column="0">
- <widget class="QLabel" name="amountLabel_s">
- <property name="text">
- <string>Amount:</string>
- </property>
- <property name="alignment">
- <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
- </property>
- </widget>
- </item>
- <item row="3" column="0">
+ <item row="0" column="0">
<widget class="QLabel" name="payToLabel_s">
<property name="text">
<string>Pay To:</string>
@@ -1126,14 +1117,7 @@
</property>
</widget>
</item>
- <item row="5" column="2">
- <widget class="BitcoinAmountField" name="payAmount_s">
- <property name="acceptDrops">
- <bool>false</bool>
- </property>
- </widget>
- </item>
- <item row="3" column="2">
+ <item row="0" column="1">
<layout class="QHBoxLayout" name="payToLayout_s">
<property name="spacing">
<number>0</number>
@@ -1145,30 +1129,86 @@
</property>
</widget>
</item>
+ <item>
+ <widget class="QToolButton" name="deleteButton_s">
+ <property name="toolTip">
+ <string>Remove this entry</string>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ <property name="icon">
+ <iconset resource="../bitcoin.qrc">
+ <normaloff>:/icons/remove</normaloff>:/icons/remove</iconset>
+ </property>
+ </widget>
+ </item>
</layout>
</item>
- <item row="4" column="2">
+ <item row="1" column="0">
+ <widget class="QLabel" name="memoLabel_s">
+ <property name="text">
+ <string>Memo:</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
<widget class="QLabel" name="memoTextLabel_s">
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
</widget>
</item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="amountLabel_s">
+ <property name="text">
+ <string>A&amp;mount:</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ <property name="buddy">
+ <cstring>payAmount_s</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="BitcoinAmountField" name="payAmount_s">
+ <property name="acceptDrops">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
</layout>
</widget>
</widget>
<customwidgets>
<customwidget>
- <class>BitcoinAmountField</class>
+ <class>QValidatedLineEdit</class>
<extends>QLineEdit</extends>
- <header>bitcoinamountfield.h</header>
+ <header>qvalidatedlineedit.h</header>
</customwidget>
<customwidget>
- <class>QValidatedLineEdit</class>
+ <class>BitcoinAmountField</class>
<extends>QLineEdit</extends>
- <header>qvalidatedlineedit.h</header>
+ <header>bitcoinamountfield.h</header>
</customwidget>
</customwidgets>
+ <tabstops>
+ <tabstop>payTo</tabstop>
+ <tabstop>addressBookButton</tabstop>
+ <tabstop>pasteButton</tabstop>
+ <tabstop>deleteButton</tabstop>
+ <tabstop>addAsLabel</tabstop>
+ <tabstop>payAmount</tabstop>
+ <tabstop>payAmount_is</tabstop>
+ <tabstop>deleteButton_is</tabstop>
+ <tabstop>payAmount_s</tabstop>
+ <tabstop>deleteButton_s</tabstop>
+ </tabstops>
<resources>
<include location="../bitcoin.qrc"/>
</resources>
diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp
index 2ce09b479e..8f8d67dc58 100644
--- a/src/qt/guiutil.cpp
+++ b/src/qt/guiutil.cpp
@@ -32,6 +32,7 @@
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
+
#include <QAbstractItemView>
#include <QApplication>
#include <QClipboard>
diff --git a/src/qt/macdockiconhandler.mm b/src/qt/macdockiconhandler.mm
index 8f826941b2..86b8c834d4 100644
--- a/src/qt/macdockiconhandler.mm
+++ b/src/qt/macdockiconhandler.mm
@@ -8,6 +8,10 @@
#undef slots
#include <Cocoa/Cocoa.h>
+#if QT_VERSION < 0x050000
+extern void qt_mac_set_dock_menu(QMenu *);
+#endif
+
@interface DockIconClickEventHandler : NSObject
{
MacDockIconHandler* dockIconHandler;
@@ -52,7 +56,9 @@ MacDockIconHandler::MacDockIconHandler() : QObject()
this->m_dummyWidget = new QWidget();
this->m_dockMenu = new QMenu(this->m_dummyWidget);
this->setMainWindow(NULL);
-
+#if QT_VERSION < 0x050000
+ qt_mac_set_dock_menu(this->m_dockMenu);
+#endif
[pool release];
}
diff --git a/src/qt/notificator.cpp b/src/qt/notificator.cpp
index c9f6834ec2..1cef397d12 100644
--- a/src/qt/notificator.cpp
+++ b/src/qt/notificator.cpp
@@ -4,7 +4,6 @@
#include "notificator.h"
-
#include <QApplication>
#include <QByteArray>
#include <QIcon>
@@ -32,7 +31,7 @@
// https://wiki.ubuntu.com/NotificationDevelopmentGuidelines recommends at least 128
const int FREEDESKTOP_NOTIFICATION_ICON_SIZE = 128;
-Notificator::Notificator(const QString &programName, QSystemTrayIcon *trayicon, QWidget *parent):
+Notificator::Notificator(const QString &programName, QSystemTrayIcon *trayicon, QWidget *parent) :
QObject(parent),
parent(parent),
programName(programName),
@@ -48,7 +47,7 @@ Notificator::Notificator(const QString &programName, QSystemTrayIcon *trayicon,
}
#ifdef USE_DBUS
interface = new QDBusInterface("org.freedesktop.Notifications",
- "/org/freedesktop/Notifications", "org.freedesktop.Notifications");
+ "/org/freedesktop/Notifications", "org.freedesktop.Notifications");
if(interface->isValid())
{
mode = Freedesktop;
diff --git a/src/qt/notificator.h b/src/qt/notificator.h
index d6298c3c0d..abab986992 100644
--- a/src/qt/notificator.h
+++ b/src/qt/notificator.h
@@ -29,7 +29,7 @@ public:
/** Create a new notificator.
@note Ownership of trayIcon is not transferred to this object.
*/
- Notificator(const QString &programName=QString(), QSystemTrayIcon *trayIcon=0, QWidget *parent=0);
+ Notificator(const QString &programName, QSystemTrayIcon *trayIcon, QWidget *parent);
~Notificator();
// Message class
diff --git a/src/qt/openuridialog.cpp b/src/qt/openuridialog.cpp
index 803a3c9ddb..06189aeaf3 100644
--- a/src/qt/openuridialog.cpp
+++ b/src/qt/openuridialog.cpp
@@ -48,5 +48,5 @@ void OpenURIDialog::on_selectFileButton_clicked()
if(filename.isEmpty())
return;
QUrl fileUri = QUrl::fromLocalFile(filename);
- ui->uriEdit->setText("bitcoin:?request=" + QUrl::toPercentEncoding(fileUri.toString()));
+ ui->uriEdit->setText("bitcoin:?r=" + QUrl::toPercentEncoding(fileUri.toString()));
}
diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp
index 34da0f90ec..ba5c06064f 100644
--- a/src/qt/paymentserver.cpp
+++ b/src/qt/paymentserver.cpp
@@ -232,7 +232,10 @@ bool PaymentServer::ipcSendCommandLine(int argc, char* argv[])
QLocalSocket* socket = new QLocalSocket();
socket->connectToServer(ipcServerName(), QIODevice::WriteOnly);
if (!socket->waitForConnected(BITCOIN_IPC_CONNECT_TIMEOUT))
+ {
+ delete socket;
return false;
+ }
QByteArray block;
QDataStream out(&block, QIODevice::WriteOnly);
@@ -277,8 +280,11 @@ PaymentServer::PaymentServer(QObject* parent, bool startLocalServer) :
{
uriServer = new QLocalServer(this);
- if (!uriServer->listen(name))
- qDebug() << "PaymentServer::PaymentServer : Cannot start bitcoin: click-to-pay handler";
+ if (!uriServer->listen(name)) {
+ // constructor is called early in init, so don't use "emit message()" here
+ QMessageBox::critical(0, tr("Payment request error"),
+ tr("Cannot start bitcoin: click-to-pay handler"));
+ }
else {
connect(uriServer, SIGNAL(newConnection()), this, SLOT(handleURIConnection()));
connect(this, SIGNAL(receivedPaymentACK(QString)), this, SLOT(handlePaymentACK(QString)));
@@ -295,12 +301,12 @@ PaymentServer::~PaymentServer()
// OSX-specific way of handling bitcoin: URIs and
// PaymentRequest mime types
//
-bool PaymentServer::eventFilter(QObject *, QEvent *event)
+bool PaymentServer::eventFilter(QObject *object, QEvent *event)
{
- // clicking on bitcoin: URIs creates FileOpen events on the Mac:
+ // clicking on bitcoin: URIs creates FileOpen events on the Mac
if (event->type() == QEvent::FileOpen)
{
- QFileOpenEvent* fileEvent = static_cast<QFileOpenEvent*>(event);
+ QFileOpenEvent *fileEvent = static_cast<QFileOpenEvent*>(event);
if (!fileEvent->file().isEmpty())
handleURIOrFile(fileEvent->file());
else if (!fileEvent->url().isEmpty())
@@ -308,7 +314,8 @@ bool PaymentServer::eventFilter(QObject *, QEvent *event)
return true;
}
- return false;
+
+ return QObject::eventFilter(object, event);
}
void PaymentServer::initNetManager()
@@ -359,17 +366,17 @@ void PaymentServer::handleURIOrFile(const QString& s)
return;
}
- if (s.startsWith(BITCOIN_IPC_PREFIX, Qt::CaseInsensitive)) // bitcoin:
+ if (s.startsWith(BITCOIN_IPC_PREFIX, Qt::CaseInsensitive)) // bitcoin: URI
{
#if QT_VERSION < 0x050000
QUrl uri(s);
#else
QUrlQuery uri((QUrl(s)));
#endif
- if (uri.hasQueryItem("request"))
+ if (uri.hasQueryItem("r"))
{
QByteArray temp;
- temp.append(uri.queryItemValue("request"));
+ temp.append(uri.queryItemValue("r"));
QString decoded = QUrl::fromPercentEncoding(temp);
QUrl fetchUrl(decoded, QUrl::StrictMode);
diff --git a/src/qt/paymentserver.h b/src/qt/paymentserver.h
index 50f077f3bc..ab59388acc 100644
--- a/src/qt/paymentserver.h
+++ b/src/qt/paymentserver.h
@@ -77,10 +77,6 @@ public:
// Return certificate store
static X509_STORE* getCertStore() { return certStore; }
- // Constructor registers this on the parent QApplication to
- // receive QEvent::FileOpen events
- bool eventFilter(QObject *object, QEvent *event);
-
// OptionsModel is used for getting proxy settings and display unit
void setOptionsModel(OptionsModel *optionsModel);
@@ -111,6 +107,11 @@ private slots:
void reportSslErrors(QNetworkReply*, const QList<QSslError> &);
void handlePaymentACK(const QString& paymentACKMsg);
+protected:
+ // Constructor registers this on the parent QApplication to
+ // receive QEvent::FileOpen and QEvent:Drop events
+ bool eventFilter(QObject *object, QEvent *event);
+
private:
static bool readPaymentRequest(const QString& filename, PaymentRequestPlus& request);
bool processPaymentRequest(PaymentRequestPlus& request, SendCoinsRecipient& recipient);
diff --git a/src/qt/receivecoinsdialog.cpp b/src/qt/receivecoinsdialog.cpp
index a536fa2ad7..075a16dabf 100644
--- a/src/qt/receivecoinsdialog.cpp
+++ b/src/qt/receivecoinsdialog.cpp
@@ -117,11 +117,11 @@ void ReceiveCoinsDialog::on_receiveButton_clicked()
address = model->getAddressTableModel()->addRow(AddressTableModel::Receive, label, "");
}
SendCoinsRecipient info(address, label,
- ui->reqAmount->value(), ui->reqMessage->text());
+ ui->reqAmount->value(), ui->reqMessage->text());
ReceiveRequestDialog *dialog = new ReceiveRequestDialog(this);
+ dialog->setAttribute(Qt::WA_DeleteOnClose);
dialog->setModel(model->getOptionsModel());
dialog->setInfo(info);
- dialog->setAttribute(Qt::WA_DeleteOnClose);
dialog->show();
clear();
diff --git a/src/qt/res/icons/add.png b/src/qt/res/icons/add.png
index f98e2a8ca7..ea53fc3493 100644
--- a/src/qt/res/icons/add.png
+++ b/src/qt/res/icons/add.png
Binary files differ
diff --git a/src/qt/res/icons/address-book.png b/src/qt/res/icons/address-book.png
index d41dbe6539..33a2d91754 100644
--- a/src/qt/res/icons/address-book.png
+++ b/src/qt/res/icons/address-book.png
Binary files differ
diff --git a/src/qt/res/icons/bitcoin.png b/src/qt/res/icons/bitcoin.png
index c90471bd07..ce5fbb0c2c 100644
--- a/src/qt/res/icons/bitcoin.png
+++ b/src/qt/res/icons/bitcoin.png
Binary files differ
diff --git a/src/qt/res/icons/bitcoin_testnet.png b/src/qt/res/icons/bitcoin_testnet.png
index d54125c0c6..1202021f53 100644
--- a/src/qt/res/icons/bitcoin_testnet.png
+++ b/src/qt/res/icons/bitcoin_testnet.png
Binary files differ
diff --git a/src/qt/res/icons/clock1.png b/src/qt/res/icons/clock1.png
index 448e47f947..9f0aa5db29 100644
--- a/src/qt/res/icons/clock1.png
+++ b/src/qt/res/icons/clock1.png
Binary files differ
diff --git a/src/qt/res/icons/clock2.png b/src/qt/res/icons/clock2.png
index c1a6e99f7f..bad00ccc63 100644
--- a/src/qt/res/icons/clock2.png
+++ b/src/qt/res/icons/clock2.png
Binary files differ
diff --git a/src/qt/res/icons/clock3.png b/src/qt/res/icons/clock3.png
index e429a402cf..7314d5302b 100644
--- a/src/qt/res/icons/clock3.png
+++ b/src/qt/res/icons/clock3.png
Binary files differ
diff --git a/src/qt/res/icons/clock4.png b/src/qt/res/icons/clock4.png
index ba036f47d3..07f5bfab5f 100644
--- a/src/qt/res/icons/clock4.png
+++ b/src/qt/res/icons/clock4.png
Binary files differ
diff --git a/src/qt/res/icons/clock5.png b/src/qt/res/icons/clock5.png
index 411d7a78a0..27e9630eb5 100644
--- a/src/qt/res/icons/clock5.png
+++ b/src/qt/res/icons/clock5.png
Binary files differ
diff --git a/src/qt/res/icons/configure.png b/src/qt/res/icons/configure.png
index 95bd319ce1..a1bd70aa4e 100644
--- a/src/qt/res/icons/configure.png
+++ b/src/qt/res/icons/configure.png
Binary files differ
diff --git a/src/qt/res/icons/connect0_16.png b/src/qt/res/icons/connect0_16.png
index 66f3ae4f86..a397e7e6a7 100644
--- a/src/qt/res/icons/connect0_16.png
+++ b/src/qt/res/icons/connect0_16.png
Binary files differ
diff --git a/src/qt/res/icons/connect1_16.png b/src/qt/res/icons/connect1_16.png
index 76000beee2..199fb44c53 100644
--- a/src/qt/res/icons/connect1_16.png
+++ b/src/qt/res/icons/connect1_16.png
Binary files differ
diff --git a/src/qt/res/icons/connect2_16.png b/src/qt/res/icons/connect2_16.png
index 6d9a37281a..2a85ba50d7 100644
--- a/src/qt/res/icons/connect2_16.png
+++ b/src/qt/res/icons/connect2_16.png
Binary files differ
diff --git a/src/qt/res/icons/connect3_16.png b/src/qt/res/icons/connect3_16.png
index a211700785..d4b35ecc5f 100644
--- a/src/qt/res/icons/connect3_16.png
+++ b/src/qt/res/icons/connect3_16.png
Binary files differ
diff --git a/src/qt/res/icons/connect4_16.png b/src/qt/res/icons/connect4_16.png
index c1232f5682..0376443b1c 100644
--- a/src/qt/res/icons/connect4_16.png
+++ b/src/qt/res/icons/connect4_16.png
Binary files differ
diff --git a/src/qt/res/icons/debugwindow.png b/src/qt/res/icons/debugwindow.png
index 1712adf0e7..767d0bb9f0 100644
--- a/src/qt/res/icons/debugwindow.png
+++ b/src/qt/res/icons/debugwindow.png
Binary files differ
diff --git a/src/qt/res/icons/edit.png b/src/qt/res/icons/edit.png
index 1d69145151..49e2ee3fc1 100644
--- a/src/qt/res/icons/edit.png
+++ b/src/qt/res/icons/edit.png
Binary files differ
diff --git a/src/qt/res/icons/editcopy.png b/src/qt/res/icons/editcopy.png
index f882aa2ad8..7807c59a88 100644
--- a/src/qt/res/icons/editcopy.png
+++ b/src/qt/res/icons/editcopy.png
Binary files differ
diff --git a/src/qt/res/icons/editpaste.png b/src/qt/res/icons/editpaste.png
index a192060bdd..e217e308ea 100644
--- a/src/qt/res/icons/editpaste.png
+++ b/src/qt/res/icons/editpaste.png
Binary files differ
diff --git a/src/qt/res/icons/export.png b/src/qt/res/icons/export.png
index 1df9c2398d..5c1f519054 100644
--- a/src/qt/res/icons/export.png
+++ b/src/qt/res/icons/export.png
Binary files differ
diff --git a/src/qt/res/icons/filesave.png b/src/qt/res/icons/filesave.png
index ae13a151d5..02e78b931a 100644
--- a/src/qt/res/icons/filesave.png
+++ b/src/qt/res/icons/filesave.png
Binary files differ
diff --git a/src/qt/res/icons/history.png b/src/qt/res/icons/history.png
index 10ac0e1592..ac955c7291 100644
--- a/src/qt/res/icons/history.png
+++ b/src/qt/res/icons/history.png
Binary files differ
diff --git a/src/qt/res/icons/key.png b/src/qt/res/icons/key.png
index ece0164f77..2638b4f231 100644
--- a/src/qt/res/icons/key.png
+++ b/src/qt/res/icons/key.png
Binary files differ
diff --git a/src/qt/res/icons/lock_closed.png b/src/qt/res/icons/lock_closed.png
index c566510c40..6de207db7d 100644
--- a/src/qt/res/icons/lock_closed.png
+++ b/src/qt/res/icons/lock_closed.png
Binary files differ
diff --git a/src/qt/res/icons/lock_open.png b/src/qt/res/icons/lock_open.png
index c98ca8663b..23ce3243aa 100644
--- a/src/qt/res/icons/lock_open.png
+++ b/src/qt/res/icons/lock_open.png
Binary files differ
diff --git a/src/qt/res/icons/notsynced.png b/src/qt/res/icons/notsynced.png
index c9e71184c5..87b1c3290b 100644
--- a/src/qt/res/icons/notsynced.png
+++ b/src/qt/res/icons/notsynced.png
Binary files differ
diff --git a/src/qt/res/icons/overview.png b/src/qt/res/icons/overview.png
index ee2511f01d..a274f0c488 100644
--- a/src/qt/res/icons/overview.png
+++ b/src/qt/res/icons/overview.png
Binary files differ
diff --git a/src/qt/res/icons/qrcode.png b/src/qt/res/icons/qrcode.png
index a8d97174b3..ee61aff2f0 100644
--- a/src/qt/res/icons/qrcode.png
+++ b/src/qt/res/icons/qrcode.png
Binary files differ
diff --git a/src/qt/res/icons/quit.png b/src/qt/res/icons/quit.png
index 0dde6f395c..bd73baee20 100644
--- a/src/qt/res/icons/quit.png
+++ b/src/qt/res/icons/quit.png
Binary files differ
diff --git a/src/qt/res/icons/receive.png b/src/qt/res/icons/receive.png
index 53ad1d1565..8ed337ca1a 100644
--- a/src/qt/res/icons/receive.png
+++ b/src/qt/res/icons/receive.png
Binary files differ
diff --git a/src/qt/res/icons/remove.png b/src/qt/res/icons/remove.png
index a44b6d130b..224d2c20c3 100644
--- a/src/qt/res/icons/remove.png
+++ b/src/qt/res/icons/remove.png
Binary files differ
diff --git a/src/qt/res/icons/send.png b/src/qt/res/icons/send.png
index ceb91ea66d..43c3d7922c 100644
--- a/src/qt/res/icons/send.png
+++ b/src/qt/res/icons/send.png
Binary files differ
diff --git a/src/qt/res/icons/synced.png b/src/qt/res/icons/synced.png
index 4d7e0e8821..9fad384768 100644
--- a/src/qt/res/icons/synced.png
+++ b/src/qt/res/icons/synced.png
Binary files differ
diff --git a/src/qt/res/icons/toolbar.png b/src/qt/res/icons/toolbar.png
index b694302871..c82d96519c 100644
--- a/src/qt/res/icons/toolbar.png
+++ b/src/qt/res/icons/toolbar.png
Binary files differ
diff --git a/src/qt/res/icons/toolbar_testnet.png b/src/qt/res/icons/toolbar_testnet.png
index dcac261c36..5995bc0667 100644
--- a/src/qt/res/icons/toolbar_testnet.png
+++ b/src/qt/res/icons/toolbar_testnet.png
Binary files differ
diff --git a/src/qt/res/icons/transaction0.png b/src/qt/res/icons/transaction0.png
index 4578666ee4..cfe1a1c8b8 100644
--- a/src/qt/res/icons/transaction0.png
+++ b/src/qt/res/icons/transaction0.png
Binary files differ
diff --git a/src/qt/res/icons/transaction2.png b/src/qt/res/icons/transaction2.png
index 01bb558a10..8a804b05ac 100644
--- a/src/qt/res/icons/transaction2.png
+++ b/src/qt/res/icons/transaction2.png
Binary files differ
diff --git a/src/qt/res/icons/tx_inout.png b/src/qt/res/icons/tx_inout.png
index 5f092f97aa..f1a7f7bbc3 100644
--- a/src/qt/res/icons/tx_inout.png
+++ b/src/qt/res/icons/tx_inout.png
Binary files differ
diff --git a/src/qt/res/icons/tx_input.png b/src/qt/res/icons/tx_input.png
index 0f5fea3a84..a2d324ee34 100644
--- a/src/qt/res/icons/tx_input.png
+++ b/src/qt/res/icons/tx_input.png
Binary files differ
diff --git a/src/qt/res/icons/tx_mined.png b/src/qt/res/icons/tx_mined.png
index 613f30fecc..a7acc6cf7b 100644
--- a/src/qt/res/icons/tx_mined.png
+++ b/src/qt/res/icons/tx_mined.png
Binary files differ
diff --git a/src/qt/res/icons/tx_output.png b/src/qt/res/icons/tx_output.png
index 9ae39fb329..a7c5ebf56b 100644
--- a/src/qt/res/icons/tx_output.png
+++ b/src/qt/res/icons/tx_output.png
Binary files differ
diff --git a/src/qt/res/images/about.png b/src/qt/res/images/about.png
index c9ab9511ef..fdede66172 100644
--- a/src/qt/res/images/about.png
+++ b/src/qt/res/images/about.png
Binary files differ
diff --git a/src/qt/res/images/splash.png b/src/qt/res/images/splash.png
index 376c274a8d..3f2b2fb2bf 100644
--- a/src/qt/res/images/splash.png
+++ b/src/qt/res/images/splash.png
Binary files differ
diff --git a/src/qt/res/images/splash_testnet.png b/src/qt/res/images/splash_testnet.png
index 2520e76e62..786dc9c3bb 100644
--- a/src/qt/res/images/splash_testnet.png
+++ b/src/qt/res/images/splash_testnet.png
Binary files differ
diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp
index 64a3a68ba7..d43cdc7e5f 100644
--- a/src/qt/rpcconsole.cpp
+++ b/src/qt/rpcconsole.cpp
@@ -8,7 +8,8 @@
#include "clientmodel.h"
#include "guiutil.h"
-#include "bitcoinrpc.h"
+#include "rpcserver.h"
+#include "rpcclient.h"
#include "json/json_spirit_value.h"
#include <openssl/crypto.h>
diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp
index 0adf24691e..0a4e80811f 100644
--- a/src/qt/sendcoinsdialog.cpp
+++ b/src/qt/sendcoinsdialog.cpp
@@ -216,12 +216,19 @@ void SendCoinsDialog::on_sendButton_clicked()
questionString.append("</span> ");
questionString.append(tr("added as transaction fee"));
}
- if(txFee > 0 || recipients.count() > 1)
+
+ // add total amount in all subdivision units
+ questionString.append("<hr />");
+ qint64 totalAmount = currentTransaction.getTotalTransactionAmount() + txFee;
+ QStringList alternativeUnits;
+ foreach(BitcoinUnits::Unit u, BitcoinUnits::availableUnits())
{
- // add total amount string if there are more then one recipients or a fee is required
- questionString.append("<hr />");
- questionString.append(tr("Total Amount %1").arg(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), currentTransaction.getTotalTransactionAmount()+txFee)));
+ if(u != model->getOptionsModel()->getDisplayUnit())
+ alternativeUnits.append(BitcoinUnits::formatWithUnit(u, totalAmount));
}
+ questionString.append(tr("Total Amount %1 (= %2)")
+ .arg(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), totalAmount))
+ .arg(alternativeUnits.join(" " + tr("or") + " ")));
QMessageBox::StandardButton retval = QMessageBox::question(this, tr("Confirm send coins"),
questionString.arg(formatted.join("<br />")),
@@ -253,13 +260,11 @@ void SendCoinsDialog::clear()
// Remove entries until only one left
while(ui->entries->count())
{
- delete ui->entries->takeAt(0)->widget();
+ ui->entries->takeAt(0)->widget()->deleteLater();
}
addEntry();
- updateRemoveEnabled();
-
- ui->sendButton->setDefault(true);
+ updateTabsAndLabels();
}
void SendCoinsDialog::reject()
@@ -280,7 +285,7 @@ SendCoinsEntry *SendCoinsDialog::addEntry()
connect(entry, SIGNAL(removeEntry(SendCoinsEntry*)), this, SLOT(removeEntry(SendCoinsEntry*)));
connect(entry, SIGNAL(payAmountChanged()), this, SLOT(coinControlUpdateLabels()));
- updateRemoveEnabled();
+ updateTabsAndLabels();
// Focus the field, so that entry can start immediately
entry->clear();
@@ -293,27 +298,21 @@ SendCoinsEntry *SendCoinsDialog::addEntry()
return entry;
}
-void SendCoinsDialog::updateRemoveEnabled()
+void SendCoinsDialog::updateTabsAndLabels()
{
- // Remove buttons are enabled as soon as there is more than one send-entry
- bool enabled = (ui->entries->count() > 1);
- for(int i = 0; i < ui->entries->count(); ++i)
- {
- SendCoinsEntry *entry = qobject_cast<SendCoinsEntry*>(ui->entries->itemAt(i)->widget());
- if(entry)
- {
- entry->setRemoveEnabled(enabled);
- }
- }
setupTabChain(0);
-
coinControlUpdateLabels();
}
void SendCoinsDialog::removeEntry(SendCoinsEntry* entry)
{
- delete entry;
- updateRemoveEnabled();
+ entry->deleteLater();
+
+ // If the last entry was removed add an empty one
+ if (!ui->entries->count())
+ addEntry();
+
+ updateTabsAndLabels();
}
QWidget *SendCoinsDialog::setupTabChain(QWidget *prev)
@@ -372,7 +371,7 @@ void SendCoinsDialog::pasteEntry(const SendCoinsRecipient &rv)
}
entry->setValue(rv);
- coinControlUpdateLabels();
+ updateTabsAndLabels();
}
bool SendCoinsDialog::handlePaymentRequest(const SendCoinsRecipient &rv)
@@ -530,16 +529,17 @@ void SendCoinsDialog::coinControlButtonClicked()
// Coin Control: checkbox custom change address
void SendCoinsDialog::coinControlChangeChecked(int state)
{
- if (model)
+ if (state == Qt::Unchecked)
{
- if (state == Qt::Checked)
- CoinControlDialog::coinControl->destChange = CBitcoinAddress(ui->lineEditCoinControlChange->text().toStdString()).Get();
- else
- CoinControlDialog::coinControl->destChange = CNoDestination();
+ CoinControlDialog::coinControl->destChange = CNoDestination();
+ ui->lineEditCoinControlChange->setValid(true);
+ ui->labelCoinControlChangeLabel->clear();
}
+ else
+ // use this to re-validate an already entered address
+ coinControlChangeEdited(ui->lineEditCoinControlChange->text());
ui->lineEditCoinControlChange->setEnabled((state == Qt::Checked));
- ui->labelCoinControlChangeLabel->setVisible((state == Qt::Checked));
}
// Coin Control: custom change address changed
@@ -555,6 +555,10 @@ void SendCoinsDialog::coinControlChangeEdited(const QString & text)
ui->labelCoinControlChangeLabel->setText("");
else if (!CBitcoinAddress(text.toStdString()).IsValid())
{
+ // invalid change address
+ CoinControlDialog::coinControl->destChange = CNoDestination();
+
+ ui->lineEditCoinControlChange->setValid(false);
ui->labelCoinControlChangeLabel->setStyleSheet("QLabel{color:red;}");
ui->labelCoinControlChangeLabel->setText(tr("Warning: Invalid Bitcoin address"));
}
@@ -572,6 +576,10 @@ void SendCoinsDialog::coinControlChangeEdited(const QString & text)
ui->labelCoinControlChangeLabel->setText(tr("(no label)"));
else
{
+ // unknown change address
+ CoinControlDialog::coinControl->destChange = CNoDestination();
+
+ ui->lineEditCoinControlChange->setValid(false);
ui->labelCoinControlChangeLabel->setStyleSheet("QLabel{color:red;}");
ui->labelCoinControlChangeLabel->setText(tr("Warning: Unknown change address"));
}
@@ -612,4 +620,3 @@ void SendCoinsDialog::coinControlUpdateLabels()
ui->labelCoinControlInsuffFunds->hide();
}
}
-
diff --git a/src/qt/sendcoinsdialog.h b/src/qt/sendcoinsdialog.h
index 4327e8e382..fcae26c720 100644
--- a/src/qt/sendcoinsdialog.h
+++ b/src/qt/sendcoinsdialog.h
@@ -46,7 +46,7 @@ public slots:
void reject();
void accept();
SendCoinsEntry *addEntry();
- void updateRemoveEnabled();
+ void updateTabsAndLabels();
void setBalance(qint64 balance, qint64 unconfirmedBalance, qint64 immatureBalance);
private:
diff --git a/src/qt/sendcoinsentry.cpp b/src/qt/sendcoinsentry.cpp
index 2641a66af4..4d28f68861 100644
--- a/src/qt/sendcoinsentry.cpp
+++ b/src/qt/sendcoinsentry.cpp
@@ -75,15 +75,13 @@ void SendCoinsEntry::setModel(WalletModel *model)
connect(model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit()));
connect(ui->payAmount, SIGNAL(textChanged()), this, SIGNAL(payAmountChanged()));
+ connect(ui->deleteButton, SIGNAL(clicked()), this, SLOT(deleteClicked()));
+ connect(ui->deleteButton_is, SIGNAL(clicked()), this, SLOT(deleteClicked()));
+ connect(ui->deleteButton_s, SIGNAL(clicked()), this, SLOT(deleteClicked()));
clear();
}
-void SendCoinsEntry::setRemoveEnabled(bool enabled)
-{
- ui->deleteButton->setEnabled(enabled);
-}
-
void SendCoinsEntry::clear()
{
// clear UI elements for normal payment
@@ -99,13 +97,11 @@ void SendCoinsEntry::clear()
ui->memoTextLabel_s->clear();
ui->payAmount_s->clear();
- ui->payTo->setFocus();
-
// update the display unit, to not use the default ("BTC")
updateDisplayUnit();
}
-void SendCoinsEntry::on_deleteButton_clicked()
+void SendCoinsEntry::deleteClicked()
{
emit removeEntry(this);
}
diff --git a/src/qt/sendcoinsentry.h b/src/qt/sendcoinsentry.h
index 1c4ddaa8ef..2b696c77fb 100644
--- a/src/qt/sendcoinsentry.h
+++ b/src/qt/sendcoinsentry.h
@@ -46,7 +46,6 @@ public:
void setFocus();
public slots:
- void setRemoveEnabled(bool enabled);
void clear();
signals:
@@ -54,7 +53,7 @@ signals:
void payAmountChanged();
private slots:
- void on_deleteButton_clicked();
+ void deleteClicked();
void on_payTo_textChanged(const QString &address);
void on_addressBookButton_clicked();
void on_pasteButton_clicked();
diff --git a/src/qt/test/Makefile.am b/src/qt/test/Makefile.am
index 7891c3e975..cb6874700e 100644
--- a/src/qt/test/Makefile.am
+++ b/src/qt/test/Makefile.am
@@ -17,7 +17,7 @@ BUILT_SOURCES = $(TEST_QT_MOC_CPP)
test_bitcoin_qt_CPPFLAGS = $(AM_CPPFLAGS) $(QT_INCLUDES) $(QT_TEST_INCLUDES)
test_bitcoin_qt_SOURCES = test_main.cpp uritests.cpp paymentservertests.cpp $(TEST_QT_H)
nodist_test_bitcoin_qt_SOURCES = $(TEST_QT_MOC_CPP)
-test_bitcoin_qt_LDADD = $(LIBBITCOINQT) $(LIBBITCOIN) $(LIBLEVELDB) \
+test_bitcoin_qt_LDADD = $(LIBBITCOINQT) $(LIBBITCOIN_SERVER) $(LIBBITCOIN_WALLET) $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBLEVELDB) \
$(LIBMEMENV) $(BOOST_LIBS) $(QT_LIBS) $(QT_DBUS_LIBS) $(QT_TEST_LIBS) \
$(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS)
diff --git a/src/qt/test/paymentservertests.cpp b/src/qt/test/paymentservertests.cpp
index b8f2cc65cb..7dee7a9cda 100644
--- a/src/qt/test/paymentservertests.cpp
+++ b/src/qt/test/paymentservertests.cpp
@@ -7,12 +7,9 @@
#include <openssl/x509.h>
#include <openssl/x509_vfy.h>
-#include <QCoreApplication>
-#include <QDebug>
+
#include <QFileOpenEvent>
#include <QTemporaryFile>
-#include <QVariant>
-
X509 *parse_b64der_cert(const char* cert_data)
{
@@ -41,9 +38,14 @@ static SendCoinsRecipient handleRequest(PaymentServer* server, std::vector<unsig
f.write((const char*)&data[0], data.size());
f.close();
- // Create a FileOpenEvent and send it directly to the server's event filter:
+ // Create a QObject, install event filter from PaymentServer
+ // and send a file open event to the object
+ QObject object;
+ object.installEventFilter(server);
QFileOpenEvent event(f.fileName());
- server->eventFilter(NULL, &event);
+ // If sending the event fails, this will cause sigCatcher to be empty,
+ // which will lead to a test failure anyway.
+ QCoreApplication::sendEvent(&object, &event);
QObject::disconnect(server, SIGNAL(receivedPaymentRequest(SendCoinsRecipient)),
&sigCatcher, SLOT(getRecipient(SendCoinsRecipient)));
diff --git a/src/qt/test/paymentservertests.h b/src/qt/test/paymentservertests.h
index 0bff923ad4..884e535a60 100644
--- a/src/qt/test/paymentservertests.h
+++ b/src/qt/test/paymentservertests.h
@@ -20,8 +20,10 @@ private slots:
class RecipientCatcher : public QObject
{
Q_OBJECT
+
public slots:
void getRecipient(SendCoinsRecipient r);
+
public:
SendCoinsRecipient recipient;
};
diff --git a/src/qt/test/test_main.cpp b/src/qt/test/test_main.cpp
index 5c941c6387..ae584706f1 100644
--- a/src/qt/test/test_main.cpp
+++ b/src/qt/test/test_main.cpp
@@ -1,8 +1,7 @@
-
-
#include "paymentservertests.h"
#include "uritests.h"
+#include <QCoreApplication>
#include <QObject>
#include <QTest>
@@ -11,6 +10,11 @@ int main(int argc, char *argv[])
{
bool fInvalid = false;
+ // Don't remove this, it's needed to access
+ // QCoreApplication:: in the tests
+ QCoreApplication app(argc, argv);
+ app.setApplicationName("Bitcoin-Qt-test");
+
URITests test1;
if (QTest::qExec(&test1) != 0)
fInvalid = true;
diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp
index 8bd2bf564a..c0c4d53732 100644
--- a/src/qt/transactiondesc.cpp
+++ b/src/qt/transactiondesc.cpp
@@ -194,7 +194,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, int vout, int u
strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatWithUnit(unit, nValue) + "<br>";
}
- int64_t nTxFee = nDebit - GetValueOut(wtx);
+ int64_t nTxFee = nDebit - wtx.GetValueOut();
if (nTxFee > 0)
strHTML += "<b>" + tr("Transaction fee") + ":</b> " + BitcoinUnits::formatWithUnit(unit, -nTxFee) + "<br>";
}
diff --git a/src/qt/transactionrecord.cpp b/src/qt/transactionrecord.cpp
index 675daa9c9c..6823557ebc 100644
--- a/src/qt/transactionrecord.cpp
+++ b/src/qt/transactionrecord.cpp
@@ -95,7 +95,7 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet *
//
// Debit
//
- int64_t nTxFee = nDebit - GetValueOut(wtx);
+ int64_t nTxFee = nDebit - wtx.GetValueOut();
for (unsigned int nOut = 0; nOut < wtx.vout.size(); nOut++)
{
diff --git a/src/qt/walletview.cpp b/src/qt/walletview.cpp
index ea71d58aa6..1a9c7866db 100644
--- a/src/qt/walletview.cpp
+++ b/src/qt/walletview.cpp
@@ -263,8 +263,8 @@ void WalletView::usedSendingAddresses()
if(!walletModel)
return;
AddressBookPage *dlg = new AddressBookPage(AddressBookPage::ForEditing, AddressBookPage::SendingTab, this);
- dlg->setModel(walletModel->getAddressTableModel());
dlg->setAttribute(Qt::WA_DeleteOnClose);
+ dlg->setModel(walletModel->getAddressTableModel());
dlg->show();
}
@@ -273,7 +273,7 @@ void WalletView::usedReceivingAddresses()
if(!walletModel)
return;
AddressBookPage *dlg = new AddressBookPage(AddressBookPage::ForEditing, AddressBookPage::ReceivingTab, this);
- dlg->setModel(walletModel->getAddressTableModel());
dlg->setAttribute(Qt::WA_DeleteOnClose);
+ dlg->setModel(walletModel->getAddressTableModel());
dlg->show();
}
diff --git a/src/qt/walletview.h b/src/qt/walletview.h
index d951691621..ecfa06ac5a 100644
--- a/src/qt/walletview.h
+++ b/src/qt/walletview.h
@@ -96,6 +96,7 @@ public slots:
/** Re-emit encryption status signal */
void updateEncryptionStatus();
+
signals:
/** Signal that we want to show the main window */
void showNormalIfMinimized();
diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp
index 6f0b353e34..34ae6e0543 100644
--- a/src/rpcblockchain.cpp
+++ b/src/rpcblockchain.cpp
@@ -3,9 +3,7 @@
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-
-#include "bitcoinrpc.h"
+#include "rpcserver.h"
#include "main.h"
#include "sync.h"
@@ -155,28 +153,79 @@ Value settxfee(const Array& params, bool fHelp)
Value getrawmempool(const Array& params, bool fHelp)
{
- if (fHelp || params.size() != 0)
+ if (fHelp || params.size() > 1)
throw runtime_error(
- "getrawmempool\n"
+ "getrawmempool ( verbose )\n"
"\nReturns all transaction ids in memory pool as a json array of string transaction ids.\n"
- "\nResult:\n"
- "[ (json array of string)\n"
+ "\nArguments:\n"
+ "1. verbose (boolean, optional, default=false) true for a json object, false for array of transaction ids\n"
+ "\nResult: (for verbose = false):\n"
+ "[ (json array of string)\n"
" \"transactionid\" (string) The transaction id\n"
" ,...\n"
"]\n"
+ "\nResult: (for verbose = true):\n"
+ "{ (json object)\n"
+ " \"transactionid\" : { (json object)\n"
+ " \"size\" : n, (numeric) transaction size in bytes\n"
+ " \"fee\" : n, (numeric) transaction fee in bitcoins\n"
+ " \"time\" : n, (numeric) local time transaction entered pool in seconds since 1 Jan 1970 GMT\n"
+ " \"height\" : n, (numeric) block height when transaction entered pool\n"
+ " \"startingpriority\" : n, (numeric) priority when transaction entered pool\n"
+ " \"currentpriority\" : n, (numeric) transaction priority now\n"
+ " \"depends\" : [ (array) unconfirmed transactions used as inputs for this transaction\n"
+ " \"transactionid\", (string) parent transaction id\n"
+ " ... ]\n"
+ " }, ...\n"
+ "]\n"
"\nExamples\n"
- + HelpExampleCli("getrawmempool", "")
- + HelpExampleRpc("getrawmempool", "")
+ + HelpExampleCli("getrawmempool", "true")
+ + HelpExampleRpc("getrawmempool", "true")
);
- vector<uint256> vtxid;
- mempool.queryHashes(vtxid);
+ bool fVerbose = false;
+ if (params.size() > 0)
+ fVerbose = params[0].get_bool();
+
+ if (fVerbose)
+ {
+ LOCK(mempool.cs);
+ Object o;
+ BOOST_FOREACH(const PAIRTYPE(uint256, CTxMemPoolEntry)& entry, mempool.mapTx)
+ {
+ const uint256& hash = entry.first;
+ const CTxMemPoolEntry& e = entry.second;
+ Object info;
+ info.push_back(Pair("size", (int)e.GetTxSize()));
+ info.push_back(Pair("fee", ValueFromAmount(e.GetFee())));
+ info.push_back(Pair("time", (boost::int64_t)e.GetTime()));
+ info.push_back(Pair("height", (int)e.GetHeight()));
+ info.push_back(Pair("startingpriority", e.GetPriority(e.GetHeight())));
+ info.push_back(Pair("currentpriority", e.GetPriority(chainActive.Height())));
+ const CTransaction& tx = e.GetTx();
+ set<string> setDepends;
+ BOOST_FOREACH(const CTxIn& txin, tx.vin)
+ {
+ if (mempool.exists(txin.prevout.hash))
+ setDepends.insert(txin.prevout.hash.ToString());
+ }
+ Array depends(setDepends.begin(), setDepends.end());
+ info.push_back(Pair("depends", depends));
+ o.push_back(Pair(hash.ToString(), info));
+ }
+ return o;
+ }
+ else
+ {
+ vector<uint256> vtxid;
+ mempool.queryHashes(vtxid);
- Array a;
- BOOST_FOREACH(const uint256& hash, vtxid)
- a.push_back(hash.ToString());
+ Array a;
+ BOOST_FOREACH(const uint256& hash, vtxid)
+ a.push_back(hash.ToString());
- return a;
+ return a;
+ }
}
Value getblockhash(const Array& params, bool fHelp)
diff --git a/src/rpcclient.cpp b/src/rpcclient.cpp
new file mode 100644
index 0000000000..a3168917fc
--- /dev/null
+++ b/src/rpcclient.cpp
@@ -0,0 +1,279 @@
+// Copyright (c) 2010 Satoshi Nakamoto
+// 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 "rpcclient.h"
+
+#include "rpcprotocol.h"
+#include "util.h"
+#include "ui_interface.h"
+#include "chainparams.h" // for Params().RPCPort()
+
+#include <stdint.h>
+
+#include <boost/algorithm/string.hpp>
+#include <boost/asio.hpp>
+#include <boost/asio/ssl.hpp>
+#include <boost/bind.hpp>
+#include <boost/filesystem.hpp>
+#include <boost/foreach.hpp>
+#include <boost/iostreams/concepts.hpp>
+#include <boost/iostreams/stream.hpp>
+#include <boost/lexical_cast.hpp>
+#include <boost/shared_ptr.hpp>
+#include "json/json_spirit_writer_template.h"
+
+using namespace std;
+using namespace boost;
+using namespace boost::asio;
+using namespace json_spirit;
+
+Object CallRPC(const string& strMethod, const Array& params)
+{
+ if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
+ throw runtime_error(strprintf(
+ _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
+ "If the file does not exist, create it with owner-readable-only file permissions."),
+ GetConfigFile().string().c_str()));
+
+ // Connect to localhost
+ bool fUseSSL = GetBoolArg("-rpcssl", false);
+ asio::io_service io_service;
+ ssl::context context(io_service, ssl::context::sslv23);
+ context.set_options(ssl::context::no_sslv2);
+ asio::ssl::stream<asio::ip::tcp::socket> sslStream(io_service, context);
+ SSLIOStreamDevice<asio::ip::tcp> d(sslStream, fUseSSL);
+ iostreams::stream< SSLIOStreamDevice<asio::ip::tcp> > stream(d);
+
+ bool fWait = GetBoolArg("-rpcwait", false); // -rpcwait means try until server has started
+ do {
+ bool fConnected = d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", itostr(Params().RPCPort())));
+ if (fConnected) break;
+ if (fWait)
+ MilliSleep(1000);
+ else
+ throw runtime_error("couldn't connect to server");
+ } while (fWait);
+
+ // HTTP basic authentication
+ string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
+ map<string, string> mapRequestHeaders;
+ mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
+
+ // Send request
+ string strRequest = JSONRPCRequest(strMethod, params, 1);
+ string strPost = HTTPPost(strRequest, mapRequestHeaders);
+ stream << strPost << std::flush;
+
+ // Receive HTTP reply status
+ int nProto = 0;
+ int nStatus = ReadHTTPStatus(stream, nProto);
+
+ // Receive HTTP reply message headers and body
+ map<string, string> mapHeaders;
+ string strReply;
+ ReadHTTPMessage(stream, mapHeaders, strReply, nProto);
+
+ if (nStatus == HTTP_UNAUTHORIZED)
+ throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
+ else if (nStatus >= 400 && nStatus != HTTP_BAD_REQUEST && nStatus != HTTP_NOT_FOUND && nStatus != HTTP_INTERNAL_SERVER_ERROR)
+ throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
+ else if (strReply.empty())
+ throw runtime_error("no response from server");
+
+ // Parse reply
+ Value valReply;
+ if (!read_string(strReply, valReply))
+ throw runtime_error("couldn't parse reply from server");
+ const Object& reply = valReply.get_obj();
+ if (reply.empty())
+ throw runtime_error("expected reply to have result, error and id properties");
+
+ return reply;
+}
+
+template<typename T>
+void ConvertTo(Value& value, bool fAllowNull=false)
+{
+ if (fAllowNull && value.type() == null_type)
+ return;
+ if (value.type() == str_type)
+ {
+ // reinterpret string as unquoted json value
+ Value value2;
+ string strJSON = value.get_str();
+ if (!read_string(strJSON, value2))
+ throw runtime_error(string("Error parsing JSON:")+strJSON);
+ ConvertTo<T>(value2, fAllowNull);
+ value = value2;
+ }
+ else
+ {
+ value = value.get_value<T>();
+ }
+}
+
+// Convert strings to command-specific RPC representation
+Array RPCConvertValues(const std::string &strMethod, const std::vector<std::string> &strParams)
+{
+ Array params;
+ BOOST_FOREACH(const std::string &param, strParams)
+ params.push_back(param);
+
+ int n = params.size();
+
+ //
+ // Special case non-string parameter types
+ //
+ if (strMethod == "stop" && n > 0) ConvertTo<bool>(params[0]);
+ 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]);
+ if (strMethod == "getreceivedbyaccount" && n > 1) ConvertTo<boost::int64_t>(params[1]);
+ if (strMethod == "listreceivedbyaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
+ if (strMethod == "listreceivedbyaddress" && n > 1) ConvertTo<bool>(params[1]);
+ if (strMethod == "listreceivedbyaccount" && n > 0) ConvertTo<boost::int64_t>(params[0]);
+ if (strMethod == "listreceivedbyaccount" && n > 1) ConvertTo<bool>(params[1]);
+ if (strMethod == "getbalance" && n > 1) ConvertTo<boost::int64_t>(params[1]);
+ if (strMethod == "getblockhash" && n > 0) ConvertTo<boost::int64_t>(params[0]);
+ if (strMethod == "move" && n > 2) ConvertTo<double>(params[2]);
+ if (strMethod == "move" && n > 3) ConvertTo<boost::int64_t>(params[3]);
+ if (strMethod == "sendfrom" && n > 2) ConvertTo<double>(params[2]);
+ if (strMethod == "sendfrom" && n > 3) ConvertTo<boost::int64_t>(params[3]);
+ if (strMethod == "listtransactions" && n > 1) ConvertTo<boost::int64_t>(params[1]);
+ if (strMethod == "listtransactions" && n > 2) ConvertTo<boost::int64_t>(params[2]);
+ if (strMethod == "listaccounts" && n > 0) ConvertTo<boost::int64_t>(params[0]);
+ if (strMethod == "walletpassphrase" && n > 1) ConvertTo<boost::int64_t>(params[1]);
+ if (strMethod == "getblocktemplate" && n > 0) ConvertTo<Object>(params[0]);
+ if (strMethod == "listsinceblock" && n > 1) ConvertTo<boost::int64_t>(params[1]);
+ if (strMethod == "sendmany" && n > 1) ConvertTo<Object>(params[1]);
+ if (strMethod == "sendmany" && n > 2) ConvertTo<boost::int64_t>(params[2]);
+ if (strMethod == "addmultisigaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
+ if (strMethod == "addmultisigaddress" && n > 1) ConvertTo<Array>(params[1]);
+ if (strMethod == "createmultisig" && n > 0) ConvertTo<boost::int64_t>(params[0]);
+ if (strMethod == "createmultisig" && n > 1) ConvertTo<Array>(params[1]);
+ if (strMethod == "listunspent" && n > 0) ConvertTo<boost::int64_t>(params[0]);
+ if (strMethod == "listunspent" && n > 1) ConvertTo<boost::int64_t>(params[1]);
+ if (strMethod == "listunspent" && n > 2) ConvertTo<Array>(params[2]);
+ if (strMethod == "getblock" && n > 1) ConvertTo<bool>(params[1]);
+ if (strMethod == "getrawtransaction" && n > 1) ConvertTo<boost::int64_t>(params[1]);
+ if (strMethod == "createrawtransaction" && n > 0) ConvertTo<Array>(params[0]);
+ if (strMethod == "createrawtransaction" && n > 1) ConvertTo<Object>(params[1]);
+ if (strMethod == "signrawtransaction" && n > 1) ConvertTo<Array>(params[1], true);
+ if (strMethod == "signrawtransaction" && n > 2) ConvertTo<Array>(params[2], true);
+ if (strMethod == "sendrawtransaction" && n > 1) ConvertTo<bool>(params[1], true);
+ if (strMethod == "gettxout" && n > 1) ConvertTo<boost::int64_t>(params[1]);
+ if (strMethod == "gettxout" && n > 2) ConvertTo<bool>(params[2]);
+ if (strMethod == "lockunspent" && n > 0) ConvertTo<bool>(params[0]);
+ if (strMethod == "lockunspent" && n > 1) ConvertTo<Array>(params[1]);
+ if (strMethod == "importprivkey" && n > 2) ConvertTo<bool>(params[2]);
+ if (strMethod == "verifychain" && n > 0) ConvertTo<boost::int64_t>(params[0]);
+ if (strMethod == "verifychain" && n > 1) ConvertTo<boost::int64_t>(params[1]);
+ if (strMethod == "keypoolrefill" && n > 0) ConvertTo<boost::int64_t>(params[0]);
+ if (strMethod == "getrawmempool" && n > 0) ConvertTo<bool>(params[0]);
+
+ return params;
+}
+
+int CommandLineRPC(int argc, char *argv[])
+{
+ string strPrint;
+ int nRet = 0;
+ try
+ {
+ // Skip switches
+ while (argc > 1 && IsSwitchChar(argv[1][0]))
+ {
+ argc--;
+ argv++;
+ }
+
+ // Method
+ if (argc < 2)
+ throw runtime_error("too few parameters");
+ string strMethod = argv[1];
+
+ // Parameters default to strings
+ std::vector<std::string> strParams(&argv[2], &argv[argc]);
+ Array params = RPCConvertValues(strMethod, strParams);
+
+ // Execute
+ Object reply = CallRPC(strMethod, params);
+
+ // Parse reply
+ const Value& result = find_value(reply, "result");
+ const Value& error = find_value(reply, "error");
+
+ if (error.type() != null_type)
+ {
+ // Error
+ strPrint = "error: " + write_string(error, false);
+ int code = find_value(error.get_obj(), "code").get_int();
+ nRet = abs(code);
+ }
+ else
+ {
+ // Result
+ if (result.type() == null_type)
+ strPrint = "";
+ else if (result.type() == str_type)
+ strPrint = result.get_str();
+ else
+ strPrint = write_string(result, true);
+ }
+ }
+ catch (boost::thread_interrupted) {
+ throw;
+ }
+ catch (std::exception& e) {
+ strPrint = string("error: ") + e.what();
+ nRet = 87;
+ }
+ catch (...) {
+ PrintException(NULL, "CommandLineRPC()");
+ }
+
+ if (strPrint != "")
+ {
+ fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
+ }
+ return nRet;
+}
+
+std::string HelpMessageCli(bool mainProgram)
+{
+ string strUsage;
+ if(mainProgram)
+ {
+ strUsage += _("Options:") + "\n";
+ strUsage += " -? " + _("This help message") + "\n";
+ strUsage += " -conf=<file> " + _("Specify configuration file (default: bitcoin.conf)") + "\n";
+ strUsage += " -datadir=<dir> " + _("Specify data directory") + "\n";
+ strUsage += " -testnet " + _("Use the test network") + "\n";
+ strUsage += " -regtest " + _("Enter regression test mode, which uses a special chain in which blocks can be "
+ "solved instantly. This is intended for regression testing tools and app development.") + "\n";
+ } else {
+ strUsage += _("RPC client options:") + "\n";
+ }
+
+ strUsage += " -rpcconnect=<ip> " + _("Send commands to node running on <ip> (default: 127.0.0.1)") + "\n";
+ strUsage += " -rpcport=<port> " + _("Connect to JSON-RPC on <port> (default: 8332 or testnet: 18332)") + "\n";
+ strUsage += " -rpcwait " + _("Wait for RPC server to start") + "\n";
+ strUsage += " -rpcuser=<user> " + _("Username for JSON-RPC connections") + "\n";
+ strUsage += " -rpcpassword=<pw> " + _("Password for JSON-RPC connections") + "\n";
+
+ if(mainProgram)
+ {
+ strUsage += "\n" + _("SSL options: (see the Bitcoin Wiki for SSL setup instructions)") + "\n";
+ strUsage += " -rpcssl " + _("Use OpenSSL (https) for JSON-RPC connections") + "\n";
+ }
+
+ return strUsage;
+}
+
diff --git a/src/rpcclient.h b/src/rpcclient.h
new file mode 100644
index 0000000000..e101d22ec5
--- /dev/null
+++ b/src/rpcclient.h
@@ -0,0 +1,25 @@
+// Copyright (c) 2010 Satoshi Nakamoto
+// 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.
+
+#ifndef _BITCOINRPC_CLIENT_H_
+#define _BITCOINRPC_CLIENT_H_ 1
+
+#include "json/json_spirit_reader_template.h"
+#include "json/json_spirit_utils.h"
+#include "json/json_spirit_writer_template.h"
+
+int CommandLineRPC(int argc, char *argv[]);
+
+json_spirit::Array RPCConvertValues(const std::string &strMethod, const std::vector<std::string> &strParams);
+
+/** Show help message for bitcoin-cli.
+ * The mainProgram argument is used to determine whether to show this message as main program
+ * (and include some common options) or as sub-header of another help message.
+ *
+ * @note the argument can be removed once bitcoin-cli functionality is removed from bitcoind
+ */
+std::string HelpMessageCli(bool mainProgram);
+
+#endif
diff --git a/src/rpcdump.cpp b/src/rpcdump.cpp
index 53cec9a6fa..92f4c2c6dd 100644
--- a/src/rpcdump.cpp
+++ b/src/rpcdump.cpp
@@ -2,10 +2,8 @@
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-
#include "base58.h"
-#include "bitcoinrpc.h"
+#include "rpcserver.h"
#include "init.h"
#include "main.h"
#include "sync.h"
diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp
index e4fa7ed853..131a258c84 100644
--- a/src/rpcmining.cpp
+++ b/src/rpcmining.cpp
@@ -3,7 +3,7 @@
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "bitcoinrpc.h"
+#include "rpcserver.h"
#include "chainparams.h"
#include "db.h"
#include "init.h"
@@ -133,6 +133,7 @@ Value setgenerate(const Array& params, bool fHelp)
"\nArguments:\n"
"1. generate (boolean, required) Set to true to turn on generation, off to turn off.\n"
"2. genproclimit (numeric, optional) Set the processor limit for when generation is on. Can be -1 for unlimited.\n"
+ " Note: in -regtest mode, genproclimit controls how many blocks are generated immediately.\n"
"\nExamples:\n"
"\nSet the generation on with a limit of one processor\n"
+ HelpExampleCli("setgenerate", "true 1") +
@@ -144,21 +145,55 @@ Value setgenerate(const Array& params, bool fHelp)
+ HelpExampleRpc("setgenerate", "true, 1")
);
+ if (pwalletMain == NULL)
+ throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found (disabled)");
+
bool fGenerate = true;
if (params.size() > 0)
fGenerate = params[0].get_bool();
+ int nGenProcLimit = -1;
if (params.size() > 1)
{
- int nGenProcLimit = params[1].get_int();
- mapArgs["-genproclimit"] = itostr(nGenProcLimit);
+ nGenProcLimit = params[1].get_int();
if (nGenProcLimit == 0)
fGenerate = false;
}
- mapArgs["-gen"] = (fGenerate ? "1" : "0");
- assert(pwalletMain != NULL);
- GenerateBitcoins(fGenerate, pwalletMain);
+ // -regtest mode: don't return until nGenProcLimit blocks are generated
+ if (fGenerate && Params().NetworkID() == CChainParams::REGTEST)
+ {
+ int nHeightStart = 0;
+ int nHeightEnd = 0;
+ int nHeight = 0;
+ int nGenerate = (nGenProcLimit > 0 ? nGenProcLimit : 1);
+ { // Don't keep cs_main locked
+ LOCK(cs_main);
+ nHeightStart = chainActive.Height();
+ nHeight = nHeightStart;
+ nHeightEnd = nHeightStart+nGenerate;
+ }
+ int nHeightLast = -1;
+ while (nHeight < nHeightEnd)
+ {
+ if (nHeightLast != nHeight)
+ {
+ nHeightLast = nHeight;
+ GenerateBitcoins(fGenerate, pwalletMain, 1);
+ }
+ MilliSleep(1);
+ { // Don't keep cs_main locked
+ LOCK(cs_main);
+ nHeight = chainActive.Height();
+ }
+ }
+ }
+ else // Not -regtest: start generate thread, return immediately
+ {
+ mapArgs["-gen"] = (fGenerate ? "1" : "0");
+ GenerateBitcoins(fGenerate, pwalletMain, nGenProcLimit);
+ }
+
return Value::null;
}
diff --git a/src/rpcnet.cpp b/src/rpcnet.cpp
index 9f8dea80b0..93811e80ed 100644
--- a/src/rpcnet.cpp
+++ b/src/rpcnet.cpp
@@ -1,15 +1,20 @@
// 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 "rpcserver.h"
-
-#include "bitcoinrpc.h"
+#include "main.h"
#include "net.h"
#include "netbase.h"
#include "protocol.h"
#include "sync.h"
#include "util.h"
+#ifdef ENABLE_WALLET
+#include "wallet.h" // for getinfo
+#include "init.h" // for getinfo
+#endif
+#include "main.h" // for getinfo
#include <inttypes.h>
@@ -112,7 +117,8 @@ Value getpeerinfo(const Array& params, bool fHelp)
BOOST_FOREACH(const CNodeStats& stats, vstats) {
Object obj;
-
+ CNodeStateStats statestats;
+ bool fStateStats = GetNodeStateStats(stats.nodeid, statestats);
obj.push_back(Pair("addr", stats.addrName));
if (!(stats.addrLocal.empty()))
obj.push_back(Pair("addrlocal", stats.addrLocal));
@@ -126,10 +132,15 @@ Value getpeerinfo(const Array& params, bool fHelp)
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));
+ // Use the sanitized form of subver here, to avoid tricksy remote peers from
+ // corrupting or modifiying the JSON output by putting special characters in
+ // their ver message.
+ obj.push_back(Pair("subver", stats.cleanSubVer));
obj.push_back(Pair("inbound", stats.fInbound));
obj.push_back(Pair("startingheight", stats.nStartingHeight));
- obj.push_back(Pair("banscore", stats.nMisbehavior));
+ if (fStateStats) {
+ obj.push_back(Pair("banscore", statestats.nMisbehavior));
+ }
if (stats.fSyncNode)
obj.push_back(Pair("syncnode", true));
@@ -314,7 +325,7 @@ Value getnettotals(const Array& params, bool fHelp)
"\nResult:\n"
"{\n"
" \"totalbytesrecv\": n, (numeric) Total bytes received\n"
- " \"totalbytessent\": n, (numeric) Total Bytes sent\n"
+ " \"totalbytessent\": n, (numeric) Total bytes sent\n"
" \"timemillis\": t (numeric) Total cpu time\n"
"}\n"
"\nExamples:\n"
@@ -328,3 +339,65 @@ Value getnettotals(const Array& params, bool fHelp)
obj.push_back(Pair("timemillis", static_cast<boost::int64_t>(GetTimeMillis())));
return obj;
}
+
+Value getinfo(const Array& params, bool fHelp)
+{
+ if (fHelp || params.size() != 0)
+ throw runtime_error(
+ "getinfo\n"
+ "Returns an object containing various state info.\n"
+ "\nResult:\n"
+ "{\n"
+ " \"version\": xxxxx, (numeric) the server version\n"
+ " \"protocolversion\": xxxxx, (numeric) the protocol version\n"
+ " \"walletversion\": xxxxx, (numeric) the wallet version\n"
+ " \"balance\": xxxxxxx, (numeric) the total bitcoin balance of the wallet\n"
+ " \"blocks\": xxxxxx, (numeric) the current number of blocks processed in the server\n"
+ " \"timeoffset\": xxxxx, (numeric) the time offset\n"
+ " \"connections\": xxxxx, (numeric) the number of connections\n"
+ " \"proxy\": \"host:port\", (string, optional) the proxy used by the server\n"
+ " \"difficulty\": xxxxxx, (numeric) the current difficulty\n"
+ " \"testnet\": true|false, (boolean) if the server is using testnet or not\n"
+ " \"keypoololdest\": xxxxxx, (numeric) the timestamp (seconds since GMT epoch) of the oldest pre-generated key in the key pool\n"
+ " \"keypoolsize\": xxxx, (numeric) how many new keys are pre-generated\n"
+ " \"paytxfee\": x.xxxx, (numeric) the transaction fee set in btc\n"
+ " \"unlocked_until\": ttt, (numeric) the timestamp in seconds since epoch (midnight Jan 1 1970 GMT) that the wallet is unlocked for transfers, or 0 if the wallet is locked\n"
+ " \"errors\": \"...\" (string) any error messages\n"
+ "}\n"
+ "\nExamples:\n"
+ + HelpExampleCli("getinfo", "")
+ + HelpExampleRpc("getinfo", "")
+ );
+
+ proxyType proxy;
+ GetProxy(NET_IPV4, proxy);
+
+ Object obj;
+ obj.push_back(Pair("version", (int)CLIENT_VERSION));
+ obj.push_back(Pair("protocolversion",(int)PROTOCOL_VERSION));
+#ifdef ENABLE_WALLET
+ if (pwalletMain) {
+ obj.push_back(Pair("walletversion", pwalletMain->GetVersion()));
+ obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
+ }
+#endif
+ 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()));
+#ifdef ENABLE_WALLET
+ if (pwalletMain) {
+ obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime()));
+ obj.push_back(Pair("keypoolsize", (int)pwalletMain->GetKeyPoolSize()));
+ }
+#endif
+ obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee)));
+#ifdef ENABLE_WALLET
+ if (pwalletMain && pwalletMain->IsCrypted())
+ obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime));
+#endif
+ obj.push_back(Pair("errors", GetWarnings("statusbar")));
+ return obj;
+}
diff --git a/src/rpcprotocol.cpp b/src/rpcprotocol.cpp
new file mode 100644
index 0000000000..4a2241edaa
--- /dev/null
+++ b/src/rpcprotocol.cpp
@@ -0,0 +1,262 @@
+// Copyright (c) 2010 Satoshi Nakamoto
+// 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 "rpcprotocol.h"
+
+#include "util.h"
+
+#include <stdint.h>
+
+#include <boost/algorithm/string.hpp>
+#include <boost/asio.hpp>
+#include <boost/asio/ssl.hpp>
+#include <boost/bind.hpp>
+#include <boost/filesystem.hpp>
+#include <boost/foreach.hpp>
+#include <boost/iostreams/concepts.hpp>
+#include <boost/iostreams/stream.hpp>
+#include <boost/lexical_cast.hpp>
+#include <boost/shared_ptr.hpp>
+#include "json/json_spirit_writer_template.h"
+
+using namespace std;
+using namespace boost;
+using namespace boost::asio;
+using namespace json_spirit;
+
+//
+// HTTP protocol
+//
+// This ain't Apache. We're just using HTTP header for the length field
+// and to be compatible with other JSON-RPC implementations.
+//
+
+string HTTPPost(const string& strMsg, const map<string,string>& mapRequestHeaders)
+{
+ ostringstream s;
+ s << "POST / HTTP/1.1\r\n"
+ << "User-Agent: bitcoin-json-rpc/" << FormatFullVersion() << "\r\n"
+ << "Host: 127.0.0.1\r\n"
+ << "Content-Type: application/json\r\n"
+ << "Content-Length: " << strMsg.size() << "\r\n"
+ << "Connection: close\r\n"
+ << "Accept: application/json\r\n";
+ BOOST_FOREACH(const PAIRTYPE(string, string)& item, mapRequestHeaders)
+ s << item.first << ": " << item.second << "\r\n";
+ s << "\r\n" << strMsg;
+
+ return s.str();
+}
+
+static string rfc1123Time()
+{
+ char buffer[64];
+ time_t now;
+ time(&now);
+ struct tm* now_gmt = gmtime(&now);
+ string locale(setlocale(LC_TIME, NULL));
+ setlocale(LC_TIME, "C"); // we want POSIX (aka "C") weekday/month strings
+ strftime(buffer, sizeof(buffer), "%a, %d %b %Y %H:%M:%S +0000", now_gmt);
+ setlocale(LC_TIME, locale.c_str());
+ return string(buffer);
+}
+
+string HTTPReply(int nStatus, const string& strMsg, bool keepalive)
+{
+ if (nStatus == HTTP_UNAUTHORIZED)
+ return strprintf("HTTP/1.0 401 Authorization Required\r\n"
+ "Date: %s\r\n"
+ "Server: bitcoin-json-rpc/%s\r\n"
+ "WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"
+ "Content-Type: text/html\r\n"
+ "Content-Length: 296\r\n"
+ "\r\n"
+ "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"
+ "\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\">\r\n"
+ "<HTML>\r\n"
+ "<HEAD>\r\n"
+ "<TITLE>Error</TITLE>\r\n"
+ "<META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=ISO-8859-1'>\r\n"
+ "</HEAD>\r\n"
+ "<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
+ "</HTML>\r\n", rfc1123Time().c_str(), FormatFullVersion().c_str());
+ const char *cStatus;
+ if (nStatus == HTTP_OK) cStatus = "OK";
+ else if (nStatus == HTTP_BAD_REQUEST) cStatus = "Bad Request";
+ else if (nStatus == HTTP_FORBIDDEN) cStatus = "Forbidden";
+ else if (nStatus == HTTP_NOT_FOUND) cStatus = "Not Found";
+ else if (nStatus == HTTP_INTERNAL_SERVER_ERROR) cStatus = "Internal Server Error";
+ else cStatus = "";
+ return strprintf(
+ "HTTP/1.1 %d %s\r\n"
+ "Date: %s\r\n"
+ "Connection: %s\r\n"
+ "Content-Length: %"PRIszu"\r\n"
+ "Content-Type: application/json\r\n"
+ "Server: bitcoin-json-rpc/%s\r\n"
+ "\r\n"
+ "%s",
+ nStatus,
+ cStatus,
+ rfc1123Time().c_str(),
+ keepalive ? "keep-alive" : "close",
+ strMsg.size(),
+ FormatFullVersion().c_str(),
+ strMsg.c_str());
+}
+
+bool ReadHTTPRequestLine(std::basic_istream<char>& stream, int &proto,
+ string& http_method, string& http_uri)
+{
+ string str;
+ getline(stream, str);
+
+ // HTTP request line is space-delimited
+ vector<string> vWords;
+ boost::split(vWords, str, boost::is_any_of(" "));
+ if (vWords.size() < 2)
+ return false;
+
+ // HTTP methods permitted: GET, POST
+ http_method = vWords[0];
+ if (http_method != "GET" && http_method != "POST")
+ return false;
+
+ // HTTP URI must be an absolute path, relative to current host
+ http_uri = vWords[1];
+ if (http_uri.size() == 0 || http_uri[0] != '/')
+ return false;
+
+ // parse proto, if present
+ string strProto = "";
+ if (vWords.size() > 2)
+ strProto = vWords[2];
+
+ proto = 0;
+ const char *ver = strstr(strProto.c_str(), "HTTP/1.");
+ if (ver != NULL)
+ proto = atoi(ver+7);
+
+ return true;
+}
+
+int ReadHTTPStatus(std::basic_istream<char>& stream, int &proto)
+{
+ string str;
+ getline(stream, str);
+ vector<string> vWords;
+ boost::split(vWords, str, boost::is_any_of(" "));
+ if (vWords.size() < 2)
+ return HTTP_INTERNAL_SERVER_ERROR;
+ proto = 0;
+ const char *ver = strstr(str.c_str(), "HTTP/1.");
+ if (ver != NULL)
+ proto = atoi(ver+7);
+ return atoi(vWords[1].c_str());
+}
+
+int ReadHTTPHeaders(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet)
+{
+ int nLen = 0;
+ while (true)
+ {
+ string str;
+ std::getline(stream, str);
+ if (str.empty() || str == "\r")
+ break;
+ string::size_type nColon = str.find(":");
+ if (nColon != string::npos)
+ {
+ string strHeader = str.substr(0, nColon);
+ boost::trim(strHeader);
+ boost::to_lower(strHeader);
+ string strValue = str.substr(nColon+1);
+ boost::trim(strValue);
+ mapHeadersRet[strHeader] = strValue;
+ if (strHeader == "content-length")
+ nLen = atoi(strValue.c_str());
+ }
+ }
+ return nLen;
+}
+
+
+int ReadHTTPMessage(std::basic_istream<char>& stream, map<string,
+ string>& mapHeadersRet, string& strMessageRet,
+ int nProto)
+{
+ mapHeadersRet.clear();
+ strMessageRet = "";
+
+ // Read header
+ int nLen = ReadHTTPHeaders(stream, mapHeadersRet);
+ if (nLen < 0 || nLen > (int)MAX_SIZE)
+ return HTTP_INTERNAL_SERVER_ERROR;
+
+ // Read message
+ if (nLen > 0)
+ {
+ vector<char> vch(nLen);
+ stream.read(&vch[0], nLen);
+ strMessageRet = string(vch.begin(), vch.end());
+ }
+
+ string sConHdr = mapHeadersRet["connection"];
+
+ if ((sConHdr != "close") && (sConHdr != "keep-alive"))
+ {
+ if (nProto >= 1)
+ mapHeadersRet["connection"] = "keep-alive";
+ else
+ mapHeadersRet["connection"] = "close";
+ }
+
+ return HTTP_OK;
+}
+
+//
+// JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility,
+// but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
+// unspecified (HTTP errors and contents of 'error').
+//
+// 1.0 spec: http://json-rpc.org/wiki/specification
+// 1.2 spec: http://groups.google.com/group/json-rpc/web/json-rpc-over-http
+// http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx
+//
+
+string JSONRPCRequest(const string& strMethod, const Array& params, const Value& id)
+{
+ Object request;
+ request.push_back(Pair("method", strMethod));
+ request.push_back(Pair("params", params));
+ request.push_back(Pair("id", id));
+ return write_string(Value(request), false) + "\n";
+}
+
+Object JSONRPCReplyObj(const Value& result, const Value& error, const Value& id)
+{
+ Object reply;
+ if (error.type() != null_type)
+ reply.push_back(Pair("result", Value::null));
+ else
+ reply.push_back(Pair("result", result));
+ reply.push_back(Pair("error", error));
+ reply.push_back(Pair("id", id));
+ return reply;
+}
+
+string JSONRPCReply(const Value& result, const Value& error, const Value& id)
+{
+ Object reply = JSONRPCReplyObj(result, error, id);
+ return write_string(Value(reply), false) + "\n";
+}
+
+Object JSONRPCError(int code, const string& message)
+{
+ Object error;
+ error.push_back(Pair("code", code));
+ error.push_back(Pair("message", message));
+ return error;
+}
diff --git a/src/rpcprotocol.h b/src/rpcprotocol.h
new file mode 100644
index 0000000000..6bf371e759
--- /dev/null
+++ b/src/rpcprotocol.h
@@ -0,0 +1,138 @@
+// Copyright (c) 2010 Satoshi Nakamoto
+// 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.
+
+#ifndef _BITCOINRPC_PROTOCOL_H_
+#define _BITCOINRPC_PROTOCOL_H_ 1
+
+#include <list>
+#include <map>
+#include <stdint.h>
+#include <string>
+#include <boost/iostreams/concepts.hpp>
+#include <boost/iostreams/stream.hpp>
+#include <boost/asio.hpp>
+#include <boost/asio/ssl.hpp>
+
+#include "json/json_spirit_reader_template.h"
+#include "json/json_spirit_utils.h"
+#include "json/json_spirit_writer_template.h"
+
+// HTTP status codes
+enum HTTPStatusCode
+{
+ HTTP_OK = 200,
+ HTTP_BAD_REQUEST = 400,
+ HTTP_UNAUTHORIZED = 401,
+ HTTP_FORBIDDEN = 403,
+ HTTP_NOT_FOUND = 404,
+ HTTP_INTERNAL_SERVER_ERROR = 500,
+};
+
+// Bitcoin RPC error codes
+enum RPCErrorCode
+{
+ // Standard JSON-RPC 2.0 errors
+ RPC_INVALID_REQUEST = -32600,
+ RPC_METHOD_NOT_FOUND = -32601,
+ RPC_INVALID_PARAMS = -32602,
+ RPC_INTERNAL_ERROR = -32603,
+ RPC_PARSE_ERROR = -32700,
+
+ // General application defined errors
+ RPC_MISC_ERROR = -1, // std::exception thrown in command handling
+ RPC_FORBIDDEN_BY_SAFE_MODE = -2, // Server is in safe mode, and command is not allowed in safe mode
+ RPC_TYPE_ERROR = -3, // Unexpected type was passed as parameter
+ RPC_INVALID_ADDRESS_OR_KEY = -5, // Invalid address or key
+ RPC_OUT_OF_MEMORY = -7, // Ran out of memory during operation
+ RPC_INVALID_PARAMETER = -8, // Invalid, missing or duplicate parameter
+ RPC_DATABASE_ERROR = -20, // Database error
+ RPC_DESERIALIZATION_ERROR = -22, // Error parsing or validating structure in raw format
+ RPC_SERVER_NOT_STARTED = -18, // RPC server was not started (StartRPCThreads() not called)
+
+ // P2P client errors
+ RPC_CLIENT_NOT_CONNECTED = -9, // Bitcoin is not connected
+ RPC_CLIENT_IN_INITIAL_DOWNLOAD = -10, // Still downloading initial blocks
+ RPC_CLIENT_NODE_ALREADY_ADDED = -23, // Node is already added
+ RPC_CLIENT_NODE_NOT_ADDED = -24, // Node has not been added before
+
+ // Wallet errors
+ RPC_WALLET_ERROR = -4, // Unspecified problem with wallet (key not found etc.)
+ RPC_WALLET_INSUFFICIENT_FUNDS = -6, // Not enough funds in wallet or account
+ RPC_WALLET_INVALID_ACCOUNT_NAME = -11, // Invalid account name
+ RPC_WALLET_KEYPOOL_RAN_OUT = -12, // Keypool ran out, call keypoolrefill first
+ RPC_WALLET_UNLOCK_NEEDED = -13, // Enter the wallet passphrase with walletpassphrase first
+ RPC_WALLET_PASSPHRASE_INCORRECT = -14, // The wallet passphrase entered was incorrect
+ RPC_WALLET_WRONG_ENC_STATE = -15, // Command given in wrong wallet encryption state (encrypting an encrypted wallet etc.)
+ RPC_WALLET_ENCRYPTION_FAILED = -16, // Failed to encrypt the wallet
+ RPC_WALLET_ALREADY_UNLOCKED = -17, // Wallet is already unlocked
+};
+
+//
+// IOStream device that speaks SSL but can also speak non-SSL
+//
+template <typename Protocol>
+class SSLIOStreamDevice : public boost::iostreams::device<boost::iostreams::bidirectional> {
+public:
+ SSLIOStreamDevice(boost::asio::ssl::stream<typename Protocol::socket> &streamIn, bool fUseSSLIn) : stream(streamIn)
+ {
+ fUseSSL = fUseSSLIn;
+ fNeedHandshake = fUseSSLIn;
+ }
+
+ void handshake(boost::asio::ssl::stream_base::handshake_type role)
+ {
+ if (!fNeedHandshake) return;
+ fNeedHandshake = false;
+ stream.handshake(role);
+ }
+ std::streamsize read(char* s, std::streamsize n)
+ {
+ handshake(boost::asio::ssl::stream_base::server); // HTTPS servers read first
+ if (fUseSSL) return stream.read_some(boost::asio::buffer(s, n));
+ return stream.next_layer().read_some(boost::asio::buffer(s, n));
+ }
+ std::streamsize write(const char* s, std::streamsize n)
+ {
+ handshake(boost::asio::ssl::stream_base::client); // HTTPS clients write first
+ if (fUseSSL) return boost::asio::write(stream, boost::asio::buffer(s, n));
+ return boost::asio::write(stream.next_layer(), boost::asio::buffer(s, n));
+ }
+ bool connect(const std::string& server, const std::string& port)
+ {
+ boost::asio::ip::tcp::resolver resolver(stream.get_io_service());
+ boost::asio::ip::tcp::resolver::query query(server.c_str(), port.c_str());
+ boost::asio::ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
+ boost::asio::ip::tcp::resolver::iterator end;
+ boost::system::error_code error = boost::asio::error::host_not_found;
+ while (error && endpoint_iterator != end)
+ {
+ stream.lowest_layer().close();
+ stream.lowest_layer().connect(*endpoint_iterator++, error);
+ }
+ if (error)
+ return false;
+ return true;
+ }
+
+private:
+ bool fNeedHandshake;
+ bool fUseSSL;
+ boost::asio::ssl::stream<typename Protocol::socket>& stream;
+};
+
+std::string HTTPPost(const std::string& strMsg, const std::map<std::string,std::string>& mapRequestHeaders);
+std::string HTTPReply(int nStatus, const std::string& strMsg, bool keepalive);
+bool ReadHTTPRequestLine(std::basic_istream<char>& stream, int &proto,
+ std::string& http_method, std::string& http_uri);
+int ReadHTTPStatus(std::basic_istream<char>& stream, int &proto);
+int ReadHTTPHeaders(std::basic_istream<char>& stream, std::map<std::string, std::string>& mapHeadersRet);
+int ReadHTTPMessage(std::basic_istream<char>& stream, std::map<std::string, std::string>& mapHeadersRet,
+ std::string& strMessageRet, int nProto);
+std::string JSONRPCRequest(const std::string& strMethod, const json_spirit::Array& params, const json_spirit::Value& id);
+json_spirit::Object JSONRPCReplyObj(const json_spirit::Value& result, const json_spirit::Value& error, const json_spirit::Value& id);
+std::string JSONRPCReply(const json_spirit::Value& result, const json_spirit::Value& error, const json_spirit::Value& id);
+json_spirit::Object JSONRPCError(int code, const std::string& message);
+
+#endif
diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp
index 2225e216d3..86025918ef 100644
--- a/src/rpcrawtransaction.cpp
+++ b/src/rpcrawtransaction.cpp
@@ -3,14 +3,17 @@
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-
#include "base58.h"
-#include "bitcoinrpc.h"
+#include "rpcserver.h"
#include "init.h"
#include "net.h"
#include "uint256.h"
+#include "core.h"
+#include "main.h"
+#include "keystore.h"
+#ifdef ENABLE_WALLET
#include "wallet.h"
+#endif
#include <stdint.h>
@@ -80,7 +83,7 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry)
out.push_back(Pair("value", ValueFromAmount(txout.nValue)));
out.push_back(Pair("n", (boost::int64_t)i));
Object o;
- ScriptPubKeyToJSON(txout.scriptPubKey, o, false);
+ ScriptPubKeyToJSON(txout.scriptPubKey, o, true);
out.push_back(Pair("scriptPubKey", o));
vout.push_back(out);
}
@@ -192,6 +195,7 @@ Value getrawtransaction(const Array& params, bool fHelp)
return result;
}
+#ifdef ENABLE_WALLET
Value listunspent(const Array& params, bool fHelp)
{
if (fHelp || params.size() > 3)
@@ -305,6 +309,7 @@ Value listunspent(const Array& params, bool fHelp)
return results;
}
+#endif
Value createrawtransaction(const Array& params, bool fHelp)
{
@@ -510,7 +515,9 @@ Value signrawtransaction(const Array& params, bool fHelp)
"this transaction depends on but may not yet be in the block chain.\n"
"The third optional argument (may be null) is an array of base58-encoded private\n"
"keys that, if given, will be the only keys used to sign the transaction.\n"
+#ifdef ENABLE_WALLET
+ HelpRequiringPassphrase() + "\n"
+#endif
"\nArguments:\n"
"1. \"hexstring\" (string, required) The transaction hex string\n"
@@ -607,8 +614,10 @@ Value signrawtransaction(const Array& params, bool fHelp)
tempKeystore.AddKey(key);
}
}
+#ifdef ENABLE_WALLET
else
EnsureWalletIsUnlocked();
+#endif
// Add previous txouts given in the RPC call:
if (params.size() > 1 && params[1].type() != null_type)
@@ -664,7 +673,11 @@ Value signrawtransaction(const Array& params, bool fHelp)
}
}
+#ifdef ENABLE_WALLET
const CKeyStore& keystore = ((fGivenKeys || !pwalletMain) ? tempKeystore : *pwalletMain);
+#else
+ const CKeyStore& keystore = tempKeystore;
+#endif
int nHashType = SIGHASH_ALL;
if (params.size() > 3 && params[3].type() != null_type)
diff --git a/src/bitcoinrpc.cpp b/src/rpcserver.cpp
index c715f13fd2..2dc7b34f88 100644
--- a/src/bitcoinrpc.cpp
+++ b/src/rpcserver.cpp
@@ -3,15 +3,16 @@
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "bitcoinrpc.h"
+#include "rpcserver.h"
#include "base58.h"
#include "init.h"
#include "main.h"
#include "util.h"
+#include "ui_interface.h"
+#ifdef ENABLE_WALLET
#include "wallet.h"
-
-#include <stdint.h>
+#endif
#include <boost/algorithm/string.hpp>
#include <boost/asio.hpp>
@@ -38,14 +39,6 @@ static map<string, boost::shared_ptr<deadline_timer> > deadlineTimers;
static ssl::context* rpc_ssl_context = NULL;
static boost::thread_group* rpc_worker_group = NULL;
-Object JSONRPCError(int code, const string& message)
-{
- Object error;
- error.push_back(Pair("code", code));
- error.push_back(Pair("message", message));
- return error;
-}
-
void RPCTypeCheck(const Array& params,
const list<Value_type>& typesExpected,
bool fAllowNull)
@@ -159,8 +152,10 @@ string CRPCTable::help(string strCommand) const
continue;
if (strCommand != "" && strMethod != strCommand)
continue;
+#ifdef ENABLE_WALLET
if (pcmd->reqWallet && !pwalletMain)
continue;
+#endif
try
{
@@ -238,11 +233,26 @@ static const CRPCCommand vRPCCommands[] =
{ "getaddednodeinfo", &getaddednodeinfo, true, true, false },
{ "getnettotals", &getnettotals, true, true, false },
{ "getdifficulty", &getdifficulty, true, false, false },
+ { "getinfo", &getinfo, true, false, false },
+ { "getrawmempool", &getrawmempool, true, false, false },
+ { "getblock", &getblock, false, false, false },
+ { "getblockhash", &getblockhash, false, false, false },
+ { "settxfee", &settxfee, 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 },
+ { "verifychain", &verifychain, true, false, false },
+
+#ifdef ENABLE_WALLET
{ "getnetworkhashps", &getnetworkhashps, true, false, false },
{ "getgenerate", &getgenerate, true, false, false },
- { "setgenerate", &setgenerate, true, false, true },
+ { "setgenerate", &setgenerate, true, true, false },
{ "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 },
@@ -268,9 +278,6 @@ static const CRPCCommand vRPCCommands[] =
{ "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 },
@@ -278,7 +285,6 @@ static const CRPCCommand vRPCCommands[] =
{ "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 },
@@ -287,17 +293,9 @@ static const CRPCCommand vRPCCommands[] =
{ "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 },
+#endif // ENABLE_WALLET
};
CRPCTable::CRPCTable()
@@ -320,194 +318,6 @@ const CRPCCommand *CRPCTable::operator[](string name) const
return (*it).second;
}
-//
-// HTTP protocol
-//
-// This ain't Apache. We're just using HTTP header for the length field
-// and to be compatible with other JSON-RPC implementations.
-//
-
-string HTTPPost(const string& strMsg, const map<string,string>& mapRequestHeaders)
-{
- ostringstream s;
- s << "POST / HTTP/1.1\r\n"
- << "User-Agent: bitcoin-json-rpc/" << FormatFullVersion() << "\r\n"
- << "Host: 127.0.0.1\r\n"
- << "Content-Type: application/json\r\n"
- << "Content-Length: " << strMsg.size() << "\r\n"
- << "Connection: close\r\n"
- << "Accept: application/json\r\n";
- BOOST_FOREACH(const PAIRTYPE(string, string)& item, mapRequestHeaders)
- s << item.first << ": " << item.second << "\r\n";
- s << "\r\n" << strMsg;
-
- return s.str();
-}
-
-string rfc1123Time()
-{
- char buffer[64];
- time_t now;
- time(&now);
- struct tm* now_gmt = gmtime(&now);
- string locale(setlocale(LC_TIME, NULL));
- setlocale(LC_TIME, "C"); // we want POSIX (aka "C") weekday/month strings
- strftime(buffer, sizeof(buffer), "%a, %d %b %Y %H:%M:%S +0000", now_gmt);
- setlocale(LC_TIME, locale.c_str());
- return string(buffer);
-}
-
-static string HTTPReply(int nStatus, const string& strMsg, bool keepalive)
-{
- if (nStatus == HTTP_UNAUTHORIZED)
- return strprintf("HTTP/1.0 401 Authorization Required\r\n"
- "Date: %s\r\n"
- "Server: bitcoin-json-rpc/%s\r\n"
- "WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"
- "Content-Type: text/html\r\n"
- "Content-Length: 296\r\n"
- "\r\n"
- "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"
- "\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\">\r\n"
- "<HTML>\r\n"
- "<HEAD>\r\n"
- "<TITLE>Error</TITLE>\r\n"
- "<META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=ISO-8859-1'>\r\n"
- "</HEAD>\r\n"
- "<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
- "</HTML>\r\n", rfc1123Time().c_str(), FormatFullVersion().c_str());
- const char *cStatus;
- if (nStatus == HTTP_OK) cStatus = "OK";
- else if (nStatus == HTTP_BAD_REQUEST) cStatus = "Bad Request";
- else if (nStatus == HTTP_FORBIDDEN) cStatus = "Forbidden";
- else if (nStatus == HTTP_NOT_FOUND) cStatus = "Not Found";
- else if (nStatus == HTTP_INTERNAL_SERVER_ERROR) cStatus = "Internal Server Error";
- else cStatus = "";
- return strprintf(
- "HTTP/1.1 %d %s\r\n"
- "Date: %s\r\n"
- "Connection: %s\r\n"
- "Content-Length: %"PRIszu"\r\n"
- "Content-Type: application/json\r\n"
- "Server: bitcoin-json-rpc/%s\r\n"
- "\r\n"
- "%s",
- nStatus,
- cStatus,
- rfc1123Time().c_str(),
- keepalive ? "keep-alive" : "close",
- strMsg.size(),
- FormatFullVersion().c_str(),
- strMsg.c_str());
-}
-
-bool ReadHTTPRequestLine(std::basic_istream<char>& stream, int &proto,
- string& http_method, string& http_uri)
-{
- string str;
- getline(stream, str);
-
- // HTTP request line is space-delimited
- vector<string> vWords;
- boost::split(vWords, str, boost::is_any_of(" "));
- if (vWords.size() < 2)
- return false;
-
- // HTTP methods permitted: GET, POST
- http_method = vWords[0];
- if (http_method != "GET" && http_method != "POST")
- return false;
-
- // HTTP URI must be an absolute path, relative to current host
- http_uri = vWords[1];
- if (http_uri.size() == 0 || http_uri[0] != '/')
- return false;
-
- // parse proto, if present
- string strProto = "";
- if (vWords.size() > 2)
- strProto = vWords[2];
-
- proto = 0;
- const char *ver = strstr(strProto.c_str(), "HTTP/1.");
- if (ver != NULL)
- proto = atoi(ver+7);
-
- return true;
-}
-
-int ReadHTTPStatus(std::basic_istream<char>& stream, int &proto)
-{
- string str;
- getline(stream, str);
- vector<string> vWords;
- boost::split(vWords, str, boost::is_any_of(" "));
- if (vWords.size() < 2)
- return HTTP_INTERNAL_SERVER_ERROR;
- proto = 0;
- const char *ver = strstr(str.c_str(), "HTTP/1.");
- if (ver != NULL)
- proto = atoi(ver+7);
- return atoi(vWords[1].c_str());
-}
-
-int ReadHTTPHeaders(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet)
-{
- int nLen = 0;
- while (true)
- {
- string str;
- std::getline(stream, str);
- if (str.empty() || str == "\r")
- break;
- string::size_type nColon = str.find(":");
- if (nColon != string::npos)
- {
- string strHeader = str.substr(0, nColon);
- boost::trim(strHeader);
- boost::to_lower(strHeader);
- string strValue = str.substr(nColon+1);
- boost::trim(strValue);
- mapHeadersRet[strHeader] = strValue;
- if (strHeader == "content-length")
- nLen = atoi(strValue.c_str());
- }
- }
- return nLen;
-}
-
-int ReadHTTPMessage(std::basic_istream<char>& stream, map<string,
- string>& mapHeadersRet, string& strMessageRet,
- int nProto)
-{
- mapHeadersRet.clear();
- strMessageRet = "";
-
- // Read header
- int nLen = ReadHTTPHeaders(stream, mapHeadersRet);
- if (nLen < 0 || nLen > (int)MAX_SIZE)
- return HTTP_INTERNAL_SERVER_ERROR;
-
- // Read message
- if (nLen > 0)
- {
- vector<char> vch(nLen);
- stream.read(&vch[0], nLen);
- strMessageRet = string(vch.begin(), vch.end());
- }
-
- string sConHdr = mapHeadersRet["connection"];
-
- if ((sConHdr != "close") && (sConHdr != "keep-alive"))
- {
- if (nProto >= 1)
- mapHeadersRet["connection"] = "keep-alive";
- else
- mapHeadersRet["connection"] = "close";
- }
-
- return HTTP_OK;
-}
bool HTTPAuthorized(map<string, string>& mapHeaders)
{
@@ -519,43 +329,6 @@ bool HTTPAuthorized(map<string, string>& mapHeaders)
return TimingResistantEqual(strUserPass, strRPCUserColonPass);
}
-//
-// JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility,
-// but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
-// unspecified (HTTP errors and contents of 'error').
-//
-// 1.0 spec: http://json-rpc.org/wiki/specification
-// 1.2 spec: http://groups.google.com/group/json-rpc/web/json-rpc-over-http
-// http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx
-//
-
-string JSONRPCRequest(const string& strMethod, const Array& params, const Value& id)
-{
- Object request;
- request.push_back(Pair("method", strMethod));
- request.push_back(Pair("params", params));
- request.push_back(Pair("id", id));
- return write_string(Value(request), false) + "\n";
-}
-
-Object JSONRPCReplyObj(const Value& result, const Value& error, const Value& id)
-{
- Object reply;
- if (error.type() != null_type)
- reply.push_back(Pair("result", Value::null));
- else
- reply.push_back(Pair("result", result));
- reply.push_back(Pair("error", error));
- reply.push_back(Pair("id", id));
- return reply;
-}
-
-string JSONRPCReply(const Value& result, const Value& error, const Value& id)
-{
- Object reply = JSONRPCReplyObj(result, error, id);
- return write_string(Value(reply), false) + "\n";
-}
-
void ErrorReply(std::ostream& stream, const Object& objError, const Value& id)
{
// Send error reply from json-rpc error object
@@ -590,59 +363,6 @@ bool ClientAllowed(const boost::asio::ip::address& address)
return false;
}
-//
-// IOStream device that speaks SSL but can also speak non-SSL
-//
-template <typename Protocol>
-class SSLIOStreamDevice : public iostreams::device<iostreams::bidirectional> {
-public:
- SSLIOStreamDevice(asio::ssl::stream<typename Protocol::socket> &streamIn, bool fUseSSLIn) : stream(streamIn)
- {
- fUseSSL = fUseSSLIn;
- fNeedHandshake = fUseSSLIn;
- }
-
- void handshake(ssl::stream_base::handshake_type role)
- {
- if (!fNeedHandshake) return;
- fNeedHandshake = false;
- stream.handshake(role);
- }
- std::streamsize read(char* s, std::streamsize n)
- {
- handshake(ssl::stream_base::server); // HTTPS servers read first
- if (fUseSSL) return stream.read_some(asio::buffer(s, n));
- return stream.next_layer().read_some(asio::buffer(s, n));
- }
- std::streamsize write(const char* s, std::streamsize n)
- {
- handshake(ssl::stream_base::client); // HTTPS clients write first
- if (fUseSSL) return asio::write(stream, asio::buffer(s, n));
- return asio::write(stream.next_layer(), asio::buffer(s, n));
- }
- bool connect(const std::string& server, const std::string& port)
- {
- ip::tcp::resolver resolver(stream.get_io_service());
- ip::tcp::resolver::query query(server.c_str(), port.c_str());
- ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
- ip::tcp::resolver::iterator end;
- boost::system::error_code error = asio::error::host_not_found;
- while (error && endpoint_iterator != end)
- {
- stream.lowest_layer().close();
- stream.lowest_layer().connect(*endpoint_iterator++, error);
- }
- if (error)
- return false;
- return true;
- }
-
-private:
- bool fNeedHandshake;
- bool fUseSSL;
- asio::ssl::stream<typename Protocol::socket>& stream;
-};
-
class AcceptedConnection
{
public:
@@ -722,6 +442,7 @@ static void RPCListen(boost::shared_ptr< basic_socket_acceptor<Protocol, SocketA
boost::asio::placeholders::error));
}
+
/**
* Accept and handle incoming connection.
*/
@@ -912,7 +633,6 @@ void RPCRunLater(const std::string& name, boost::function<void(void)> func, int6
deadlineTimers[name]->async_wait(boost::bind(RPCRunHandler, _1, func));
}
-
class JSONRequest
{
public:
@@ -954,6 +674,7 @@ void JSONRequest::parse(const Value& valRequest)
throw JSONRPCError(RPC_INVALID_REQUEST, "Params must be an array");
}
+
static Object JSONRPCExecOne(const Value& req)
{
Object rpc_result;
@@ -1075,8 +796,10 @@ 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");
+#ifdef ENABLE_WALLET
if (pcmd->reqWallet && !pwalletMain)
throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found (disabled)");
+#endif
// Observe safe mode
string strWarning = GetWarnings("rpc");
@@ -1091,6 +814,7 @@ json_spirit::Value CRPCTable::execute(const std::string &strMethod, const json_s
{
if (pcmd->threadSafe)
result = pcmd->actor(params, false);
+#ifdef ENABLE_WALLET
else if (!pwalletMain) {
LOCK(cs_main);
result = pcmd->actor(params, false);
@@ -1098,6 +822,12 @@ json_spirit::Value CRPCTable::execute(const std::string &strMethod, const json_s
LOCK2(cs_main, pwalletMain->cs_wallet);
result = pcmd->actor(params, false);
}
+#else // ENABLE_WALLET
+ else {
+ LOCK(cs_main);
+ result = pcmd->actor(params, false);
+ }
+#endif // !ENABLE_WALLET
}
return result;
}
@@ -1107,255 +837,13 @@ json_spirit::Value CRPCTable::execute(const std::string &strMethod, const json_s
}
}
-
-Object CallRPC(const string& strMethod, const Array& params)
-{
- if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
- throw runtime_error(strprintf(
- _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
- "If the file does not exist, create it with owner-readable-only file permissions."),
- GetConfigFile().string().c_str()));
-
- // Connect to localhost
- bool fUseSSL = GetBoolArg("-rpcssl", false);
- asio::io_service io_service;
- ssl::context context(io_service, ssl::context::sslv23);
- context.set_options(ssl::context::no_sslv2);
- asio::ssl::stream<asio::ip::tcp::socket> sslStream(io_service, context);
- SSLIOStreamDevice<asio::ip::tcp> d(sslStream, fUseSSL);
- iostreams::stream< SSLIOStreamDevice<asio::ip::tcp> > stream(d);
- if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", itostr(Params().RPCPort()))))
- throw runtime_error("couldn't connect to server");
-
- // HTTP basic authentication
- string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
- map<string, string> mapRequestHeaders;
- mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
-
- // Send request
- string strRequest = JSONRPCRequest(strMethod, params, 1);
- string strPost = HTTPPost(strRequest, mapRequestHeaders);
- stream << strPost << std::flush;
-
- // Receive HTTP reply status
- int nProto = 0;
- int nStatus = ReadHTTPStatus(stream, nProto);
-
- // Receive HTTP reply message headers and body
- map<string, string> mapHeaders;
- string strReply;
- ReadHTTPMessage(stream, mapHeaders, strReply, nProto);
-
- if (nStatus == HTTP_UNAUTHORIZED)
- throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
- else if (nStatus >= 400 && nStatus != HTTP_BAD_REQUEST && nStatus != HTTP_NOT_FOUND && nStatus != HTTP_INTERNAL_SERVER_ERROR)
- throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
- else if (strReply.empty())
- throw runtime_error("no response from server");
-
- // Parse reply
- Value valReply;
- if (!read_string(strReply, valReply))
- throw runtime_error("couldn't parse reply from server");
- const Object& reply = valReply.get_obj();
- if (reply.empty())
- throw runtime_error("expected reply to have result, error and id properties");
-
- return reply;
-}
-
-
-
-
-template<typename T>
-void ConvertTo(Value& value, bool fAllowNull=false)
-{
- if (fAllowNull && value.type() == null_type)
- return;
- if (value.type() == str_type)
- {
- // reinterpret string as unquoted json value
- Value value2;
- string strJSON = value.get_str();
- if (!read_string(strJSON, value2))
- throw runtime_error(string("Error parsing JSON:")+strJSON);
- ConvertTo<T>(value2, fAllowNull);
- value = value2;
- }
- else
- {
- value = value.get_value<T>();
- }
-}
-
-// Convert strings to command-specific RPC representation
-Array RPCConvertValues(const std::string &strMethod, const std::vector<std::string> &strParams)
-{
- Array params;
- BOOST_FOREACH(const std::string &param, strParams)
- params.push_back(param);
-
- int n = params.size();
-
- //
- // Special case non-string parameter types
- //
- if (strMethod == "stop" && n > 0) ConvertTo<bool>(params[0]);
- 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]);
- if (strMethod == "getreceivedbyaccount" && n > 1) ConvertTo<boost::int64_t>(params[1]);
- if (strMethod == "listreceivedbyaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
- if (strMethod == "listreceivedbyaddress" && n > 1) ConvertTo<bool>(params[1]);
- if (strMethod == "listreceivedbyaccount" && n > 0) ConvertTo<boost::int64_t>(params[0]);
- if (strMethod == "listreceivedbyaccount" && n > 1) ConvertTo<bool>(params[1]);
- if (strMethod == "getbalance" && n > 1) ConvertTo<boost::int64_t>(params[1]);
- if (strMethod == "getblockhash" && n > 0) ConvertTo<boost::int64_t>(params[0]);
- if (strMethod == "move" && n > 2) ConvertTo<double>(params[2]);
- if (strMethod == "move" && n > 3) ConvertTo<boost::int64_t>(params[3]);
- if (strMethod == "sendfrom" && n > 2) ConvertTo<double>(params[2]);
- if (strMethod == "sendfrom" && n > 3) ConvertTo<boost::int64_t>(params[3]);
- if (strMethod == "listtransactions" && n > 1) ConvertTo<boost::int64_t>(params[1]);
- if (strMethod == "listtransactions" && n > 2) ConvertTo<boost::int64_t>(params[2]);
- if (strMethod == "listaccounts" && n > 0) ConvertTo<boost::int64_t>(params[0]);
- if (strMethod == "walletpassphrase" && n > 1) ConvertTo<boost::int64_t>(params[1]);
- if (strMethod == "getblocktemplate" && n > 0) ConvertTo<Object>(params[0]);
- if (strMethod == "listsinceblock" && n > 1) ConvertTo<boost::int64_t>(params[1]);
- if (strMethod == "sendmany" && n > 1) ConvertTo<Object>(params[1]);
- if (strMethod == "sendmany" && n > 2) ConvertTo<boost::int64_t>(params[2]);
- if (strMethod == "addmultisigaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
- if (strMethod == "addmultisigaddress" && n > 1) ConvertTo<Array>(params[1]);
- if (strMethod == "createmultisig" && n > 0) ConvertTo<boost::int64_t>(params[0]);
- if (strMethod == "createmultisig" && n > 1) ConvertTo<Array>(params[1]);
- if (strMethod == "listunspent" && n > 0) ConvertTo<boost::int64_t>(params[0]);
- if (strMethod == "listunspent" && n > 1) ConvertTo<boost::int64_t>(params[1]);
- if (strMethod == "listunspent" && n > 2) ConvertTo<Array>(params[2]);
- if (strMethod == "getblock" && n > 1) ConvertTo<bool>(params[1]);
- if (strMethod == "getrawtransaction" && n > 1) ConvertTo<boost::int64_t>(params[1]);
- if (strMethod == "createrawtransaction" && n > 0) ConvertTo<Array>(params[0]);
- if (strMethod == "createrawtransaction" && n > 1) ConvertTo<Object>(params[1]);
- if (strMethod == "signrawtransaction" && n > 1) ConvertTo<Array>(params[1], true);
- if (strMethod == "signrawtransaction" && n > 2) ConvertTo<Array>(params[2], true);
- if (strMethod == "sendrawtransaction" && n > 1) ConvertTo<bool>(params[1], true);
- if (strMethod == "gettxout" && n > 1) ConvertTo<boost::int64_t>(params[1]);
- if (strMethod == "gettxout" && n > 2) ConvertTo<bool>(params[2]);
- if (strMethod == "lockunspent" && n > 0) ConvertTo<bool>(params[0]);
- if (strMethod == "lockunspent" && n > 1) ConvertTo<Array>(params[1]);
- if (strMethod == "importprivkey" && n > 2) ConvertTo<bool>(params[2]);
- if (strMethod == "verifychain" && n > 0) ConvertTo<boost::int64_t>(params[0]);
- if (strMethod == "verifychain" && n > 1) ConvertTo<boost::int64_t>(params[1]);
- if (strMethod == "keypoolrefill" && n > 0) ConvertTo<boost::int64_t>(params[0]);
-
- return params;
-}
-
-int CommandLineRPC(int argc, char *argv[])
-{
- string strPrint;
- int nRet = 0;
- try
- {
- // Skip switches
- while (argc > 1 && IsSwitchChar(argv[1][0]))
- {
- argc--;
- argv++;
- }
-
- // Method
- if (argc < 2)
- throw runtime_error("too few parameters");
- string strMethod = argv[1];
-
- // Parameters default to strings
- std::vector<std::string> strParams(&argv[2], &argv[argc]);
- Array params = RPCConvertValues(strMethod, strParams);
-
- // Execute
- Object reply = CallRPC(strMethod, params);
-
- // Parse reply
- const Value& result = find_value(reply, "result");
- const Value& error = find_value(reply, "error");
-
- if (error.type() != null_type)
- {
- // Error
- strPrint = "error: " + write_string(error, false);
- int code = find_value(error.get_obj(), "code").get_int();
- nRet = abs(code);
- }
- else
- {
- // Result
- if (result.type() == null_type)
- strPrint = "";
- else if (result.type() == str_type)
- strPrint = result.get_str();
- else
- strPrint = write_string(result, true);
- }
- }
- catch (boost::thread_interrupted) {
- throw;
- }
- catch (std::exception& e) {
- strPrint = string("error: ") + e.what();
- nRet = 87;
- }
- catch (...) {
- PrintException(NULL, "CommandLineRPC()");
- }
-
- if (strPrint != "")
- {
- fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
- }
- return nRet;
+std::string HelpExampleCli(string methodname, string args){
+ return "> bitcoin-cli " + methodname + " " + args + "\n";
}
-
-
-
-#ifdef TEST
-int main(int argc, char *argv[])
-{
-#ifdef _MSC_VER
- // Turn off Microsoft heap dump noise
- _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
- _CrtSetReportFile(_CRT_WARN, CreateFile("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
-#endif
- setbuf(stdin, NULL);
- setbuf(stdout, NULL);
- setbuf(stderr, NULL);
-
- try
- {
- if (argc >= 2 && string(argv[1]) == "-server")
- {
- LogPrintf("server ready\n");
- ThreadRPCServer(NULL);
- }
- else
- {
- return CommandLineRPC(argc, argv);
- }
- }
- catch (boost::thread_interrupted) {
- throw;
- }
- catch (std::exception& e) {
- PrintException(&e, "main()");
- } catch (...) {
- PrintException(NULL, "main()");
- }
- return 0;
+std::string HelpExampleRpc(string methodname, string args){
+ return "> curl --user myusername --data-binary '{\"jsonrpc\": \"1.0\", \"id\":\"curltest\", "
+ "\"method\": \"" + methodname + "\", \"params\": [" + args + "] }' -H 'content-type: text/plain;' http://127.0.0.1:8332/\n";
}
-#endif
const CRPCTable tableRPC;
diff --git a/src/bitcoinrpc.h b/src/rpcserver.h
index 9025ff9216..4d29e90c09 100644
--- a/src/bitcoinrpc.h
+++ b/src/rpcserver.h
@@ -3,10 +3,11 @@
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#ifndef _BITCOINRPC_H_
-#define _BITCOINRPC_H_ 1
+#ifndef _BITCOINRPC_SERVER_H_
+#define _BITCOINRPC_SERVER_H_ 1
#include "uint256.h"
+#include "rpcprotocol.h"
#include <list>
#include <map>
@@ -18,66 +19,9 @@
#include "json/json_spirit_writer_template.h"
class CBlockIndex;
-class CReserveKey;
-
-// HTTP status codes
-enum HTTPStatusCode
-{
- HTTP_OK = 200,
- HTTP_BAD_REQUEST = 400,
- HTTP_UNAUTHORIZED = 401,
- HTTP_FORBIDDEN = 403,
- HTTP_NOT_FOUND = 404,
- HTTP_INTERNAL_SERVER_ERROR = 500,
-};
-
-// Bitcoin RPC error codes
-enum RPCErrorCode
-{
- // Standard JSON-RPC 2.0 errors
- RPC_INVALID_REQUEST = -32600,
- RPC_METHOD_NOT_FOUND = -32601,
- RPC_INVALID_PARAMS = -32602,
- RPC_INTERNAL_ERROR = -32603,
- RPC_PARSE_ERROR = -32700,
-
- // General application defined errors
- RPC_MISC_ERROR = -1, // std::exception thrown in command handling
- RPC_FORBIDDEN_BY_SAFE_MODE = -2, // Server is in safe mode, and command is not allowed in safe mode
- RPC_TYPE_ERROR = -3, // Unexpected type was passed as parameter
- RPC_INVALID_ADDRESS_OR_KEY = -5, // Invalid address or key
- RPC_OUT_OF_MEMORY = -7, // Ran out of memory during operation
- RPC_INVALID_PARAMETER = -8, // Invalid, missing or duplicate parameter
- RPC_DATABASE_ERROR = -20, // Database error
- RPC_DESERIALIZATION_ERROR = -22, // Error parsing or validating structure in raw format
- RPC_SERVER_NOT_STARTED = -18, // RPC server was not started (StartRPCThreads() not called)
-
- // P2P client errors
- RPC_CLIENT_NOT_CONNECTED = -9, // Bitcoin is not connected
- RPC_CLIENT_IN_INITIAL_DOWNLOAD = -10, // Still downloading initial blocks
- RPC_CLIENT_NODE_ALREADY_ADDED = -23, // Node is already added
- RPC_CLIENT_NODE_NOT_ADDED = -24, // Node has not been added before
-
- // Wallet errors
- RPC_WALLET_ERROR = -4, // Unspecified problem with wallet (key not found etc.)
- RPC_WALLET_INSUFFICIENT_FUNDS = -6, // Not enough funds in wallet or account
- RPC_WALLET_INVALID_ACCOUNT_NAME = -11, // Invalid account name
- RPC_WALLET_KEYPOOL_RAN_OUT = -12, // Keypool ran out, call keypoolrefill first
- RPC_WALLET_UNLOCK_NEEDED = -13, // Enter the wallet passphrase with walletpassphrase first
- RPC_WALLET_PASSPHRASE_INCORRECT = -14, // The wallet passphrase entered was incorrect
- RPC_WALLET_WRONG_ENC_STATE = -15, // Command given in wrong wallet encryption state (encrypting an encrypted wallet etc.)
- RPC_WALLET_ENCRYPTION_FAILED = -16, // Failed to encrypt the wallet
- RPC_WALLET_ALREADY_UNLOCKED = -17, // Wallet is already unlocked
-};
-
-json_spirit::Object JSONRPCError(int code, const std::string& message);
void StartRPCThreads();
void StopRPCThreads();
-int CommandLineRPC(int argc, char *argv[]);
-
-/** Convert parameter values for RPC call from strings to command-specific JSON objects. */
-json_spirit::Array RPCConvertValues(const std::string &strMethod, const std::vector<std::string> &strParams);
/*
Type-check arguments; throws JSONRPCError if wrong type given. Does not check that
diff --git a/src/rpcwallet.cpp b/src/rpcwallet.cpp
index 8b14c0aca9..82fa9d88c5 100644
--- a/src/rpcwallet.cpp
+++ b/src/rpcwallet.cpp
@@ -3,10 +3,8 @@
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-
#include "base58.h"
-#include "bitcoinrpc.h"
+#include "rpcserver.h"
#include "init.h"
#include "net.h"
#include "netbase.h"
@@ -35,15 +33,6 @@ std::string HelpRequiringPassphrase()
: "";
}
-std::string HelpExampleCli(string methodname, string args){
- return "> bitcoin-cli " + methodname + " " + args + "\n";
-}
-
-std::string HelpExampleRpc(string methodname, string args){
- return "> curl --user myusername --data-binary '{\"jsonrpc\": \"1.0\", \"id\":\"curltest\", "
- "\"method\": \"" + methodname + "\", \"params\": [" + args + "] }' -H 'content-type: text/plain;' http://127.0.0.1:8332/\n";
-}
-
void EnsureWalletIsUnlocked()
{
if (pwalletMain->IsLocked())
@@ -77,64 +66,6 @@ string AccountFromValue(const Value& value)
return strAccount;
}
-Value getinfo(const Array& params, bool fHelp)
-{
- if (fHelp || params.size() != 0)
- throw runtime_error(
- "getinfo\n"
- "Returns an object containing various state info.\n"
- "\nResult:\n"
- "{\n"
- " \"version\": xxxxx, (numeric) the server version\n"
- " \"protocolversion\": xxxxx, (numeric) the protocol version\n"
- " \"walletversion\": xxxxx, (numeric) the wallet version\n"
- " \"balance\": xxxxxxx, (numeric) the total bitcoin balance of the wallet\n"
- " \"blocks\": xxxxxx, (numeric) the current number of blocks processed in the server\n"
- " \"timeoffset\": xxxxx, (numeric) the time offset\n"
- " \"connections\": xxxxx, (numeric) the number of connections\n"
- " \"proxy\": \"host:port\", (string, optional) the proxy used by the server\n"
- " \"difficulty\": xxxxxx, (numeric) the current difficulty\n"
- " \"testnet\": true|false, (boolean) if the server is using testnet or not\n"
- " \"keypoololdest\": xxxxxx, (numeric) the timestamp (seconds since GMT epoch) of the oldest pre-generated key in the key pool\n"
- " \"keypoolsize\": xxxx, (numeric) how many new keys are pre-generated\n"
- " \"paytxfee\": x.xxxx, (numeric) the transaction fee set in btc\n"
- " \"unlocked_until\": ttt, (numeric) the timestamp in seconds since epoch (midnight Jan 1 1970 GMT) that the wallet is unlocked for transfers, or 0 if the wallet is locked\n"
- " \"errors\": \"...\" (string) any error messages\n"
- "}\n"
- "\nExamples:\n"
- + HelpExampleCli("getinfo", "")
- + HelpExampleRpc("getinfo", "")
- );
-
- proxyType proxy;
- GetProxy(NET_IPV4, proxy);
-
- Object obj;
- obj.push_back(Pair("version", (int)CLIENT_VERSION));
- obj.push_back(Pair("protocolversion",(int)PROTOCOL_VERSION));
- 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()));
- 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 && pwalletMain->IsCrypted())
- obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime));
- obj.push_back(Pair("errors", GetWarnings("statusbar")));
- return obj;
-}
-
-
-
Value getnewaddress(const Array& params, bool fHelp)
{
if (fHelp || params.size() > 1)
@@ -403,8 +334,7 @@ Value sendtoaddress(const Array& params, bool fHelp)
if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
wtx.mapValue["to"] = params[3].get_str();
- if (pwalletMain->IsLocked())
- throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
+ EnsureWalletIsUnlocked();
string strError = pwalletMain->SendMoneyToDestination(address.Get(), nAmount, wtx);
if (strError != "")
@@ -1675,7 +1605,7 @@ Value gettransaction(const Array& params, bool fHelp)
int64_t nCredit = wtx.GetCredit();
int64_t nDebit = wtx.GetDebit();
int64_t nNet = nCredit - nDebit;
- int64_t nFee = (wtx.IsFromMe() ? GetValueOut(wtx) - nDebit : 0);
+ int64_t nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0);
entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
if (wtx.IsFromMe())
@@ -1726,15 +1656,15 @@ Value keypoolrefill(const Array& params, bool fHelp)
+ HelpExampleRpc("keypoolrefill", "")
);
- unsigned int kpSize = max(GetArg("-keypool", 100), (int64_t) 0);
+ // 0 is interpreted by TopUpKeyPool() as the default keypool size given by -keypool
+ unsigned int kpSize = 0;
if (params.size() > 0) {
if (params[0].get_int() < 0)
- throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected valid size");
- kpSize = (unsigned int) params[0].get_int();
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected valid size.");
+ kpSize = (unsigned int)params[0].get_int();
}
EnsureWalletIsUnlocked();
-
pwalletMain->TopUpKeyPool(kpSize);
if (pwalletMain->GetKeyPoolSize() < kpSize)
diff --git a/src/script.cpp b/src/script.cpp
index 228d432ee3..2b66bc73d6 100644
--- a/src/script.cpp
+++ b/src/script.cpp
@@ -14,8 +14,6 @@
#include "uint256.h"
#include "util.h"
-#include <stdint.h>
-
#include <boost/foreach.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/tuple/tuple_comparison.hpp>
diff --git a/src/sync.cpp b/src/sync.cpp
index 33e1219541..9a20c87f88 100644
--- a/src/sync.cpp
+++ b/src/sync.cpp
@@ -42,6 +42,8 @@ struct CLockLocation
return mutexName+" "+sourceFile+":"+itostr(sourceLine);
}
+ std::string MutexName() const { return mutexName; }
+
private:
std::string mutexName;
std::string sourceFile;
@@ -126,4 +128,20 @@ void LeaveCritical()
pop_lock();
}
+std::string LocksHeld()
+{
+ std::string result;
+ BOOST_FOREACH(const PAIRTYPE(void*, CLockLocation)&i, *lockstack)
+ result += i.second.ToString() + std::string("\n");
+ return result;
+}
+
+void AssertLockHeld(std::string strName)
+{
+ BOOST_FOREACH(const PAIRTYPE(void*, CLockLocation)&i, *lockstack)
+ if (i.second.MutexName() == strName) return;
+ LogPrintf("Lock %s not held; locks held:\n%s", strName.c_str(), LocksHeld().c_str());
+ assert(0);
+}
+
#endif /* DEBUG_LOCKORDER */
diff --git a/src/sync.h b/src/sync.h
index 39f2cb5155..c50abf81b6 100644
--- a/src/sync.h
+++ b/src/sync.h
@@ -87,9 +87,12 @@ typedef AnnotatedMixin<boost::mutex> CWaitableCriticalSection;
#ifdef DEBUG_LOCKORDER
void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false);
void LeaveCritical();
+std::string LocksHeld();
+void AssertLockHeld(std::string strName);
#else
void static inline EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false) {}
void static inline LeaveCritical() {}
+void static inline AssertLockHeld(std::string) {}
#endif
#ifdef DEBUG_LOCKCONTENTION
diff --git a/src/test/DoS_tests.cpp b/src/test/DoS_tests.cpp
index f0fb84bc54..fbca09b4dc 100644
--- a/src/test/DoS_tests.cpp
+++ b/src/test/DoS_tests.cpp
@@ -21,6 +21,7 @@
// Tests this internal-to-main.cpp method:
extern bool AddOrphanTx(const CTransaction& tx);
extern unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans);
+extern void Misbehaving(NodeId nodeid, int howmuch);
extern std::map<uint256, CTransaction> mapOrphanTransactions;
extern std::map<uint256, std::set<uint256> > mapOrphanTransactionsByPrev;
@@ -38,16 +39,21 @@ BOOST_AUTO_TEST_CASE(DoS_banning)
CNode::ClearBanned();
CAddress addr1(ip(0xa0b0c001));
CNode dummyNode1(INVALID_SOCKET, addr1, "", true);
- dummyNode1.Misbehaving(100); // Should get banned
+ dummyNode1.nVersion = 1;
+ Misbehaving(dummyNode1.GetId(), 100); // Should get banned
+ SendMessages(&dummyNode1, false);
BOOST_CHECK(CNode::IsBanned(addr1));
BOOST_CHECK(!CNode::IsBanned(ip(0xa0b0c001|0x0000ff00))); // Different IP, not banned
CAddress addr2(ip(0xa0b0c002));
CNode dummyNode2(INVALID_SOCKET, addr2, "", true);
- dummyNode2.Misbehaving(50);
+ dummyNode2.nVersion = 1;
+ Misbehaving(dummyNode2.GetId(), 50);
+ SendMessages(&dummyNode2, false);
BOOST_CHECK(!CNode::IsBanned(addr2)); // 2 not banned yet...
BOOST_CHECK(CNode::IsBanned(addr1)); // ... but 1 still should be
- dummyNode2.Misbehaving(50);
+ Misbehaving(dummyNode2.GetId(), 50);
+ SendMessages(&dummyNode2, false);
BOOST_CHECK(CNode::IsBanned(addr2));
}
@@ -57,11 +63,15 @@ BOOST_AUTO_TEST_CASE(DoS_banscore)
mapArgs["-banscore"] = "111"; // because 11 is my favorite number
CAddress addr1(ip(0xa0b0c001));
CNode dummyNode1(INVALID_SOCKET, addr1, "", true);
- dummyNode1.Misbehaving(100);
+ dummyNode1.nVersion = 1;
+ Misbehaving(dummyNode1.GetId(), 100);
+ SendMessages(&dummyNode1, false);
BOOST_CHECK(!CNode::IsBanned(addr1));
- dummyNode1.Misbehaving(10);
+ Misbehaving(dummyNode1.GetId(), 10);
+ SendMessages(&dummyNode1, false);
BOOST_CHECK(!CNode::IsBanned(addr1));
- dummyNode1.Misbehaving(1);
+ Misbehaving(dummyNode1.GetId(), 1);
+ SendMessages(&dummyNode1, false);
BOOST_CHECK(CNode::IsBanned(addr1));
mapArgs.erase("-banscore");
}
@@ -74,8 +84,10 @@ BOOST_AUTO_TEST_CASE(DoS_bantime)
CAddress addr(ip(0xa0b0c001));
CNode dummyNode(INVALID_SOCKET, addr, "", true);
+ dummyNode.nVersion = 1;
- dummyNode.Misbehaving(100);
+ Misbehaving(dummyNode.GetId(), 100);
+ SendMessages(&dummyNode, false);
BOOST_CHECK(CNode::IsBanned(addr));
SetMockTime(nStartTime+60*60);
diff --git a/src/test/Makefile.am b/src/test/Makefile.am
index 180fd7effa..dccd264e5a 100644
--- a/src/test/Makefile.am
+++ b/src/test/Makefile.am
@@ -20,17 +20,26 @@ 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) $(BDB_LIBS)
-test_bitcoin_SOURCES = accounting_tests.cpp alert_tests.cpp \
+test_bitcoin_LDADD = $(LIBBITCOIN_SERVER) $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBLEVELDB) $(LIBMEMENV) \
+ $(BOOST_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIB)
+if ENABLE_WALLET
+test_bitcoin_LDADD += $(LIBBITCOIN_WALLET)
+endif
+test_bitcoin_LDADD += $(BDB_LIBS)
+
+test_bitcoin_SOURCES = 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 \
Checkpoints_tests.cpp compress_tests.cpp DoS_tests.cpp getarg_tests.cpp \
- key_tests.cpp miner_tests.cpp mruset_tests.cpp multisig_tests.cpp \
+ key_tests.cpp mruset_tests.cpp multisig_tests.cpp \
netbase_tests.cpp pmt_tests.cpp rpc_tests.cpp script_P2SH_tests.cpp \
script_tests.cpp serialize_tests.cpp sigopcount_tests.cpp test_bitcoin.cpp \
transaction_tests.cpp uint160_tests.cpp uint256_tests.cpp util_tests.cpp \
- wallet_tests.cpp sighash_tests.cpp $(JSON_TEST_FILES) $(RAW_TEST_FILES)
+ sighash_tests.cpp $(JSON_TEST_FILES) $(RAW_TEST_FILES)
+
+if ENABLE_WALLET
+test_bitcoin_SOURCES += accounting_tests.cpp wallet_tests.cpp miner_tests.cpp rpc_wallet_tests.cpp
+endif
nodist_test_bitcoin_SOURCES = $(BUILT_SOURCES)
diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp
index dcb7f9abd4..46c9ae021d 100644
--- a/src/test/miner_tests.cpp
+++ b/src/test/miner_tests.cpp
@@ -57,6 +57,8 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
CScript script;
uint256 hash;
+ LOCK(cs_main);
+
// Simple block creation, nothing special yet:
BOOST_CHECK(pblocktemplate = CreateNewBlockWithKey(reservekey));
@@ -99,7 +101,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
{
tx.vout[0].nValue -= 1000000;
hash = tx.GetHash();
- mempool.addUnchecked(hash, tx);
+ mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11));
tx.vin[0].prevout.hash = hash;
}
BOOST_CHECK(pblocktemplate = CreateNewBlockWithKey(reservekey));
@@ -119,7 +121,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
{
tx.vout[0].nValue -= 10000000;
hash = tx.GetHash();
- mempool.addUnchecked(hash, tx);
+ mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11));
tx.vin[0].prevout.hash = hash;
}
BOOST_CHECK(pblocktemplate = CreateNewBlockWithKey(reservekey));
@@ -128,7 +130,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
// orphan in mempool
hash = tx.GetHash();
- mempool.addUnchecked(hash, tx);
+ mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11));
BOOST_CHECK(pblocktemplate = CreateNewBlockWithKey(reservekey));
delete pblocktemplate;
mempool.clear();
@@ -138,7 +140,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
tx.vin[0].prevout.hash = txFirst[1]->GetHash();
tx.vout[0].nValue = 4900000000LL;
hash = tx.GetHash();
- mempool.addUnchecked(hash, tx);
+ mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11));
tx.vin[0].prevout.hash = hash;
tx.vin.resize(2);
tx.vin[1].scriptSig = CScript() << OP_1;
@@ -146,7 +148,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
tx.vin[1].prevout.n = 0;
tx.vout[0].nValue = 5900000000LL;
hash = tx.GetHash();
- mempool.addUnchecked(hash, tx);
+ mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11));
BOOST_CHECK(pblocktemplate = CreateNewBlockWithKey(reservekey));
delete pblocktemplate;
mempool.clear();
@@ -157,7 +159,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
tx.vin[0].scriptSig = CScript() << OP_0 << OP_1;
tx.vout[0].nValue = 0;
hash = tx.GetHash();
- mempool.addUnchecked(hash, tx);
+ mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11));
BOOST_CHECK(pblocktemplate = CreateNewBlockWithKey(reservekey));
delete pblocktemplate;
mempool.clear();
@@ -170,12 +172,12 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
script = CScript() << OP_0;
tx.vout[0].scriptPubKey.SetDestination(script.GetID());
hash = tx.GetHash();
- mempool.addUnchecked(hash, tx);
+ mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11));
tx.vin[0].prevout.hash = hash;
tx.vin[0].scriptSig = CScript() << (std::vector<unsigned char>)script;
tx.vout[0].nValue -= 1000000;
hash = tx.GetHash();
- mempool.addUnchecked(hash,tx);
+ mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11));
BOOST_CHECK(pblocktemplate = CreateNewBlockWithKey(reservekey));
delete pblocktemplate;
mempool.clear();
@@ -186,10 +188,10 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
tx.vout[0].nValue = 4900000000LL;
tx.vout[0].scriptPubKey = CScript() << OP_1;
hash = tx.GetHash();
- mempool.addUnchecked(hash, tx);
+ mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11));
tx.vout[0].scriptPubKey = CScript() << OP_2;
hash = tx.GetHash();
- mempool.addUnchecked(hash, tx);
+ mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11));
BOOST_CHECK(pblocktemplate = CreateNewBlockWithKey(reservekey));
delete pblocktemplate;
mempool.clear();
diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp
index 4fb2aeb6ae..29195545da 100644
--- a/src/test/rpc_tests.cpp
+++ b/src/test/rpc_tests.cpp
@@ -1,4 +1,5 @@
-#include "bitcoinrpc.h"
+#include "rpcserver.h"
+#include "rpcclient.h"
#include "base58.h"
@@ -8,9 +9,7 @@
using namespace std;
using namespace json_spirit;
-BOOST_AUTO_TEST_SUITE(rpc_tests)
-
-static Array
+Array
createArgs(int nRequired, const char* address1=NULL, const char* address2=NULL)
{
Array result;
@@ -22,44 +21,7 @@ createArgs(int nRequired, const char* address1=NULL, const char* address2=NULL)
return result;
}
-BOOST_AUTO_TEST_CASE(rpc_addmultisig)
-{
- rpcfn_type addmultisig = tableRPC["addmultisigaddress"]->actor;
-
- // old, 65-byte-long:
- const char address1Hex[] = "0434e3e09f49ea168c5bbf53f877ff4206923858aab7c7e1df25bc263978107c95e35065a27ef6f1b27222db0ec97e0e895eaca603d3ee0d4c060ce3d8a00286c8";
- // new, compressed:
- const char address2Hex[] = "0388c2037017c62240b6b72ac1a2a5f94da790596ebd06177c8572752922165cb4";
-
- Value v;
- CBitcoinAddress address;
- BOOST_CHECK_NO_THROW(v = addmultisig(createArgs(1, address1Hex), false));
- address.SetString(v.get_str());
- BOOST_CHECK(address.IsValid() && address.IsScript());
-
- BOOST_CHECK_NO_THROW(v = addmultisig(createArgs(1, address1Hex, address2Hex), false));
- address.SetString(v.get_str());
- BOOST_CHECK(address.IsValid() && address.IsScript());
-
- BOOST_CHECK_NO_THROW(v = addmultisig(createArgs(2, address1Hex, address2Hex), false));
- address.SetString(v.get_str());
- BOOST_CHECK(address.IsValid() && address.IsScript());
-
- BOOST_CHECK_THROW(addmultisig(createArgs(0), false), runtime_error);
- BOOST_CHECK_THROW(addmultisig(createArgs(1), false), runtime_error);
- BOOST_CHECK_THROW(addmultisig(createArgs(2, address1Hex), false), runtime_error);
-
- BOOST_CHECK_THROW(addmultisig(createArgs(1, ""), false), runtime_error);
- BOOST_CHECK_THROW(addmultisig(createArgs(1, "NotAValidPubkey"), false), runtime_error);
-
- string short1(address1Hex, address1Hex+sizeof(address1Hex)-2); // last byte missing
- BOOST_CHECK_THROW(addmultisig(createArgs(2, short1.c_str()), false), runtime_error);
-
- string short2(address1Hex+1, address1Hex+sizeof(address1Hex)); // first byte missing
- BOOST_CHECK_THROW(addmultisig(createArgs(2, short2.c_str()), false), runtime_error);
-}
-
-static Value CallRPC(string args)
+Value CallRPC(string args)
{
vector<string> vArgs;
boost::split(vArgs, args, boost::is_any_of(" \t"));
@@ -78,34 +40,8 @@ static Value CallRPC(string args)
}
}
-BOOST_AUTO_TEST_CASE(rpc_wallet)
-{
- // Test RPC calls for various wallet statistics
- Value r;
-
- BOOST_CHECK_NO_THROW(CallRPC("listunspent"));
- BOOST_CHECK_THROW(CallRPC("listunspent string"), runtime_error);
- BOOST_CHECK_THROW(CallRPC("listunspent 0 string"), runtime_error);
- BOOST_CHECK_THROW(CallRPC("listunspent 0 1 not_array"), runtime_error);
- BOOST_CHECK_THROW(CallRPC("listunspent 0 1 [] extra"), runtime_error);
- BOOST_CHECK_NO_THROW(r=CallRPC("listunspent 0 1 []"));
- BOOST_CHECK(r.get_array().empty());
-
- BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaddress"));
- BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaddress 0"));
- BOOST_CHECK_THROW(CallRPC("listreceivedbyaddress not_int"), runtime_error);
- BOOST_CHECK_THROW(CallRPC("listreceivedbyaddress 0 not_bool"), runtime_error);
- BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaddress 0 true"));
- BOOST_CHECK_THROW(CallRPC("listreceivedbyaddress 0 true extra"), runtime_error);
-
- BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaccount"));
- BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaccount 0"));
- BOOST_CHECK_THROW(CallRPC("listreceivedbyaccount not_int"), runtime_error);
- BOOST_CHECK_THROW(CallRPC("listreceivedbyaccount 0 not_bool"), runtime_error);
- BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaccount 0 true"));
- BOOST_CHECK_THROW(CallRPC("listreceivedbyaccount 0 true extra"), runtime_error);
-}
+BOOST_AUTO_TEST_SUITE(rpc_tests)
BOOST_AUTO_TEST_CASE(rpc_rawparams)
{
diff --git a/src/test/rpc_wallet_tests.cpp b/src/test/rpc_wallet_tests.cpp
new file mode 100644
index 0000000000..2cf0fb350b
--- /dev/null
+++ b/src/test/rpc_wallet_tests.cpp
@@ -0,0 +1,82 @@
+#include "rpcserver.h"
+#include "rpcclient.h"
+
+#include "base58.h"
+
+#include <boost/algorithm/string.hpp>
+#include <boost/test/unit_test.hpp>
+
+using namespace std;
+using namespace json_spirit;
+
+extern Array createArgs(int nRequired, const char* address1=NULL, const char* address2=NULL);
+extern Value CallRPC(string args);
+
+BOOST_AUTO_TEST_SUITE(rpc_wallet_tests)
+
+BOOST_AUTO_TEST_CASE(rpc_addmultisig)
+{
+ rpcfn_type addmultisig = tableRPC["addmultisigaddress"]->actor;
+
+ // old, 65-byte-long:
+ const char address1Hex[] = "0434e3e09f49ea168c5bbf53f877ff4206923858aab7c7e1df25bc263978107c95e35065a27ef6f1b27222db0ec97e0e895eaca603d3ee0d4c060ce3d8a00286c8";
+ // new, compressed:
+ const char address2Hex[] = "0388c2037017c62240b6b72ac1a2a5f94da790596ebd06177c8572752922165cb4";
+
+ Value v;
+ CBitcoinAddress address;
+ BOOST_CHECK_NO_THROW(v = addmultisig(createArgs(1, address1Hex), false));
+ address.SetString(v.get_str());
+ BOOST_CHECK(address.IsValid() && address.IsScript());
+
+ BOOST_CHECK_NO_THROW(v = addmultisig(createArgs(1, address1Hex, address2Hex), false));
+ address.SetString(v.get_str());
+ BOOST_CHECK(address.IsValid() && address.IsScript());
+
+ BOOST_CHECK_NO_THROW(v = addmultisig(createArgs(2, address1Hex, address2Hex), false));
+ address.SetString(v.get_str());
+ BOOST_CHECK(address.IsValid() && address.IsScript());
+
+ BOOST_CHECK_THROW(addmultisig(createArgs(0), false), runtime_error);
+ BOOST_CHECK_THROW(addmultisig(createArgs(1), false), runtime_error);
+ BOOST_CHECK_THROW(addmultisig(createArgs(2, address1Hex), false), runtime_error);
+
+ BOOST_CHECK_THROW(addmultisig(createArgs(1, ""), false), runtime_error);
+ BOOST_CHECK_THROW(addmultisig(createArgs(1, "NotAValidPubkey"), false), runtime_error);
+
+ string short1(address1Hex, address1Hex+sizeof(address1Hex)-2); // last byte missing
+ BOOST_CHECK_THROW(addmultisig(createArgs(2, short1.c_str()), false), runtime_error);
+
+ string short2(address1Hex+1, address1Hex+sizeof(address1Hex)); // first byte missing
+ BOOST_CHECK_THROW(addmultisig(createArgs(2, short2.c_str()), false), runtime_error);
+}
+
+BOOST_AUTO_TEST_CASE(rpc_wallet)
+{
+ // Test RPC calls for various wallet statistics
+ Value r;
+
+ BOOST_CHECK_NO_THROW(CallRPC("listunspent"));
+ BOOST_CHECK_THROW(CallRPC("listunspent string"), runtime_error);
+ BOOST_CHECK_THROW(CallRPC("listunspent 0 string"), runtime_error);
+ BOOST_CHECK_THROW(CallRPC("listunspent 0 1 not_array"), runtime_error);
+ BOOST_CHECK_THROW(CallRPC("listunspent 0 1 [] extra"), runtime_error);
+ BOOST_CHECK_NO_THROW(r=CallRPC("listunspent 0 1 []"));
+ BOOST_CHECK(r.get_array().empty());
+
+ BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaddress"));
+ BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaddress 0"));
+ BOOST_CHECK_THROW(CallRPC("listreceivedbyaddress not_int"), runtime_error);
+ BOOST_CHECK_THROW(CallRPC("listreceivedbyaddress 0 not_bool"), runtime_error);
+ BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaddress 0 true"));
+ BOOST_CHECK_THROW(CallRPC("listreceivedbyaddress 0 true extra"), runtime_error);
+
+ BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaccount"));
+ BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaccount 0"));
+ BOOST_CHECK_THROW(CallRPC("listreceivedbyaccount not_int"), runtime_error);
+ BOOST_CHECK_THROW(CallRPC("listreceivedbyaccount 0 not_bool"), runtime_error);
+ BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaccount 0 true"));
+ BOOST_CHECK_THROW(CallRPC("listreceivedbyaccount 0 true extra"), runtime_error);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp
index f947167597..a4592fe803 100644
--- a/src/test/test_bitcoin.cpp
+++ b/src/test/test_bitcoin.cpp
@@ -7,14 +7,15 @@
#include "txdb.h"
#include "ui_interface.h"
#include "util.h"
+#ifdef ENABLE_WALLET
#include "wallet.h"
+#endif
#include <boost/filesystem.hpp>
#include <boost/test/unit_test.hpp>
CWallet* pwalletMain;
-CClientUIInterface uiInterface;
extern bool fPrintToConsole;
extern void noui_connect();
@@ -27,7 +28,9 @@ struct TestingSetup {
TestingSetup() {
fPrintToDebugger = true; // don't want to write to debug.log file
noui_connect();
+#ifdef ENABLE_WALLET
bitdb.MakeMock();
+#endif
pathTemp = GetTempPath() / strprintf("test_bitcoin_%lu_%i", (unsigned long)GetTime(), (int)(GetRand(100000)));
boost::filesystem::create_directories(pathTemp);
mapArgs["-datadir"] = pathTemp.string();
@@ -35,24 +38,32 @@ struct TestingSetup {
pcoinsdbview = new CCoinsViewDB(1 << 23, true);
pcoinsTip = new CCoinsViewCache(*pcoinsdbview);
InitBlockIndex();
+#ifdef ENABLE_WALLET
bool fFirstRun;
pwalletMain = new CWallet("wallet.dat");
pwalletMain->LoadWallet(fFirstRun);
RegisterWallet(pwalletMain);
+#endif
nScriptCheckThreads = 3;
for (int i=0; i < nScriptCheckThreads-1; i++)
threadGroup.create_thread(&ThreadScriptCheck);
+ RegisterNodeSignals(GetNodeSignals());
}
~TestingSetup()
{
threadGroup.interrupt_all();
threadGroup.join_all();
+ UnregisterNodeSignals(GetNodeSignals());
+#ifdef ENABLE_WALLET
delete pwalletMain;
pwalletMain = NULL;
+#endif
delete pcoinsTip;
delete pcoinsdbview;
delete pblocktree;
+#ifdef ENABLE_WALLET
bitdb.Flush(true);
+#endif
boost::filesystem::remove_all(pathTemp);
}
};
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
index d501b89ecf..be251d1d64 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -8,6 +8,33 @@
using namespace std;
+CTxMemPoolEntry::CTxMemPoolEntry()
+{
+ nHeight = MEMPOOL_HEIGHT;
+}
+
+CTxMemPoolEntry::CTxMemPoolEntry(const CTransaction& _tx, int64_t _nFee,
+ int64_t _nTime, double _dPriority,
+ unsigned int _nHeight):
+ tx(_tx), nFee(_nFee), nTime(_nTime), dPriority(_dPriority), nHeight(_nHeight)
+{
+ nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);
+}
+
+CTxMemPoolEntry::CTxMemPoolEntry(const CTxMemPoolEntry& other)
+{
+ *this = other;
+}
+
+double
+CTxMemPoolEntry::GetPriority(unsigned int currentHeight) const
+{
+ int64_t nValueIn = tx.GetValueOut()+nFee;
+ double deltaPriority = ((double)(currentHeight-nHeight)*nValueIn)/nTxSize;
+ double dResult = dPriority + deltaPriority;
+ return dResult;
+}
+
CTxMemPool::CTxMemPool()
{
// Sanity checks off by default for performance, because otherwise
@@ -42,16 +69,17 @@ void CTxMemPool::AddTransactionsUpdated(unsigned int n)
}
-bool CTxMemPool::addUnchecked(const uint256& hash, const CTransaction &tx)
+bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry)
{
// Add to memory pool without checking anything.
// Used by main.cpp AcceptToMemoryPool(), which DOES do
// all the appropriate checks.
LOCK(cs);
{
- mapTx[hash] = tx;
+ mapTx[hash] = entry;
+ const CTransaction& tx = mapTx[hash].GetTx();
for (unsigned int i = 0; i < tx.vin.size(); i++)
- mapNextTx[tx.vin[i].prevout] = CInPoint(&mapTx[hash], i);
+ mapNextTx[tx.vin[i].prevout] = CInPoint(&tx, i);
nTransactionsUpdated++;
}
return true;
@@ -113,13 +141,15 @@ void CTxMemPool::check(CCoinsViewCache *pcoins) const
LogPrint("mempool", "Checking mempool with %u transactions and %u inputs\n", (unsigned int)mapTx.size(), (unsigned int)mapNextTx.size());
LOCK(cs);
- for (std::map<uint256, CTransaction>::const_iterator it = mapTx.begin(); it != mapTx.end(); it++) {
+ for (std::map<uint256, CTxMemPoolEntry>::const_iterator it = mapTx.begin(); it != mapTx.end(); it++) {
unsigned int i = 0;
- BOOST_FOREACH(const CTxIn &txin, it->second.vin) {
+ const CTransaction& tx = it->second.GetTx();
+ BOOST_FOREACH(const CTxIn &txin, tx.vin) {
// Check that every mempool transaction's inputs refer to available coins, or other mempool tx's.
- std::map<uint256, CTransaction>::const_iterator it2 = mapTx.find(txin.prevout.hash);
+ std::map<uint256, CTxMemPoolEntry>::const_iterator it2 = mapTx.find(txin.prevout.hash);
if (it2 != mapTx.end()) {
- assert(it2->second.vout.size() > txin.prevout.n && !it2->second.vout[txin.prevout.n].IsNull());
+ const CTransaction& tx2 = it2->second.GetTx();
+ assert(tx2.vout.size() > txin.prevout.n && !tx2.vout[txin.prevout.n].IsNull());
} else {
CCoins &coins = pcoins->GetCoins(txin.prevout.hash);
assert(coins.IsAvailable(txin.prevout.n));
@@ -127,37 +157,38 @@ void CTxMemPool::check(CCoinsViewCache *pcoins) const
// Check whether its inputs are marked in mapNextTx.
std::map<COutPoint, CInPoint>::const_iterator it3 = mapNextTx.find(txin.prevout);
assert(it3 != mapNextTx.end());
- assert(it3->second.ptx == &it->second);
+ assert(it3->second.ptx == &tx);
assert(it3->second.n == i);
i++;
}
}
for (std::map<COutPoint, CInPoint>::const_iterator it = mapNextTx.begin(); it != mapNextTx.end(); it++) {
uint256 hash = it->second.ptx->GetHash();
- std::map<uint256, CTransaction>::const_iterator it2 = mapTx.find(hash);
+ map<uint256, CTxMemPoolEntry>::const_iterator it2 = mapTx.find(hash);
+ const CTransaction& tx = it2->second.GetTx();
assert(it2 != mapTx.end());
- assert(&it2->second == it->second.ptx);
- assert(it2->second.vin.size() > it->second.n);
+ assert(&tx == it->second.ptx);
+ assert(tx.vin.size() > it->second.n);
assert(it->first == it->second.ptx->vin[it->second.n].prevout);
}
}
-void CTxMemPool::queryHashes(std::vector<uint256>& vtxid)
+void CTxMemPool::queryHashes(vector<uint256>& vtxid)
{
vtxid.clear();
LOCK(cs);
vtxid.reserve(mapTx.size());
- for (map<uint256, CTransaction>::iterator mi = mapTx.begin(); mi != mapTx.end(); ++mi)
+ for (map<uint256, CTxMemPoolEntry>::iterator mi = mapTx.begin(); mi != mapTx.end(); ++mi)
vtxid.push_back((*mi).first);
}
bool CTxMemPool::lookup(uint256 hash, CTransaction& result) const
{
LOCK(cs);
- std::map<uint256, CTransaction>::const_iterator i = mapTx.find(hash);
+ map<uint256, CTxMemPoolEntry>::const_iterator i = mapTx.find(hash);
if (i == mapTx.end()) return false;
- result = i->second;
+ result = i->second.GetTx();
return true;
}
diff --git a/src/txmempool.h b/src/txmempool.h
index 57b92789fb..a652c424a4 100644
--- a/src/txmempool.h
+++ b/src/txmempool.h
@@ -13,6 +13,33 @@
static const unsigned int MEMPOOL_HEIGHT = 0x7FFFFFFF;
/*
+ * CTxMemPool stores these:
+ */
+class CTxMemPoolEntry
+{
+private:
+ CTransaction tx;
+ int64_t nFee; // Cached to avoid expensive parent-transaction lookups
+ size_t nTxSize; // ... and avoid recomputing tx size
+ int64_t nTime; // Local time when entering the mempool
+ double dPriority; // Priority when entering the mempool
+ unsigned int nHeight; // Chain height when entering the mempool
+
+public:
+ CTxMemPoolEntry(const CTransaction& _tx, int64_t _nFee,
+ int64_t _nTime, double _dPriority, unsigned int _nHeight);
+ CTxMemPoolEntry();
+ CTxMemPoolEntry(const CTxMemPoolEntry& other);
+
+ const CTransaction& GetTx() const { return this->tx; }
+ double GetPriority(unsigned int currentHeight) const;
+ int64_t GetFee() const { return nFee; }
+ size_t GetTxSize() const { return nTxSize; }
+ int64_t GetTime() const { return nTime; }
+ unsigned int GetHeight() const { return nHeight; }
+};
+
+/*
* CTxMemPool stores valid-according-to-the-current-best-chain
* transactions that may be included in the next block.
*
@@ -30,7 +57,7 @@ private:
public:
mutable CCriticalSection cs;
- std::map<uint256, CTransaction> mapTx;
+ std::map<uint256, CTxMemPoolEntry> mapTx;
std::map<COutPoint, CInPoint> mapNextTx;
CTxMemPool();
@@ -44,7 +71,7 @@ public:
void check(CCoinsViewCache *pcoins) const;
void setSanityCheck(bool _fSanityCheck) { fSanityCheck = _fSanityCheck; }
- bool addUnchecked(const uint256& hash, const CTransaction &tx);
+ bool addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry);
bool remove(const CTransaction &tx, bool fRecursive = false);
bool removeConflicts(const CTransaction &tx);
void clear();
diff --git a/src/util.cpp b/src/util.cpp
index 44186b7325..a8c591cc7a 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -12,9 +12,7 @@
#include "uint256.h"
#include "version.h"
-#include <inttypes.h>
#include <stdarg.h>
-#include <stdint.h>
#ifndef WIN32
// for posix_fallocate
@@ -97,6 +95,7 @@ string strMiscWarning;
bool fNoListen = false;
bool fLogTimestamps = false;
volatile bool fReopenDebugLog = false;
+CClientUIInterface uiInterface;
// Init OpenSSL library multithreading support
static CCriticalSection** ppmutexOpenSSL;
@@ -1513,3 +1512,4 @@ void RenameThread(const char* name)
(void)name;
#endif
}
+
diff --git a/src/wallet.cpp b/src/wallet.cpp
index 31dfe18185..241e937b1b 100644
--- a/src/wallet.cpp
+++ b/src/wallet.cpp
@@ -10,7 +10,6 @@
#include "net.h"
#include <inttypes.h>
-#include <stdint.h>
#include <boost/algorithm/string/replace.hpp>
#include <openssl/rand.h>
@@ -656,7 +655,7 @@ void CWalletTx::GetAmounts(list<pair<CTxDestination, int64_t> >& listReceived,
int64_t nDebit = GetDebit();
if (nDebit > 0) // debit>0 means we signed/sent this transaction
{
- int64_t nValueOut = GetValueOut(*this);
+ int64_t nValueOut = GetValueOut();
nFee = nDebit - nValueOut;
}
@@ -766,6 +765,10 @@ void CWalletTx::AddSupportingTransactions()
{
tx = *mapWalletPrev[hash];
}
+ else
+ {
+ continue;
+ }
int nDepth = tx.SetMerkleBranch();
vtxPrev.push_back(tx);
@@ -896,7 +899,10 @@ void CWalletTx::RelayWalletTransaction()
{
BOOST_FOREACH(const CMerkleTx& tx, vtxPrev)
{
- if (!tx.IsCoinBase())
+ // Important: versions of bitcoin before 0.8.6 had a bug that inserted
+ // empty transactions into the vtxPrev, which will cause the node to be
+ // banned when retransmitted, hence the check for !tx.vin.empty()
+ if (!tx.IsCoinBase() && !tx.vin.empty())
if (tx.GetDepthInMainChain() == 0)
RelayTransaction((CTransaction)tx, tx.GetHash());
}
@@ -1299,7 +1305,9 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64_t> >& vecSend,
// Reserve a new key pair from key pool
CPubKey vchPubKey;
- assert(reservekey.GetReservedKey(vchPubKey)); // should never fail, as we just unlocked
+ bool ret;
+ ret = reservekey.GetReservedKey(vchPubKey);
+ assert(ret); // should never fail, as we just unlocked
scriptChange.SetDestination(vchPubKey.GetID());
}
@@ -1343,15 +1351,7 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64_t> >& vecSend,
strFailReason = _("Transaction too large");
return false;
}
- unsigned int nTxSizeMod = nBytes;
- // See miner.c's dPriority logic for the matching network-node side code.
- BOOST_FOREACH(const CTxIn& txin, (*(CTransaction*)&wtxNew).vin)
- {
- unsigned int offset = 41U + min(110U, (unsigned int)txin.scriptSig.size());
- if (nTxSizeMod > offset)
- nTxSizeMod -= offset;
- }
- dPriority /= nTxSizeMod;
+ dPriority = wtxNew.ComputePriority(dPriority, nBytes);
// Check that enough fee is included
int64_t nPayFee = nTransactionFee * (1 + (int64_t)nBytes / 1000);
diff --git a/src/walletdb.cpp b/src/walletdb.cpp
index 6b3628b184..2dc6594e93 100644
--- a/src/walletdb.cpp
+++ b/src/walletdb.cpp
@@ -12,7 +12,6 @@
#include "wallet.h"
#include <inttypes.h>
-#include <stdint.h>
#include <boost/filesystem.hpp>
#include <boost/foreach.hpp>