diff options
99 files changed, 2613 insertions, 2214 deletions
diff --git a/.gitignore b/.gitignore index ba6842acaa..da0437835b 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ src/*.exe src/*/*.exe src/bitcoin src/bitcoind +src/bitcoin-cli src/test/test_bitcoin src/qt/test/test_bitcoin-qt @@ -1,9 +1,5 @@ Building Bitcoin -See doc/readme-qt.md for instructions on building Bitcoin-Qt, -the intended-for-end-users, nice-graphical-interface, reference -implementation of Bitcoin. - See doc/build-*.md for instructions on building bitcoind, the intended-for-services, no-graphical-interface, reference implementation of Bitcoin.
\ No newline at end of file diff --git a/Makefile.am b/Makefile.am index dc0e6d8f76..243166b3f7 100644 --- a/Makefile.am +++ b/Makefile.am @@ -118,7 +118,8 @@ test_bitcoin_filtered.info: test_bitcoin.info $(LCOV) -r $< "/usr/include/*" -o $@ block_test.info: test_bitcoin_filtered.info - -@TIMEOUT=15 qa/pull-tester/run-bitcoind-for-test.sh $(JAVA) -Xmx2G -jar $(JAVA_COMPARISON_TOOL) 1 18444 + $(MKDIR_P) qa/tmp + -@TIMEOUT=15 qa/pull-tester/run-bitcoind-for-test.sh $(JAVA) -jar $(JAVA_COMPARISON_TOOL) qa/tmp/compTool 0 $(LCOV) -c -d $(abs_builddir)/src --t BitcoinJBlockTest -o $@ $(LCOV) -z -d $(abs_builddir)/src $(LCOV) -z -d $(abs_builddir)/src/leveldb @@ -146,7 +147,8 @@ endif if USE_COMPARISON_TOOL check-local: - @qa/pull-tester/run-bitcoind-for-test.sh $(JAVA) -Xmx2G -jar $(JAVA_COMPARISON_TOOL) 1 18444 + $(MKDIR_P) qa/tmp + @qa/pull-tester/run-bitcoind-for-test.sh $(JAVA) -jar $(JAVA_COMPARISON_TOOL) qa/tmp/compTool $(COMPARISON_TOOL_REORG_TESTS) endif EXTRA_DIST = $(top_srcdir)/share/genbuild.sh qa/pull-tester/pull-tester.sh $(WINDOWS_PACKAGING) $(OSX_PACKAGING) diff --git a/configure.ac b/configure.ac index 905acd573c..f6d870f332 100644 --- a/configure.ac +++ b/configure.ac @@ -69,10 +69,15 @@ AC_ARG_ENABLE(tests, [use_tests=yes]) AC_ARG_WITH([comparison-tool], - AS_HELP_STRING([with-comparison-tool],[path to java comparison tool (requires --enable-tests)]), + AS_HELP_STRING([--with-comparison-tool],[path to java comparison tool (requires --enable-tests)]), [use_comparison_tool=$withval], [use_comparison_tool=no]) +AC_ARG_ENABLE([comparison-tool-reorg-tests], + AS_HELP_STRING([--enable-comparison-tool-reorg-tests],[enable expensive reorg tests in the comparison tool (default no)]), + [use_comparison_tool_reorg_tests=$enableval], + [use_comparison_tool_reorg_tests=no]) + AC_ARG_WITH([qrencode], [AS_HELP_STRING([--with-qrencode], [enable QR code support (default is yes if qt is enabled and libqrencode is found)])], @@ -235,6 +240,15 @@ if test x$use_comparison_tool != xno; then AC_SUBST(JAVA_COMPARISON_TOOL, $use_comparison_tool) fi +if test x$use_comparison_tool_reorg_tests != xno; then + if test x$use_comparison_tool == x; then + AC_MSG_ERROR("comparison tool reorg tests but comparison tool was not specified") + fi + AC_SUBST(COMPARISON_TOOL_REORG_TESTS, 1) +else + AC_SUBST(COMPARISON_TOOL_REORG_TESTS, 0) +fi + if test x$use_lcov == xyes; then if test x$LCOV == x; then AC_MSG_ERROR("lcov testing requested but lcov not found") @@ -678,6 +692,7 @@ AM_CONDITIONAL([TARGET_WINDOWS], [test x$TARGET_OS = xwindows]) 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]) +AM_CONDITIONAL([USE_COMPARISON_TOOL_REORG_TESTS],[test x$use_comparison_tool_reorg_test != xno]) AC_DEFINE(CLIENT_VERSION_MAJOR, _CLIENT_VERSION_MAJOR, [Major version]) AC_DEFINE(CLIENT_VERSION_MINOR, _CLIENT_VERSION_MINOR, [Minor version]) diff --git a/contrib/README.md b/contrib/README.md index 7128fd5eb0..eb0d3ee2c9 100644 --- a/contrib/README.md +++ b/contrib/README.md @@ -1,8 +1,23 @@ -Contrib Index +Python Tools --------------------- ### [BitRPC](/contrib/bitrpc) ### -Added bitrpc.py which allows for sending of all standard Bitcoin commands via RPC rather than as command line args. +Allows for sending of all standard Bitcoin commands via RPC rather than as command line args. + +### [PyMiner](/contrib/pyminer) ### + +This is a 'getwork' CPU mining client for Bitcoin. It is pure-python, and therefore very, very slow. The purpose is to provide a reference implementation of a miner, for study. + +### [SpendFrom](/contrib/spendfrom) ### + +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. + +Repository Tools +--------------------- ### [Debian](/contrib/debian) ### Contains files used to package bitcoind/bitcoin-qt @@ -20,10 +35,6 @@ Construct a linear, no-fork, best version of the blockchain. ### [MacDeploy](/contrib/macdeploy) ### Scripts and notes for Mac builds. -### [PyMiner](/contrib/pyminer) ### - -This is a 'getwork' CPU mining client for Bitcoin. It is pure-python, and therefore very, very slow. The purpose is to provide a reference implementation of a miner, for study. - ### [Qos](/contrib/qos) ### A Linux bash script that will set up tc to limit the outgoing bandwidth for connections to the Bitcoin network. This means one can have an always-on bitcoind instance running, and another local bitcoind/bitcoin-qt instance which connects to this node and receives blocks from it. @@ -31,11 +42,6 @@ A Linux bash script that will set up tc to limit the outgoing bandwidth for conn ### [Seeds](/contrib/seeds) ### Utility to generate the pnSeed[] array that is compiled into the client. -### [SpendFrom](/contrib/spendfrom) ### - -Use the raw transactions API to send coins received on a particular -address (or addresses). - ### [TestGen](/contrib/testgen) ### Utilities to generate test vectors for the data-driven Bitcoin tests. @@ -46,5 +52,3 @@ tests each pull and when master is tested using jenkins. ### [Verify SF Binaries](/contrib/verifysfbinaries) ### This script attempts to download and verify the signature file SHA256SUMS.asc from SourceForge. -### [Wallet Tools](/contrib/wallettools) ### -Contains a wallet change password and unlock script. diff --git a/contrib/bitcoin-qt.pro b/contrib/bitcoin-qt.pro index 0b181ef449..6adf7650d2 100644 --- a/contrib/bitcoin-qt.pro +++ b/contrib/bitcoin-qt.pro @@ -4,14 +4,15 @@ FORMS += \ ../src/qt/forms/sendcoinsentry.ui \ ../src/qt/forms/sendcoinsdialog.ui \ ../src/qt/forms/rpcconsole.ui \ - ../src/qt/forms/qrcodedialog.ui \ ../src/qt/forms/overviewpage.ui \ ../src/qt/forms/optionsdialog.ui \ ../src/qt/forms/intro.ui \ ../src/qt/forms/editaddressdialog.ui \ ../src/qt/forms/askpassphrasedialog.ui \ ../src/qt/forms/addressbookpage.ui \ - ../src/qt/forms/aboutdialog.ui + ../src/qt/forms/aboutdialog.ui \ + ../src/qt/forms/receivecoinsdialog.ui \ + ../src/qt/forms/receiverequestdialog.ui RESOURCES += \ ../src/qt/bitcoin.qrc diff --git a/contrib/pyminer/README.md b/contrib/pyminer/README.md index 119d51bdc7..3b20f2fdea 100644 --- a/contrib/pyminer/README.md +++ b/contrib/pyminer/README.md @@ -1,7 +1,8 @@ ### PyMiner ### -This is a 'getwork' CPU mining client for Bitcoin. +This is a 'getwork' CPU mining client for Bitcoin. It is pure-python, and therefore very, very slow. The purpose is to provide a reference implementation of a miner, for study. -It is pure-python, and therefore very, very slow. The purpose is to -provide a reference implementation of a miner, for study. +### Other Resources ### +- [BitcoinTalk Thread](https://bitcointalk.org/index.php?topic=3546.0) +- [Jgarzik Repo](https://github.com/jgarzik/pyminer)
\ No newline at end of file diff --git a/contrib/spendfrom/README.md b/contrib/spendfrom/README.md index bc4def5f74..809540b7b1 100644 --- a/contrib/spendfrom/README.md +++ b/contrib/spendfrom/README.md @@ -1,11 +1,10 @@ ### SpendFrom ### Use the raw transactions API to send coins received on a particular -address (or addresses). +address (or addresses). -Depends on `jsonrpc` - -Usage: +### Usage: ### +Depends on [jsonrpc](http://json-rpc.org/). spendfrom.py --from=FROMADDRESS1[,FROMADDRESS2] --to=TOADDRESS --amount=amount \ --fee=fee --datadir=/path/to/.bitcoin --testnet --dry_run @@ -14,21 +13,23 @@ With no arguments, outputs a list of amounts associated with addresses. With arguments, sends coins received by the `FROMADDRESS` addresses to the `TOADDRESS`. -You may explictly specify how much fee to pay (a fee more than 1% of the amount +### Notes ### + +- You may explictly specify how much fee to pay (a fee more than 1% of the amount will fail, though, to prevent bitcoin-losing accidents). Spendfrom may fail if it thinks the transaction would never be confirmed (if the amount being sent is too small, or if the transaction is too many bytes for the fee). -If a change output needs to be created, the change will be sent to the last +- If a change output needs to be created, the change will be sent to the last `FROMADDRESS` (if you specify just one `FROMADDRESS`, change will go back to it). -If `--datadir` is not specified, the default datadir is used. +- If `--datadir` is not specified, the default datadir is used. -The `--dry_run` option will just create and sign the the transaction and print +- The `--dry_run` option will just create and sign the the transaction and print the transaction data (as hexadecimal), instead of broadcasting it. -If the transaction is created and broadcast successfully, a transaction id +- If the transaction is created and broadcast successfully, a transaction id is printed. -If this was a tool for end-users and not programmers, it would have much friendlier +- If this was a tool for end-users and not programmers, it would have much friendlier error-handling. diff --git a/contrib/verifysfbinaries/README.md b/contrib/verifysfbinaries/README.md index caa4073605..f646d1efd1 100644 --- a/contrib/verifysfbinaries/README.md +++ b/contrib/verifysfbinaries/README.md @@ -1,7 +1,6 @@ ### Verify SF Binaries ### This script attempts to download the signature file `SHA256SUMS.asc` from SourceForge. -It first checks if the signature passes, and then downloads the files specified in -the file, and checks if the hashes of these files match those that are specified -in the signature file. The script returns 0 if everything passes the checks. It returns 1 if either the -signature check or the hash check doesn't pass. If an error occurs the return value is 2
\ No newline at end of file +It first checks if the signature passes, and then downloads the files specified in the file, and checks if the hashes of these files match those that are specified in the signature file. + +The script returns 0 if everything passes the checks. It returns 1 if either the signature check or the hash check doesn't pass. If an error occurs the return value is 2.
\ No newline at end of file diff --git a/doc/build-msw.md b/doc/build-msw.md index d348ad7cc3..e7e902eaa5 100644 --- a/doc/build-msw.md +++ b/doc/build-msw.md @@ -1,8 +1,6 @@ WINDOWS BUILD NOTES =================== -See [readme-qt.md](readme-qt.md) for instructions on building Bitcoin-Qt, the -graphical user interface. Compilers Supported ------------------- diff --git a/doc/build-osx.md b/doc/build-osx.md index 271f8f55bd..6ded75d340 100644 --- a/doc/build-osx.md +++ b/doc/build-osx.md @@ -5,8 +5,6 @@ This guide will show you how to build bitcoind(headless client) for OSX. Notes ----- -* See [readme-qt.md](readme-qt.md) for instructions on building Bitcoin-Qt, the -graphical user interface. * Tested on OS X 10.5 through 10.8 on Intel processors only. PPC is not supported because it is big-endian. * All of the commands should be executed in a Terminal application. The diff --git a/doc/build-unix.md b/doc/build-unix.md index 422b46cc3a..59a036f4a8 100644 --- a/doc/build-unix.md +++ b/doc/build-unix.md @@ -10,7 +10,6 @@ To Build make This will build bitcoin-qt as well if the dependencies are met. -See [readme-qt.md](readme-qt.md) for more information. Dependencies --------------------- diff --git a/qa/pull-tester/build-tests.sh.in b/qa/pull-tester/build-tests.sh.in index 461e7be048..73f046a0f5 100755 --- a/qa/pull-tester/build-tests.sh.in +++ b/qa/pull-tester/build-tests.sh.in @@ -9,8 +9,9 @@ set -o xtrace MINGWPREFIX=$1 JAVA_COMPARISON_TOOL=$2 -JOBS=${3-1} -OUT_DIR=${4-} +RUN_EXPENSIVE_TESTS=$3 +JOBS=${4-1} +OUT_DIR=${5-} if [ $# -lt 2 ]; then echo "Usage: $0 [mingw-prefix] [java-comparison-tool] <make jobs> <save output dir>" @@ -22,20 +23,30 @@ DISTDIR=@PACKAGE@-@VERSION@ # Cross-compile for windows first (breaking the mingw/windows build is most common) cd @abs_top_srcdir@ make distdir -mv $DISTDIR win32-build +mkdir -p win32-build +rsync -av $DISTDIR/ win32-build/ +rm -r $DISTDIR cd win32-build -./configure --disable-silent-rules --disable-ccache --prefix=$MINGWPREFIX --host=i586-mingw32msvc --with-qt-bindir=$MINGWPREFIX/host/bin --with-qt-plugindir=$MINGWPREFIX/plugins --with-qt-incdir=$MINGWPREFIX/include --with-boost=$MINGWPREFIX --with-protoc-bindir=$MINGWPREFIX/host/bin CPPFLAGS=-I$MINGWPREFIX/include LDFLAGS=-L$MINGWPREFIX/lib + +if [ $RUN_EXPENSIVE_TESTS = 1 ]; then + ./configure --disable-silent-rules --disable-ccache --prefix=$MINGWPREFIX --host=i586-mingw32msvc --with-qt-bindir=$MINGWPREFIX/host/bin --with-qt-plugindir=$MINGWPREFIX/plugins --with-qt-incdir=$MINGWPREFIX/include --with-boost=$MINGWPREFIX --with-protoc-bindir=$MINGWPREFIX/host/bin CPPFLAGS=-I$MINGWPREFIX/include LDFLAGS=-L$MINGWPREFIX/lib --with-comparison-tool="$JAVA_COMPARISON_TOOL" --enable-comparison-tool-reorg-tests +else + ./configure --disable-silent-rules --disable-ccache --prefix=$MINGWPREFIX --host=i586-mingw32msvc --with-qt-bindir=$MINGWPREFIX/host/bin --with-qt-plugindir=$MINGWPREFIX/plugins --with-qt-incdir=$MINGWPREFIX/include --with-boost=$MINGWPREFIX --with-protoc-bindir=$MINGWPREFIX/host/bin CPPFLAGS=-I$MINGWPREFIX/include LDFLAGS=-L$MINGWPREFIX/lib +fi make -j$JOBS # And compile for Linux: cd @abs_top_srcdir@ make distdir -mv $DISTDIR linux-build +mkdir -p linux-build +rsync -av $DISTDIR/ linux-build/ +rm -r $DISTDIR cd linux-build -# TODO: re-enable blockchain tester tool, as of 11 Oct 2013 is it not working properly -# on the pull-tester machine. -#./configure --disable-silent-rules --disable-ccache --with-comparison-tool="$JAVA_COMPARISON_TOOL" -./configure --disable-silent-rules --disable-ccache +if [ $RUN_EXPENSIVE_TESTS = 1 ]; then + ./configure --disable-silent-rules --disable-ccache --with-comparison-tool="$JAVA_COMPARISON_TOOL" --enable-comparison-tool-reorg-tests +else + ./configure --disable-silent-rules --disable-ccache --with-comparison-tool="$JAVA_COMPARISON_TOOL" +fi make -j$JOBS # link interesting binaries to parent out/ directory, if it exists. Do this before @@ -57,6 +68,12 @@ fi cd @abs_top_srcdir@/linux-build make check +if [ $RUN_EXPENSIVE_TESTS = 1 ]; then + # Run unit tests and blockchain-tester on Windows: + cd @abs_top_srcdir@/win32-build + make check +fi + # Clean up builds (pull-tester machine doesn't have infinite disk space) cd @abs_top_srcdir@/linux-build make clean diff --git a/qa/pull-tester/pull-tester.py b/qa/pull-tester/pull-tester.py index 34dd74c7e0..6a7c45ccd1 100755 --- a/qa/pull-tester/pull-tester.py +++ b/qa/pull-tester/pull-tester.py @@ -67,7 +67,12 @@ Contact BlueMatt on freenode if something looks broken.""" auth=(os.environ['GITHUB_USER'], os.environ["GITHUB_AUTH_TOKEN"])) if success == True: - post_data = { "body" : "Automatic sanity-testing: PASSED, see " + linkUrl + " for binaries and test log." + common_message} + if needTests: + message = "Automatic sanity-testing: PLEASE ADD TEST-CASES, though technically passed. See " + linkUrl + " for binaries and test log." + else: + message = "Automatic sanity-testing: PASSED, see " + linkUrl + " for binaries and test log." + + post_data = { "body" : message + common_message} elif inMerge: post_data = { "body" : "Automatic sanity-testing: FAILED MERGE, see " + linkUrl + " for test log." + """ @@ -113,7 +118,7 @@ def testpull(number, comment_url, clone_url, commit): run("chown -R ${BUILD_USER}:${BUILD_GROUP} ${CHROOT_COPY}/${OUT_DIR}", fail_hard=False) script = os.environ["BUILD_PATH"]+"/qa/pull-tester/pull-tester.sh" - script += " ${BUILD_PATH} ${MINGW_DEPS_DIR} ${SCRIPTS_DIR}/BitcoindComparisonTool.jar 6 ${OUT_DIR}" + script += " ${BUILD_PATH} ${MINGW_DEPS_DIR} ${SCRIPTS_DIR}/BitcoindComparisonTool_jar/BitcoindComparisonTool.jar 0 6 ${OUT_DIR}" returncode = run("chroot ${CHROOT_COPY} sudo -u ${BUILD_USER} -H timeout ${TEST_TIMEOUT} "+script, fail_hard=False, stdout=out, stderr=out) diff --git a/qa/pull-tester/run-bitcoind-for-test.sh.in b/qa/pull-tester/run-bitcoind-for-test.sh.in index e02fef3b56..25faf9c42d 100755 --- a/qa/pull-tester/run-bitcoind-for-test.sh.in +++ b/qa/pull-tester/run-bitcoind-for-test.sh.in @@ -5,7 +5,8 @@ mkdir -p "$DATADIR"/regtest touch "$DATADIR/regtest/debug.log" tail -q -n 1 -F "$DATADIR/regtest/debug.log" | grep -m 1 -q "Done loading" & WAITER=$! -"@abs_top_builddir@/src/bitcoind@EXEEXT@" -connect=0.0.0.0 -datadir="$DATADIR" -rpcuser=user -rpcpassword=pass -listen -keypool=3 -debug -logtimestamps -port=18444 -regtest & +PORT=`expr $BASHPID + 10000` +"@abs_top_builddir@/src/bitcoind@EXEEXT@" -connect=0.0.0.0 -datadir="$DATADIR" -rpcuser=user -rpcpassword=pass -listen -keypool=3 -debug -debug=net -logtimestamps -port=$PORT -regtest -rpcport=`expr $PORT + 1` & BITCOIND=$! #Install a watchdog. @@ -13,10 +14,10 @@ BITCOIND=$! wait $WAITER if [ -n "$TIMEOUT" ]; then - timeout "$TIMEOUT"s "$@" + timeout "$TIMEOUT"s "$@" $PORT RETURN=$? else - "$@" + "$@" $PORT RETURN=$? fi diff --git a/src/Makefile.am b/src/Makefile.am index 49249fedc7..14d1dd03a6 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -6,7 +6,7 @@ AM_LDFLAGS = $(PTHREAD_CFLAGS) noinst_LIBRARIES = libbitcoin.a -bin_PROGRAMS = bitcoind +bin_PROGRAMS = bitcoind bitcoin-cli SUBDIRS = . $(BUILD_QT) $(BUILD_TEST) DIST_SUBDIRS = . qt test @@ -55,6 +55,17 @@ endif 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_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 leveldb/%.a: diff --git a/src/addrman.h b/src/addrman.h index 081543ace4..d703e1091e 100644 --- a/src/addrman.h +++ b/src/addrman.h @@ -419,7 +419,7 @@ public: Check(); } if (fRet) - LogPrint("addr", "Added %s from %s: %i tried, %i new\n", addr.ToStringIPPort().c_str(), source.ToString().c_str(), nTried, nNew); + LogPrint("addrman", "Added %s from %s: %i tried, %i new\n", addr.ToStringIPPort().c_str(), source.ToString().c_str(), nTried, nNew); return fRet; } @@ -435,7 +435,7 @@ public: Check(); } if (nAdd) - LogPrint("addr", "Added %i addresses from %s: %i tried, %i new\n", nAdd, source.ToString().c_str(), nTried, nNew); + LogPrint("addrman", "Added %i addresses from %s: %i tried, %i new\n", nAdd, source.ToString().c_str(), nTried, nNew); return nAdd > 0; } diff --git a/src/bitcoin-cli-res.rc b/src/bitcoin-cli-res.rc new file mode 100644 index 0000000000..337897753e --- /dev/null +++ b/src/bitcoin-cli-res.rc @@ -0,0 +1,36 @@ +#include <windows.h> // needed for VERSIONINFO +#include "clientversion.h" // holds the needed client version information + +#define VER_PRODUCTVERSION CLIENT_VERSION_MAJOR,CLIENT_VERSION_MINOR,CLIENT_VERSION_REVISION,CLIENT_VERSION_BUILD +#define VER_PRODUCTVERSION_STR STRINGIZE(CLIENT_VERSION_MAJOR) "." STRINGIZE(CLIENT_VERSION_MINOR) "." STRINGIZE(CLIENT_VERSION_REVISION) "." STRINGIZE(CLIENT_VERSION_BUILD) +#define VER_FILEVERSION VER_PRODUCTVERSION +#define VER_FILEVERSION_STR VER_PRODUCTVERSION_STR +#define COPYRIGHT_STR "2009-" STRINGIZE(COPYRIGHT_YEAR) " The Bitcoin developers" + +VS_VERSION_INFO VERSIONINFO +FILEVERSION VER_FILEVERSION +PRODUCTVERSION VER_PRODUCTVERSION +FILEOS VOS_NT_WINDOWS32 +FILETYPE VFT_APP +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904E4" // U.S. English - multilingual (hex) + BEGIN + VALUE "CompanyName", "Bitcoin" + VALUE "FileDescription", "Bitcoin-cli (OSS RPC client for Bitcoin)" + VALUE "FileVersion", VER_FILEVERSION_STR + VALUE "InternalName", "bitcoin-cli" + VALUE "LegalCopyright", COPYRIGHT_STR + VALUE "LegalTrademarks1", "Distributed under the MIT/X11 software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php." + VALUE "OriginalFilename", "bitcoin-cli.exe" + VALUE "ProductName", "Bitcoin-cli" + VALUE "ProductVersion", VER_PRODUCTVERSION_STR + END + END + + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1252 // language neutral - multilingual (decimal) + END +END diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp new file mode 100644 index 0000000000..bb30c748bb --- /dev/null +++ b/src/bitcoin-cli.cpp @@ -0,0 +1,69 @@ +// Copyright (c) 2009-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 "util.h" +#include "init.h" +#include "bitcoinrpc.h" +#include "ui_interface.h" /* for _(...) */ + +////////////////////////////////////////////////////////////////////////////// +// +// Start +// +static bool AppInitRPC(int argc, char* argv[]) +{ + // + // Parameters + // + ParseParameters(argc, argv); + if (!boost::filesystem::is_directory(GetDataDir(false))) + { + fprintf(stderr, "Error: Specified data directory \"%s\" does not exist.\n", mapArgs["-datadir"].c_str()); + return false; + } + ReadConfigFile(mapArgs, mapMultiArgs); + + if (argc<2 || mapArgs.count("-?") || mapArgs.count("--help")) + { + // First part of help message is specific to RPC client + std::string strUsage = _("Bitcoin RPC client version") + " " + FormatFullVersion() + "\n\n" + + _("Usage:") + "\n" + + " bitcoin-cli [options] <command> [params] " + _("Send command to Bitcoin server") + "\n" + + " bitcoin-cli [options] help " + _("List commands") + "\n" + + " bitcoin-cli [options] help <command> " + _("Get help for a command") + "\n"; + + strUsage += "\n" + HelpMessage(HMM_BITCOIN_CLI); + + fprintf(stdout, "%s", strUsage.c_str()); + return false; + } + return true; +} + +int main(int argc, char* argv[]) +{ + try + { + if(!AppInitRPC(argc, argv)) + return 1; + } + catch (std::exception& e) { + PrintExceptionContinue(&e, "AppInitRPC()"); + } catch (...) { + PrintExceptionContinue(NULL, "AppInitRPC()"); + } + + try + { + if(!CommandLineRPC(argc, argv)) + return 1; + } + catch (std::exception& e) { + PrintExceptionContinue(&e, "CommandLineRPC()"); + } catch (...) { + PrintExceptionContinue(NULL, "CommandLineRPC()"); + } + return 0; +} diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp index 1b40a868a1..4fd3296069 100644 --- a/src/bitcoind.cpp +++ b/src/bitcoind.cpp @@ -3,7 +3,10 @@ // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include "ui_interface.h" #include "init.h" +#include "util.h" +#include "main.h" #include "bitcoinrpc.h" #include <boost/algorithm/string/predicate.hpp> @@ -57,12 +60,13 @@ bool AppInit(int argc, char* argv[]) // First part of help message is specific to bitcoind / RPC client std::string strUsage = _("Bitcoin version") + " " + FormatFullVersion() + "\n\n" + _("Usage:") + "\n" + - " bitcoind [options] " + "\n" + - " bitcoind [options] <command> [params] " + _("Send command to -server or bitcoind") + "\n" + + " bitcoind [options] " + _("Start Bitcoin server") + "\n" + + _("Usage (deprecated, use bitcoin-cli):") + "\n" + + " bitcoind [options] <command> [params] " + _("Send command to Bitcoin server") + "\n" + " bitcoind [options] help " + _("List commands") + "\n" + " bitcoind [options] help <command> " + _("Get help for a command") + "\n"; - strUsage += "\n" + HelpMessage(); + strUsage += "\n" + HelpMessage(HMM_BITCOIND); fprintf(stdout, "%s", strUsage.c_str()); return false; diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp index 93ab9a4770..f3ea0adb40 100644 --- a/src/bitcoinrpc.cpp +++ b/src/bitcoinrpc.cpp @@ -4,6 +4,8 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "chainparams.h" +#include "main.h" +#include "wallet.h" #include "init.h" #include "util.h" #include "sync.h" @@ -31,8 +33,6 @@ using namespace boost; using namespace boost::asio; using namespace json_spirit; -static const char* Value_type_name[]={"obj", "array", "str", "bool", "int", "real", "null"}; - static std::string strRPCUserColonPass; // These are created by StartRPCThreads, destroyed in StopRPCThreads @@ -533,7 +533,7 @@ string JSONRPCRequest(const string& strMethod, const Array& params, const Value& request.push_back(Pair("method", strMethod)); request.push_back(Pair("params", params)); request.push_back(Pair("id", id)); - return write_string(Value(request), raw_utf8) + "\n"; + return write_string(Value(request), false) + "\n"; } Object JSONRPCReplyObj(const Value& result, const Value& error, const Value& id) @@ -551,7 +551,7 @@ Object JSONRPCReplyObj(const Value& result, const Value& error, const Value& id) string JSONRPCReply(const Value& result, const Value& error, const Value& id) { Object reply = JSONRPCReplyObj(result, error, id); - return write_string(Value(reply), raw_utf8) + "\n"; + return write_string(Value(reply), false) + "\n"; } void ErrorReply(std::ostream& stream, const Object& objError, const Value& id) @@ -982,7 +982,7 @@ static string JSONRPCExecBatch(const Array& vReq) for (unsigned int reqIdx = 0; reqIdx < vReq.size(); reqIdx++) ret.push_back(JSONRPCExecOne(vReq[reqIdx])); - return write_string(Value(ret), raw_utf8) + "\n"; + return write_string(Value(ret), false) + "\n"; } void ServiceConnection(AcceptedConnection *conn) @@ -1284,7 +1284,7 @@ int CommandLineRPC(int argc, char *argv[]) if (error.type() != null_type) { // Error - strPrint = "error: " + write_string(error, raw_utf8); + strPrint = "error: " + write_string(error, false); int code = find_value(error.get_obj(), "code").get_int(); nRet = abs(code); } @@ -1296,7 +1296,7 @@ int CommandLineRPC(int argc, char *argv[]) else if (result.type() == str_type) strPrint = result.get_str(); else - strPrint = write_string(result, pretty_print | raw_utf8); + strPrint = write_string(result, true); } } catch (boost::thread_interrupted) { diff --git a/src/bitcoinrpc.h b/src/bitcoinrpc.h index 275369ddd2..0c1c722b50 100644 --- a/src/bitcoinrpc.h +++ b/src/bitcoinrpc.h @@ -49,10 +49,13 @@ enum RPCErrorCode 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.) diff --git a/src/core.h b/src/core.h index 9ee8b2edce..70e62716f3 100644 --- a/src/core.h +++ b/src/core.h @@ -421,6 +421,9 @@ public: // equality test friend bool operator==(const CCoins &a, const CCoins &b) { + // Empty CCoins objects are always equal. + if (a.IsPruned() && b.IsPruned()) + return true; return a.fCoinBase == b.fCoinBase && a.nHeight == b.nHeight && a.nVersion == b.nVersion && diff --git a/src/init.cpp b/src/init.cpp index daa12d8995..647b8d52ea 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -171,94 +171,130 @@ bool static Bind(const CService &addr, unsigned int flags) { return true; } -// Core-specific options shared between UI and daemon -std::string HelpMessage() +// Core-specific options shared between UI, daemon and RPC client +std::string HelpMessage(HelpMessageMode hmm) { string strUsage = _("Options:") + "\n"; strUsage += " -? " + _("This help message") + "\n"; strUsage += " -conf=<file> " + _("Specify configuration file (default: bitcoin.conf)") + "\n"; - strUsage += " -pid=<file> " + _("Specify pid file (default: bitcoind.pid)") + "\n"; - strUsage += " -gen " + _("Generate coins (default: 0)") + "\n"; strUsage += " -datadir=<dir> " + _("Specify data directory") + "\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 += " -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"; #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"; - if (fHaveGUI) + 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"; + } + else + { + strUsage += ".\n"; + } + strUsage += " -logtimestamps " + _("Prepend debug output with timestamp") + "\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"; +#endif + } + + if (hmm == HMM_BITCOIN_QT) + { strUsage += " -server " + _("Accept command line and JSON-RPC commands") + "\n"; + } + + if (hmm == HMM_BITCOIND) + { #if !defined(WIN32) - if (fHaveGUI) strUsage += " -daemon " + _("Run in the background as a daemon and accept commands") + "\n"; #endif - strUsage += " -testnet " + _("Use the test network") + "\n"; - strUsage += " -debug " + _("Output extra debugging information. Implies all other -debug* options") + "\n"; - strUsage += " -debugnet " + _("Output extra network debugging information") + "\n"; - strUsage += " -logtimestamps " + _("Prepend debug output with timestamp") + "\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"; -#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"; - 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"; - if (!fHaveGUI) - strUsage += " -rpcconnect=<ip> " + _("Send commands to node running on <ip> (default: 127.0.0.1)") + "\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"; + 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 += "\n" + _("SSL options: (see the Bitcoin Wiki for SSL setup instructions)") + "\n"; strUsage += " -rpcssl " + _("Use OpenSSL (https) for JSON-RPC connections") + "\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"; + 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"; + } return strUsage; } @@ -431,7 +467,16 @@ bool AppInit2(boost::thread_group& threadGroup) // ********************************************************* Step 3: parameter-to-internal-flags - if (mapMultiArgs.count("-debug")) fDebug = true; + fDebug = !mapMultiArgs["-debug"].empty(); + // Special-case: if -debug=0/-nodebug is set, turn off debugging messages + const vector<string>& categories = mapMultiArgs["-debug"]; + if (GetBoolArg("-nodebug", false) || find(categories.begin(), categories.end(), string("0")) != categories.end()) + fDebug = false; + + // Check for -debugnet (deprecated) + if (GetBoolArg("-debugnet", false)) + InitWarning(_("Warning: Deprecated argument -debugnet ignored, use -debug=net")); + fBenchmark = GetBoolArg("-benchmark", false); mempool.fChecks = GetBoolArg("-checkmempool", RegTest()); Checkpoints::fEnabled = GetBoolArg("-checkpoints", true); @@ -445,12 +490,6 @@ bool AppInit2(boost::thread_group& threadGroup) else if (nScriptCheckThreads > MAX_SCRIPTCHECK_THREADS) nScriptCheckThreads = MAX_SCRIPTCHECK_THREADS; - // -debug implies fDebug* - if (fDebug) - fDebugNet = true; - else - fDebugNet = GetBoolArg("-debugnet", false); - if (fDaemon) fServer = true; else diff --git a/src/init.h b/src/init.h index e5a2a69293..8cb1bf52fc 100644 --- a/src/init.h +++ b/src/init.h @@ -5,7 +5,10 @@ #ifndef BITCOIN_INIT_H #define BITCOIN_INIT_H -#include "wallet.h" +#include <string> +#include <boost/thread.hpp> + +class CWallet; extern std::string strWalletFile; extern CWallet* pwalletMain; @@ -14,6 +17,15 @@ void StartShutdown(); bool ShutdownRequested(); void Shutdown(); bool AppInit2(boost::thread_group& threadGroup); -std::string HelpMessage(); + +/* The help message mode determines what help message to show */ +enum HelpMessageMode +{ + HMM_BITCOIND, + HMM_BITCOIN_QT, + HMM_BITCOIN_CLI +}; + +std::string HelpMessage(HelpMessageMode mode); #endif diff --git a/src/json/LICENSE.txt b/src/json/LICENSE.txt index 6ed66a2e69..797d5363b3 100644 --- a/src/json/LICENSE.txt +++ b/src/json/LICENSE.txt @@ -1,6 +1,6 @@ The MIT License -Copyright (c) 2007 - 2010 John W. Wilkinson +Copyright (c) 2007 - 2009 John W. Wilkinson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation diff --git a/src/json/json_spirit.h b/src/json/json_spirit.h index ef442e9fd5..ac1879d5b3 100644 --- a/src/json/json_spirit.h +++ b/src/json/json_spirit.h @@ -1,10 +1,10 @@ #ifndef JSON_SPIRIT #define JSON_SPIRIT -// Copyright John W. Wilkinson 2007 - 2013 +// Copyright John W. Wilkinson 2007 - 2009. // Distributed under the MIT License, see accompanying file LICENSE.txt -// json spirit version 4.06 +// json spirit version 4.03 #if defined(_MSC_VER) && (_MSC_VER >= 1020) # pragma once diff --git a/src/json/json_spirit_error_position.h b/src/json/json_spirit_error_position.h index e2b59b47ae..17208507df 100644 --- a/src/json/json_spirit_error_position.h +++ b/src/json/json_spirit_error_position.h @@ -1,10 +1,10 @@ #ifndef JSON_SPIRIT_ERROR_POSITION #define JSON_SPIRIT_ERROR_POSITION -// Copyright John W. Wilkinson 2007 - 2013 +// Copyright John W. Wilkinson 2007 - 2009. // Distributed under the MIT License, see accompanying file LICENSE.txt -// json spirit version 4.06 +// json spirit version 4.03 #if defined(_MSC_VER) && (_MSC_VER >= 1020) # pragma once @@ -48,7 +48,7 @@ namespace json_spirit return ( reason_ == lhs.reason_ ) && ( line_ == lhs.line_ ) && ( column_ == lhs.column_ ); - } +} } #endif diff --git a/src/json/json_spirit_reader.cpp b/src/json/json_spirit_reader.cpp index 7dea074736..aa4f637226 100644 --- a/src/json/json_spirit_reader.cpp +++ b/src/json/json_spirit_reader.cpp @@ -1,137 +1,137 @@ -// Copyright John W. Wilkinson 2007 - 2013 +// Copyright John W. Wilkinson 2007 - 2009. // Distributed under the MIT License, see accompanying file LICENSE.txt -// json spirit version 4.06 +// json spirit version 4.03 #include "json_spirit_reader.h" #include "json_spirit_reader_template.h" using namespace json_spirit; -#ifdef JSON_SPIRIT_VALUE_ENABLED - bool json_spirit::read( const std::string& s, Value& value ) - { - return read_string( s, value ); - } - - void json_spirit::read_or_throw( const std::string& s, Value& value ) - { - read_string_or_throw( s, value ); - } - - bool json_spirit::read( std::istream& is, Value& value ) - { - return read_stream( is, value ); - } - - void json_spirit::read_or_throw( std::istream& is, Value& value ) - { - read_stream_or_throw( is, value ); - } - - bool json_spirit::read( std::string::const_iterator& begin, std::string::const_iterator end, Value& value ) - { - return read_range( begin, end, value ); - } - - void json_spirit::read_or_throw( std::string::const_iterator& begin, std::string::const_iterator end, Value& value ) - { - begin = read_range_or_throw( begin, end, value ); - } -#endif +bool json_spirit::read( const std::string& s, Value& value ) +{ + return read_string( s, value ); +} + +void json_spirit::read_or_throw( const std::string& s, Value& value ) +{ + read_string_or_throw( s, value ); +} + +bool json_spirit::read( std::istream& is, Value& value ) +{ + return read_stream( is, value ); +} + +void json_spirit::read_or_throw( std::istream& is, Value& value ) +{ + read_stream_or_throw( is, value ); +} + +bool json_spirit::read( std::string::const_iterator& begin, std::string::const_iterator end, Value& value ) +{ + return read_range( begin, end, value ); +} + +void json_spirit::read_or_throw( std::string::const_iterator& begin, std::string::const_iterator end, Value& value ) +{ + begin = read_range_or_throw( begin, end, value ); +} + +#ifndef BOOST_NO_STD_WSTRING + +bool json_spirit::read( const std::wstring& s, wValue& value ) +{ + return read_string( s, value ); +} + +void json_spirit::read_or_throw( const std::wstring& s, wValue& value ) +{ + read_string_or_throw( s, value ); +} + +bool json_spirit::read( std::wistream& is, wValue& value ) +{ + return read_stream( is, value ); +} + +void json_spirit::read_or_throw( std::wistream& is, wValue& value ) +{ + read_stream_or_throw( is, value ); +} + +bool json_spirit::read( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wValue& value ) +{ + return read_range( begin, end, value ); +} + +void json_spirit::read_or_throw( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wValue& value ) +{ + begin = read_range_or_throw( begin, end, value ); +} -#if defined( JSON_SPIRIT_WVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) - bool json_spirit::read( const std::wstring& s, wValue& value ) - { - return read_string( s, value ); - } - - void json_spirit::read_or_throw( const std::wstring& s, wValue& value ) - { - read_string_or_throw( s, value ); - } - - bool json_spirit::read( std::wistream& is, wValue& value ) - { - return read_stream( is, value ); - } - - void json_spirit::read_or_throw( std::wistream& is, wValue& value ) - { - read_stream_or_throw( is, value ); - } - - bool json_spirit::read( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wValue& value ) - { - return read_range( begin, end, value ); - } - - void json_spirit::read_or_throw( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wValue& value ) - { - begin = read_range_or_throw( begin, end, value ); - } #endif -#ifdef JSON_SPIRIT_MVALUE_ENABLED - bool json_spirit::read( const std::string& s, mValue& value ) - { - return read_string( s, value ); - } - - void json_spirit::read_or_throw( const std::string& s, mValue& value ) - { - read_string_or_throw( s, value ); - } - - bool json_spirit::read( std::istream& is, mValue& value ) - { - return read_stream( is, value ); - } - - void json_spirit::read_or_throw( std::istream& is, mValue& value ) - { - read_stream_or_throw( is, value ); - } - - bool json_spirit::read( std::string::const_iterator& begin, std::string::const_iterator end, mValue& value ) - { - return read_range( begin, end, value ); - } - - void json_spirit::read_or_throw( std::string::const_iterator& begin, std::string::const_iterator end, mValue& value ) - { - begin = read_range_or_throw( begin, end, value ); - } -#endif +bool json_spirit::read( const std::string& s, mValue& value ) +{ + return read_string( s, value ); +} + +void json_spirit::read_or_throw( const std::string& s, mValue& value ) +{ + read_string_or_throw( s, value ); +} + +bool json_spirit::read( std::istream& is, mValue& value ) +{ + return read_stream( is, value ); +} + +void json_spirit::read_or_throw( std::istream& is, mValue& value ) +{ + read_stream_or_throw( is, value ); +} + +bool json_spirit::read( std::string::const_iterator& begin, std::string::const_iterator end, mValue& value ) +{ + return read_range( begin, end, value ); +} + +void json_spirit::read_or_throw( std::string::const_iterator& begin, std::string::const_iterator end, mValue& value ) +{ + begin = read_range_or_throw( begin, end, value ); +} + +#ifndef BOOST_NO_STD_WSTRING + +bool json_spirit::read( const std::wstring& s, wmValue& value ) +{ + return read_string( s, value ); +} + +void json_spirit::read_or_throw( const std::wstring& s, wmValue& value ) +{ + read_string_or_throw( s, value ); +} + +bool json_spirit::read( std::wistream& is, wmValue& value ) +{ + return read_stream( is, value ); +} + +void json_spirit::read_or_throw( std::wistream& is, wmValue& value ) +{ + read_stream_or_throw( is, value ); +} + +bool json_spirit::read( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wmValue& value ) +{ + return read_range( begin, end, value ); +} + +void json_spirit::read_or_throw( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wmValue& value ) +{ + begin = read_range_or_throw( begin, end, value ); +} -#if defined( JSON_SPIRIT_WMVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) - bool json_spirit::read( const std::wstring& s, wmValue& value ) - { - return read_string( s, value ); - } - - void json_spirit::read_or_throw( const std::wstring& s, wmValue& value ) - { - read_string_or_throw( s, value ); - } - - bool json_spirit::read( std::wistream& is, wmValue& value ) - { - return read_stream( is, value ); - } - - void json_spirit::read_or_throw( std::wistream& is, wmValue& value ) - { - read_stream_or_throw( is, value ); - } - - bool json_spirit::read( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wmValue& value ) - { - return read_range( begin, end, value ); - } - - void json_spirit::read_or_throw( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wmValue& value ) - { - begin = read_range_or_throw( begin, end, value ); - } #endif diff --git a/src/json/json_spirit_reader.h b/src/json/json_spirit_reader.h index f0dc5330f2..96494a9789 100644 --- a/src/json/json_spirit_reader.h +++ b/src/json/json_spirit_reader.h @@ -1,10 +1,10 @@ #ifndef JSON_SPIRIT_READER #define JSON_SPIRIT_READER -// Copyright John W. Wilkinson 2007 - 2013 +// Copyright John W. Wilkinson 2007 - 2009. // Distributed under the MIT License, see accompanying file LICENSE.txt -// json spirit version 4.06 +// json spirit version 4.03 #if defined(_MSC_VER) && (_MSC_VER >= 1020) # pragma once @@ -18,7 +18,6 @@ namespace json_spirit { // functions to reads a JSON values -#ifdef JSON_SPIRIT_VALUE_ENABLED bool read( const std::string& s, Value& value ); bool read( std::istream& is, Value& value ); bool read( std::string::const_iterator& begin, std::string::const_iterator end, Value& value ); @@ -26,9 +25,9 @@ namespace json_spirit void read_or_throw( const std::string& s, Value& value ); void read_or_throw( std::istream& is, Value& value ); void read_or_throw( std::string::const_iterator& begin, std::string::const_iterator end, Value& value ); -#endif -#if defined( JSON_SPIRIT_WVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) +#ifndef BOOST_NO_STD_WSTRING + bool read( const std::wstring& s, wValue& value ); bool read( std::wistream& is, wValue& value ); bool read( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wValue& value ); @@ -36,9 +35,9 @@ namespace json_spirit void read_or_throw( const std::wstring& s, wValue& value ); void read_or_throw( std::wistream& is, wValue& value ); void read_or_throw( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wValue& value ); + #endif -#ifdef JSON_SPIRIT_MVALUE_ENABLED bool read( const std::string& s, mValue& value ); bool read( std::istream& is, mValue& value ); bool read( std::string::const_iterator& begin, std::string::const_iterator end, mValue& value ); @@ -46,9 +45,9 @@ namespace json_spirit void read_or_throw( const std::string& s, mValue& value ); void read_or_throw( std::istream& is, mValue& value ); void read_or_throw( std::string::const_iterator& begin, std::string::const_iterator end, mValue& value ); -#endif -#if defined( JSON_SPIRIT_WMVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) +#ifndef BOOST_NO_STD_WSTRING + bool read( const std::wstring& s, wmValue& value ); bool read( std::wistream& is, wmValue& value ); bool read( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wmValue& value ); @@ -56,6 +55,7 @@ namespace json_spirit void read_or_throw( const std::wstring& s, wmValue& value ); void read_or_throw( std::wistream& is, wmValue& value ); void read_or_throw( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wmValue& value ); + #endif } diff --git a/src/json/json_spirit_reader_template.h b/src/json/json_spirit_reader_template.h index d3d0cecaa5..4dec00e6c9 100644 --- a/src/json/json_spirit_reader_template.h +++ b/src/json/json_spirit_reader_template.h @@ -1,14 +1,10 @@ #ifndef JSON_SPIRIT_READER_TEMPLATE #define JSON_SPIRIT_READER_TEMPLATE -// Copyright John W. Wilkinson 2007 - 2013 +// Copyright John W. Wilkinson 2007 - 2009. // Distributed under the MIT License, see accompanying file LICENSE.txt -// json spirit version 4.06 - -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once -#endif +// json spirit version 4.03 #include "json_spirit_value.h" #include "json_spirit_error_position.h" @@ -488,7 +484,7 @@ namespace json_spirit ; string_ - = lexeme_d // this causes white space and what would appear to be comments inside a string to be retained + = lexeme_d // this causes white space inside a string to be retained [ confix_p ( @@ -519,44 +515,6 @@ namespace json_spirit }; template< class Iter_type, class Value_type > - void add_posn_iter_and_read_range_or_throw( Iter_type begin, Iter_type end, Value_type& value ) - { - typedef spirit_namespace::position_iterator< Iter_type > Posn_iter_t; - - const Posn_iter_t posn_begin( begin, end ); - const Posn_iter_t posn_end( end, end ); - - read_range_or_throw( posn_begin, posn_end, value ); - } - - template< class Istream_type > - struct Multi_pass_iters - { - typedef typename Istream_type::char_type Char_type; - typedef std::istream_iterator< Char_type, Char_type > istream_iter; - typedef spirit_namespace::multi_pass< istream_iter > Mp_iter; - - Multi_pass_iters( Istream_type& is ) - { - is.unsetf( std::ios::skipws ); - - begin_ = spirit_namespace::make_multi_pass( istream_iter( is ) ); - end_ = spirit_namespace::make_multi_pass( istream_iter() ); - } - - Mp_iter begin_; - Mp_iter end_; - }; - - // reads a JSON Value from a pair of input iterators throwing an exception on invalid input, e.g. - // - // string::const_iterator start = str.begin(); - // const string::const_iterator next = read_range_or_throw( str.begin(), str.end(), value ); - // - // The iterator 'next' will point to the character past the - // last one read. - // - template< class Iter_type, class Value_type > Iter_type read_range_or_throw( Iter_type begin, Iter_type end, Value_type& value ) { Semantic_actions< Value_type, Iter_type > semantic_actions( value ); @@ -564,9 +522,7 @@ namespace json_spirit const spirit_namespace::parse_info< Iter_type > info = spirit_namespace::parse( begin, end, Json_grammer< Value_type, Iter_type >( semantic_actions ), - spirit_namespace::space_p | - spirit_namespace::comment_p("//") | - spirit_namespace::comment_p("/*", "*/") ); + spirit_namespace::space_p ); if( !info.hit ) { @@ -577,14 +533,17 @@ namespace json_spirit return info.stop; } - // reads a JSON Value from a pair of input iterators, e.g. - // - // string::const_iterator start = str.begin(); - // const bool success = read_string( start, str.end(), value ); - // - // The iterator 'start' will point to the character past the - // last one read. - // + template< class Iter_type, class Value_type > + void add_posn_iter_and_read_range_or_throw( Iter_type begin, Iter_type end, Value_type& value ) + { + typedef spirit_namespace::position_iterator< Iter_type > Posn_iter_t; + + const Posn_iter_t posn_begin( begin, end ); + const Posn_iter_t posn_end( end, end ); + + read_range_or_throw( posn_begin, posn_end, value ); + } + template< class Iter_type, class Value_type > bool read_range( Iter_type& begin, Iter_type end, Value_type& value ) { @@ -600,10 +559,12 @@ namespace json_spirit } } - // reads a JSON Value from a string, e.g. - // - // const bool success = read_string( str, value ); - // + template< class String_type, class Value_type > + void read_string_or_throw( const String_type& s, Value_type& value ) + { + add_posn_iter_and_read_range_or_throw( s.begin(), s.end(), value ); + } + template< class String_type, class Value_type > bool read_string( const String_type& s, Value_type& value ) { @@ -612,20 +573,25 @@ namespace json_spirit return read_range( begin, s.end(), value ); } - // reads a JSON Value from a string throwing an exception on invalid input, e.g. - // - // read_string_or_throw( is, value ); - // - template< class String_type, class Value_type > - void read_string_or_throw( const String_type& s, Value_type& value ) + template< class Istream_type > + struct Multi_pass_iters { - add_posn_iter_and_read_range_or_throw( s.begin(), s.end(), value ); - } + typedef typename Istream_type::char_type Char_type; + typedef std::istream_iterator< Char_type, Char_type > istream_iter; + typedef spirit_namespace::multi_pass< istream_iter > Mp_iter; + + Multi_pass_iters( Istream_type& is ) + { + is.unsetf( std::ios::skipws ); + + begin_ = spirit_namespace::make_multi_pass( istream_iter( is ) ); + end_ = spirit_namespace::make_multi_pass( istream_iter() ); + } + + Mp_iter begin_; + Mp_iter end_; + }; - // reads a JSON Value from a stream, e.g. - // - // const bool success = read_stream( is, value ); - // template< class Istream_type, class Value_type > bool read_stream( Istream_type& is, Value_type& value ) { @@ -634,10 +600,6 @@ namespace json_spirit return read_range( mp_iters.begin_, mp_iters.end_, value ); } - // reads a JSON Value from a stream throwing an exception on invalid input, e.g. - // - // read_stream_or_throw( is, value ); - // template< class Istream_type, class Value_type > void read_stream_or_throw( Istream_type& is, Value_type& value ) { diff --git a/src/json/json_spirit_stream_reader.h b/src/json/json_spirit_stream_reader.h index 8bbdbc0543..7e59c9adc2 100644 --- a/src/json/json_spirit_stream_reader.h +++ b/src/json/json_spirit_stream_reader.h @@ -1,10 +1,10 @@ #ifndef JSON_SPIRIT_READ_STREAM #define JSON_SPIRIT_READ_STREAM -// Copyright John W. Wilkinson 2007 - 2013 +// Copyright John W. Wilkinson 2007 - 2009. // Distributed under the MIT License, see accompanying file LICENSE.txt -// json spirit version 4.06 +// json spirit version 4.03 #if defined(_MSC_VER) && (_MSC_VER >= 1020) # pragma once diff --git a/src/json/json_spirit_utils.h b/src/json/json_spirit_utils.h index a174ac3a98..553e3b96a4 100644 --- a/src/json/json_spirit_utils.h +++ b/src/json/json_spirit_utils.h @@ -1,10 +1,10 @@ #ifndef JSON_SPIRIT_UTILS #define JSON_SPIRIT_UTILS -// Copyright John W. Wilkinson 2007 - 2013 +// Copyright John W. Wilkinson 2007 - 2009. // Distributed under the MIT License, see accompanying file LICENSE.txt -// json spirit version 4.06 +// json spirit version 4.03 #if defined(_MSC_VER) && (_MSC_VER >= 1020) # pragma once @@ -37,11 +37,9 @@ namespace json_spirit } } -#ifdef JSON_SPIRIT_VALUE_ENABLED typedef std::map< std::string, Value > Mapped_obj; -#endif -#if defined( JSON_SPIRIT_WVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) +#ifndef BOOST_NO_STD_WSTRING typedef std::map< std::wstring, wValue > wMapped_obj; #endif diff --git a/src/json/json_spirit_value.h b/src/json/json_spirit_value.h index a5020405d4..7e83a2a7e3 100644 --- a/src/json/json_spirit_value.h +++ b/src/json/json_spirit_value.h @@ -1,10 +1,10 @@ #ifndef JSON_SPIRIT_VALUE #define JSON_SPIRIT_VALUE -// Copyright John W. Wilkinson 2007 - 2013 +// Copyright John W. Wilkinson 2007 - 2009. // Distributed under the MIT License, see accompanying file LICENSE.txt -// json spirit version 4.06 +// json spirit version 4.03 #if defined(_MSC_VER) && (_MSC_VER >= 1020) # pragma once @@ -21,20 +21,11 @@ #include <boost/shared_ptr.hpp> #include <boost/variant.hpp> -// comment out the value types you don't need to reduce build times and intermediate file sizes -#define JSON_SPIRIT_VALUE_ENABLED -#define JSON_SPIRIT_WVALUE_ENABLED -#define JSON_SPIRIT_MVALUE_ENABLED -#define JSON_SPIRIT_WMVALUE_ENABLED - namespace json_spirit { enum Value_type{ obj_type, array_type, str_type, bool_type, int_type, real_type, null_type }; + static const char* Value_type_name[]={"obj", "array", "str", "bool", "int", "real", "null"}; - static std::string value_type_to_string( Value_type vtype ); - - struct Null{}; - template< class Config > // Config determines whether the value uses std::string or std::wstring and // whether JSON Objects are represented as vectors or maps class Value_impl @@ -58,12 +49,6 @@ namespace json_spirit Value_impl( boost::uint64_t value ); Value_impl( double value ); - template< class Iter > - Value_impl( Iter first, Iter last ); // constructor from containers, e.g. std::vector or std::list - - template< BOOST_VARIANT_ENUM_PARAMS( typename T ) > - Value_impl( const boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >& variant ); // constructor for compatible variant types - Value_impl( const Value_impl& other ); bool operator==( const Value_impl& lhs ) const; @@ -96,32 +81,13 @@ namespace json_spirit void check_type( const Value_type vtype ) const; - typedef boost::variant< boost::recursive_wrapper< Object >, boost::recursive_wrapper< Array >, - String_type, bool, boost::int64_t, double, Null, boost::uint64_t > Variant; + typedef boost::variant< String_type, + boost::recursive_wrapper< Object >, boost::recursive_wrapper< Array >, + bool, boost::int64_t, double > Variant; + Value_type type_; Variant v_; - - class Variant_converter_visitor : public boost::static_visitor< Variant > - { - public: - - template< typename T, typename A, template< typename, typename > class Cont > - Variant operator()( const Cont< T, A >& cont ) const - { - return Array( cont.begin(), cont.end() ); - } - - Variant operator()( int i ) const - { - return static_cast< boost::int64_t >( i ); - } - - template<class T> - Variant operator()( const T& t ) const - { - return t; - } - }; + bool is_uint64_; }; // vector objects @@ -132,10 +98,6 @@ namespace json_spirit typedef typename Config::String_type String_type; typedef typename Config::Value_type Value_type; - Pair_impl() - { - } - Pair_impl( const String_type& name, const Value_type& value ); bool operator==( const Pair_impl& lhs ) const; @@ -144,7 +106,6 @@ namespace json_spirit Value_type value_; }; -#if defined( JSON_SPIRIT_VALUE_ENABLED ) || defined( JSON_SPIRIT_WVALUE_ENABLED ) template< class String > struct Config_vector { @@ -161,32 +122,30 @@ namespace json_spirit return obj.back().value_; } - static const String_type& get_name( const Pair_type& pair ) + static String_type get_name( const Pair_type& pair ) { return pair.name_; } - static const Value_type& get_value( const Pair_type& pair ) + static Value_type get_value( const Pair_type& pair ) { return pair.value_; } }; -#endif // typedefs for ASCII -#ifdef JSON_SPIRIT_VALUE_ENABLED typedef Config_vector< std::string > Config; typedef Config::Value_type Value; typedef Config::Pair_type Pair; typedef Config::Object_type Object; typedef Config::Array_type Array; -#endif // typedefs for Unicode -#if defined( JSON_SPIRIT_WVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) +#ifndef BOOST_NO_STD_WSTRING + typedef Config_vector< std::wstring > wConfig; typedef wConfig::Value_type wValue; @@ -197,7 +156,6 @@ namespace json_spirit // map objects -#if defined( JSON_SPIRIT_MVALUE_ENABLED ) || defined( JSON_SPIRIT_WMVALUE_ENABLED ) template< class String > struct Config_map { @@ -205,134 +163,135 @@ namespace json_spirit typedef Value_impl< Config_map > Value_type; typedef std::vector< Value_type > Array_type; typedef std::map< String_type, Value_type > Object_type; - typedef std::pair< const String_type, Value_type > Pair_type; + typedef typename Object_type::value_type Pair_type; static Value_type& add( Object_type& obj, const String_type& name, const Value_type& value ) { return obj[ name ] = value; } - static const String_type& get_name( const Pair_type& pair ) + static String_type get_name( const Pair_type& pair ) { return pair.first; } - static const Value_type& get_value( const Pair_type& pair ) + static Value_type get_value( const Pair_type& pair ) { return pair.second; } }; -#endif // typedefs for ASCII -#ifdef JSON_SPIRIT_MVALUE_ENABLED typedef Config_map< std::string > mConfig; typedef mConfig::Value_type mValue; typedef mConfig::Object_type mObject; typedef mConfig::Array_type mArray; -#endif // typedefs for Unicode -#if defined( JSON_SPIRIT_WMVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) +#ifndef BOOST_NO_STD_WSTRING + typedef Config_map< std::wstring > wmConfig; typedef wmConfig::Value_type wmValue; typedef wmConfig::Object_type wmObject; typedef wmConfig::Array_type wmArray; + #endif /////////////////////////////////////////////////////////////////////////////////////////////// // // implementation - inline bool operator==( const Null&, const Null& ) - { - return true; - } - template< class Config > const Value_impl< Config > Value_impl< Config >::null; template< class Config > Value_impl< Config >::Value_impl() - : v_( Null() ) + : type_( null_type ) + , is_uint64_( false ) { } template< class Config > Value_impl< Config >::Value_impl( const Const_str_ptr value ) - : v_( String_type( value ) ) + : type_( str_type ) + , v_( String_type( value ) ) + , is_uint64_( false ) { } template< class Config > Value_impl< Config >::Value_impl( const String_type& value ) - : v_( value ) + : type_( str_type ) + , v_( value ) + , is_uint64_( false ) { } template< class Config > Value_impl< Config >::Value_impl( const Object& value ) - : v_( value ) + : type_( obj_type ) + , v_( value ) + , is_uint64_( false ) { } template< class Config > Value_impl< Config >::Value_impl( const Array& value ) - : v_( value ) + : type_( array_type ) + , v_( value ) + , is_uint64_( false ) { } template< class Config > Value_impl< Config >::Value_impl( bool value ) - : v_( value ) + : type_( bool_type ) + , v_( value ) + , is_uint64_( false ) { } template< class Config > Value_impl< Config >::Value_impl( int value ) - : v_( static_cast< boost::int64_t >( value ) ) + : type_( int_type ) + , v_( static_cast< boost::int64_t >( value ) ) + , is_uint64_( false ) { } template< class Config > Value_impl< Config >::Value_impl( boost::int64_t value ) - : v_( value ) + : type_( int_type ) + , v_( value ) + , is_uint64_( false ) { } template< class Config > Value_impl< Config >::Value_impl( boost::uint64_t value ) - : v_( value ) + : type_( int_type ) + , v_( static_cast< boost::int64_t >( value ) ) + , is_uint64_( true ) { } template< class Config > Value_impl< Config >::Value_impl( double value ) - : v_( value ) + : type_( real_type ) + , v_( value ) + , is_uint64_( false ) { } template< class Config > Value_impl< Config >::Value_impl( const Value_impl< Config >& other ) - : v_( other.v_ ) - { - } - - template< class Config > - template< class Iter > - Value_impl< Config >::Value_impl( Iter first, Iter last ) - : v_( Array( first, last ) ) - { - } - - template< class Config > - template< BOOST_VARIANT_ENUM_PARAMS( typename T ) > - Value_impl< Config >::Value_impl( const boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >& variant ) - : v_( boost::apply_visitor( Variant_converter_visitor(), variant) ) + : type_( other.type() ) + , v_( other.v_ ) + , is_uint64_( other.is_uint64_ ) { } @@ -341,7 +300,9 @@ namespace json_spirit { Value_impl tmp( lhs ); + std::swap( type_, tmp.type_ ); std::swap( v_, tmp.v_ ); + std::swap( is_uint64_, tmp.is_uint64_ ); return *this; } @@ -359,18 +320,13 @@ namespace json_spirit template< class Config > Value_type Value_impl< Config >::type() const { - if( is_uint64() ) - { - return int_type; - } - - return static_cast< Value_type >( v_.which() ); + return type_; } template< class Config > bool Value_impl< Config >::is_uint64() const { - return v_.which() == null_type + 1; + return is_uint64_; } template< class Config > @@ -386,7 +342,8 @@ namespace json_spirit { std::ostringstream os; - os << "get_value< " << value_type_to_string( vtype ) << " > called on " << value_type_to_string( type() ) << " Value"; + ///// Bitcoin: Tell the types by name instead of by number + os << "value is type " << Value_type_name[type()] << ", expected " << Value_type_name[vtype]; throw std::runtime_error( os.str() ); } @@ -395,7 +352,7 @@ namespace json_spirit template< class Config > const typename Config::String_type& Value_impl< Config >::get_str() const { - check_type( str_type ); + check_type( str_type ); return *boost::get< String_type >( &v_ ); } @@ -411,7 +368,7 @@ namespace json_spirit template< class Config > const typename Value_impl< Config >::Array& Value_impl< Config >::get_array() const { - check_type( array_type ); + check_type( array_type ); return *boost::get< Array >( &v_ ); } @@ -419,7 +376,7 @@ namespace json_spirit template< class Config > bool Value_impl< Config >::get_bool() const { - check_type( bool_type ); + check_type( bool_type ); return boost::get< bool >( v_ ); } @@ -427,7 +384,7 @@ namespace json_spirit template< class Config > int Value_impl< Config >::get_int() const { - check_type( int_type ); + check_type( int_type ); return static_cast< int >( get_int64() ); } @@ -435,12 +392,7 @@ namespace json_spirit template< class Config > boost::int64_t Value_impl< Config >::get_int64() const { - check_type( int_type ); - - if( is_uint64() ) - { - return static_cast< boost::int64_t >( get_uint64() ); - } + check_type( int_type ); return boost::get< boost::int64_t >( v_ ); } @@ -448,14 +400,9 @@ namespace json_spirit template< class Config > boost::uint64_t Value_impl< Config >::get_uint64() const { - check_type( int_type ); + check_type( int_type ); - if( !is_uint64() ) - { - return static_cast< boost::uint64_t >( get_int64() ); - } - - return boost::get< boost::uint64_t >( v_ ); + return static_cast< boost::uint64_t >( get_int64() ); } template< class Config > @@ -467,7 +414,7 @@ namespace json_spirit : static_cast< double >( get_int64() ); } - check_type( real_type ); + check_type( real_type ); return boost::get< double >( v_ ); } @@ -475,7 +422,7 @@ namespace json_spirit template< class Config > typename Value_impl< Config >::Object& Value_impl< Config >::get_obj() { - check_type( obj_type ); + check_type( obj_type ); return *boost::get< Object >( &v_ ); } @@ -483,7 +430,7 @@ namespace json_spirit template< class Config > typename Value_impl< Config >::Array& Value_impl< Config >::get_array() { - check_type( array_type ); + check_type( array_type ); return *boost::get< Array >( &v_ ); } @@ -582,24 +529,6 @@ namespace json_spirit { return internal_::get_value( *this, internal_::Type_to_type< T >() ); } - - static std::string value_type_to_string( const Value_type vtype ) - { - switch( vtype ) - { - case obj_type: return "Object"; - case array_type: return "Array"; - case str_type: return "string"; - case bool_type: return "boolean"; - case int_type: return "integer"; - case real_type: return "real"; - case null_type: return "null"; - } - - assert( false ); - - return "unknown type"; - } } #endif diff --git a/src/json/json_spirit_writer.cpp b/src/json/json_spirit_writer.cpp index 06d3f21d91..d24a632cf3 100644 --- a/src/json/json_spirit_writer.cpp +++ b/src/json/json_spirit_writer.cpp @@ -1,96 +1,95 @@ -// Copyright John W. Wilkinson 2007 - 2013 +// Copyright John W. Wilkinson 2007 - 2009. // Distributed under the MIT License, see accompanying file LICENSE.txt -// json spirit version 4.06 +// json spirit version 4.03 #include "json_spirit_writer.h" #include "json_spirit_writer_template.h" -using namespace json_spirit; - -#ifdef JSON_SPIRIT_VALUE_ENABLED - void json_spirit::write( const Value& value, std::ostream& os, unsigned int options ) - { - write_stream( value, os, options ); - } - std::string json_spirit::write( const Value& value, unsigned int options ) - { - return write_string( value, options ); - } - - void json_spirit::write_formatted( const Value& value, std::ostream& os ) - { - write_stream( value, os, pretty_print ); - } - - std::string json_spirit::write_formatted( const Value& value ) - { - return write_string( value, pretty_print ); - } -#endif +void json_spirit::write( const Value& value, std::ostream& os ) +{ + write_stream( value, os, false ); +} -#ifdef JSON_SPIRIT_MVALUE_ENABLED - void json_spirit::write( const mValue& value, std::ostream& os, unsigned int options ) - { - write_stream( value, os, options ); - } - - std::string json_spirit::write( const mValue& value, unsigned int options ) - { - return write_string( value, options ); - } - - void json_spirit::write_formatted( const mValue& value, std::ostream& os ) - { - write_stream( value, os, pretty_print ); - } - - std::string json_spirit::write_formatted( const mValue& value ) - { - return write_string( value, pretty_print ); - } -#endif +void json_spirit::write_formatted( const Value& value, std::ostream& os ) +{ + write_stream( value, os, true ); +} + +std::string json_spirit::write( const Value& value ) +{ + return write_string( value, false ); +} + +std::string json_spirit::write_formatted( const Value& value ) +{ + return write_string( value, true ); +} + +#ifndef BOOST_NO_STD_WSTRING + +void json_spirit::write( const wValue& value, std::wostream& os ) +{ + write_stream( value, os, false ); +} + +void json_spirit::write_formatted( const wValue& value, std::wostream& os ) +{ + write_stream( value, os, true ); +} + +std::wstring json_spirit::write( const wValue& value ) +{ + return write_string( value, false ); +} + +std::wstring json_spirit::write_formatted( const wValue& value ) +{ + return write_string( value, true ); +} -#if defined( JSON_SPIRIT_WVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) - void json_spirit::write( const wValue& value, std::wostream& os, unsigned int options ) - { - write_stream( value, os, options ); - } - - std::wstring json_spirit::write( const wValue& value, unsigned int options ) - { - return write_string( value, options ); - } - - void json_spirit::write_formatted( const wValue& value, std::wostream& os ) - { - write_stream( value, os, pretty_print ); - } - - std::wstring json_spirit::write_formatted( const wValue& value ) - { - return write_string( value, pretty_print ); - } #endif -#if defined( JSON_SPIRIT_WMVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) - void json_spirit::write_formatted( const wmValue& value, std::wostream& os ) - { - write_stream( value, os, pretty_print ); - } - - std::wstring json_spirit::write_formatted( const wmValue& value ) - { - return write_string( value, pretty_print ); - } - - void json_spirit::write( const wmValue& value, std::wostream& os, unsigned int options ) - { - write_stream( value, os, options ); - } - - std::wstring json_spirit::write( const wmValue& value, unsigned int options ) - { - return write_string( value, options ); - } +void json_spirit::write( const mValue& value, std::ostream& os ) +{ + write_stream( value, os, false ); +} + +void json_spirit::write_formatted( const mValue& value, std::ostream& os ) +{ + write_stream( value, os, true ); +} + +std::string json_spirit::write( const mValue& value ) +{ + return write_string( value, false ); +} + +std::string json_spirit::write_formatted( const mValue& value ) +{ + return write_string( value, true ); +} + +#ifndef BOOST_NO_STD_WSTRING + +void json_spirit::write( const wmValue& value, std::wostream& os ) +{ + write_stream( value, os, false ); +} + +void json_spirit::write_formatted( const wmValue& value, std::wostream& os ) +{ + write_stream( value, os, true ); +} + +std::wstring json_spirit::write( const wmValue& value ) +{ + return write_string( value, false ); +} + +std::wstring json_spirit::write_formatted( const wmValue& value ) +{ + return write_string( value, true ); +} + #endif diff --git a/src/json/json_spirit_writer.h b/src/json/json_spirit_writer.h index 18c2fd4264..52e14068e7 100644 --- a/src/json/json_spirit_writer.h +++ b/src/json/json_spirit_writer.h @@ -1,62 +1,49 @@ #ifndef JSON_SPIRIT_WRITER #define JSON_SPIRIT_WRITER -// Copyright John W. Wilkinson 2007 - 2013 +// Copyright John W. Wilkinson 2007 - 2009. // Distributed under the MIT License, see accompanying file LICENSE.txt -// json spirit version 4.06 +// json spirit version 4.03 #if defined(_MSC_VER) && (_MSC_VER >= 1020) # pragma once #endif #include "json_spirit_value.h" -#include "json_spirit_writer_options.h" #include <iostream> namespace json_spirit { - // these functions to convert JSON Values to text + // functions to convert JSON Values to text, + // the "formatted" versions add whitespace to format the output nicely -#ifdef JSON_SPIRIT_VALUE_ENABLED - void write( const Value& value, std::ostream& os, unsigned int options = 0 ); - std::string write( const Value& value, unsigned int options = 0 ); -#endif + void write ( const Value& value, std::ostream& os ); + void write_formatted( const Value& value, std::ostream& os ); + std::string write ( const Value& value ); + std::string write_formatted( const Value& value ); -#ifdef JSON_SPIRIT_MVALUE_ENABLED - void write( const mValue& value, std::ostream& os, unsigned int options = 0 ); - std::string write( const mValue& value, unsigned int options = 0 ); -#endif +#ifndef BOOST_NO_STD_WSTRING -#if defined( JSON_SPIRIT_WVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) - void write( const wValue& value, std::wostream& os, unsigned int options = 0 ); - std::wstring write( const wValue& value, unsigned int options = 0 ); -#endif + void write ( const wValue& value, std::wostream& os ); + void write_formatted( const wValue& value, std::wostream& os ); + std::wstring write ( const wValue& value ); + std::wstring write_formatted( const wValue& value ); -#if defined( JSON_SPIRIT_WMVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) - void write( const wmValue& value, std::wostream& os, unsigned int options = 0 ); - std::wstring write( const wmValue& value, unsigned int options = 0 ); #endif - // these "formatted" versions of the "write" functions are the equivalent of the above functions - // with option "pretty_print" - -#ifdef JSON_SPIRIT_VALUE_ENABLED - void write_formatted( const Value& value, std::ostream& os ); - std::string write_formatted( const Value& value ); -#endif -#ifdef JSON_SPIRIT_MVALUE_ENABLED + void write ( const mValue& value, std::ostream& os ); void write_formatted( const mValue& value, std::ostream& os ); + std::string write ( const mValue& value ); std::string write_formatted( const mValue& value ); -#endif -#if defined( JSON_SPIRIT_WVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) - void write_formatted( const wValue& value, std::wostream& os ); - std::wstring write_formatted( const wValue& value ); -#endif -#if defined( JSON_SPIRIT_WMVALUE_ENABLED ) && !defined( BOOST_NO_STD_WSTRING ) +#ifndef BOOST_NO_STD_WSTRING + + void write ( const wmValue& value, std::wostream& os ); void write_formatted( const wmValue& value, std::wostream& os ); + std::wstring write ( const wmValue& value ); std::wstring write_formatted( const wmValue& value ); + #endif } diff --git a/src/json/json_spirit_writer_options.h b/src/json/json_spirit_writer_options.h deleted file mode 100644 index ac6c57f33c..0000000000 --- a/src/json/json_spirit_writer_options.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef JSON_SPIRIT_WRITER_OPTIONS -#define JSON_SPIRIT_WRITER_OPTIONS - -// Copyright John W. Wilkinson 2007 - 2013 -// Distributed under the MIT License, see accompanying file LICENSE.txt - -// json spirit version 4.06 - -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once -#endif - -namespace json_spirit -{ - enum Output_options{ pretty_print = 0x01, // Add whitespace to format the output nicely. - - raw_utf8 = 0x02, // This prevents non-printable characters from being escapted using "\uNNNN" notation. - // Note, this is an extension to the JSON standard. It disables the escaping of - // non-printable characters allowing UTF-8 sequences held in 8 bit char strings - // to pass through unaltered. - - remove_trailing_zeros = 0x04, - // outputs e.g. "1.200000000000000" as "1.2" - single_line_arrays = 0x08, - // pretty printing except that arrays printed on single lines unless they contain - // composite elements, i.e. objects or arrays - always_escape_nonascii = 0x10, - // all unicode wide characters are escaped, i.e. outputed as "\uXXXX", even if they are - // printable under the current locale, ascii printable chars are not escaped - }; -} - -#endif diff --git a/src/json/json_spirit_writer_template.h b/src/json/json_spirit_writer_template.h index 014d9d4cd0..28c49ddc64 100644 --- a/src/json/json_spirit_writer_template.h +++ b/src/json/json_spirit_writer_template.h @@ -1,22 +1,16 @@ #ifndef JSON_SPIRIT_WRITER_TEMPLATE #define JSON_SPIRIT_WRITER_TEMPLATE -// Copyright John W. Wilkinson 2007 - 2013 +// Copyright John W. Wilkinson 2007 - 2009. // Distributed under the MIT License, see accompanying file LICENSE.txt -// json spirit version 4.06 - -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once -#endif +// json spirit version 4.03 #include "json_spirit_value.h" -#include "json_spirit_writer_options.h" #include <cassert> #include <sstream> #include <iomanip> -#include <boost/io/ios_state.hpp> namespace json_spirit { @@ -66,7 +60,7 @@ namespace json_spirit } template< class String_type > - String_type add_esc_chars( const String_type& s, bool raw_utf8, bool esc_nonascii ) + String_type add_esc_chars( const String_type& s ) { typedef typename String_type::const_iterator Iter_type; typedef typename String_type::value_type Char_type; @@ -81,80 +75,21 @@ namespace json_spirit if( add_esc_char( c, result ) ) continue; - if( raw_utf8 ) + const wint_t unsigned_c( ( c >= 0 ) ? c : 256 + c ); + + if( iswprint( unsigned_c ) ) { result += c; } else { - const wint_t unsigned_c( ( c >= 0 ) ? c : 256 + c ); - - if( !esc_nonascii && iswprint( unsigned_c ) ) - { - result += c; - } - else - { - result += non_printable_to_string< String_type >( unsigned_c ); - } - } - } - - return result; - } - - template< class Ostream > - void append_double( Ostream& os, const double d, const int precision ) - { - os << std::showpoint << std::setprecision( precision ) << d; - } - - template< class String_type > - void erase_and_extract_exponent( String_type& str, String_type& exp ) - { - const typename String_type::size_type exp_start= str.find( 'e' ); - - if( exp_start != String_type::npos ) - { - exp = str.substr( exp_start ); - str.erase( exp_start ); - } - } - - template< class String_type > - typename String_type::size_type find_first_non_zero( const String_type& str ) - { - typename String_type::size_type result = str.size() - 1; - - for( ; result != 0; --result ) - { - if( str[ result ] != '0' ) - { - break; + result += non_printable_to_string< String_type >( unsigned_c ); } } return result; } - template< class String_type > - void remove_trailing( String_type& str ) - { - String_type exp; - - erase_and_extract_exponent( str, exp ); - - const typename String_type::size_type first_non_zero = find_first_non_zero( str ); - - if( first_non_zero != 0 ) - { - const int offset = str[first_non_zero] == '.' ? 2 : 1; // note zero digits following a decimal point is non standard - str.erase( first_non_zero + offset ); - } - - str += exp; - } - // this class generates the JSON text, // it keeps track of the indentation level etc. // @@ -170,15 +105,10 @@ namespace json_spirit public: - Generator( const Value_type& value, Ostream_type& os, unsigned int options ) + Generator( const Value_type& value, Ostream_type& os, bool pretty ) : os_( os ) , indentation_level_( 0 ) - , pretty_( ( options & pretty_print ) != 0 || ( options & single_line_arrays ) != 0 ) - , raw_utf8_( ( options & raw_utf8 ) != 0 ) - , esc_nonascii_( ( options & always_escape_nonascii ) != 0 ) - , remove_trailing_zeros_( ( options & remove_trailing_zeros ) != 0 ) - , single_line_arrays_( ( options & single_line_arrays ) != 0 ) - , ios_saver_( os ) + , pretty_( pretty ) { output( value ); } @@ -193,8 +123,12 @@ namespace json_spirit case array_type: output( value.get_array() ); break; case str_type: output( value.get_str() ); break; case bool_type: output( value.get_bool() ); break; - case real_type: output( value.get_real() ); break; case int_type: output_int( value ); break; + + /// Bitcoin: Added std::fixed and changed precision from 16 to 8 + case real_type: os_ << std::showpoint << std::fixed << std::setprecision(8) + << value.get_real(); break; + case null_type: os_ << "null"; break; default: assert( false ); } @@ -205,6 +139,11 @@ namespace json_spirit output_array_or_obj( obj, '{', '}' ); } + void output( const Array_type& arr ) + { + output_array_or_obj( arr, '[', ']' ); + } + void output( const Obj_member_type& member ) { output( Config_type::get_name( member ) ); space(); @@ -226,7 +165,7 @@ namespace json_spirit void output( const String_type& s ) { - os_ << '"' << add_esc_chars( s, raw_utf8_, esc_nonascii_ ) << '"'; + os_ << '"' << add_esc_chars( s ) << '"'; } void output( bool b ) @@ -234,75 +173,6 @@ namespace json_spirit os_ << to_str< String_type >( b ? "true" : "false" ); } - void output( double d ) - { - if( remove_trailing_zeros_ ) - { - std::basic_ostringstream< Char_type > os; - - append_double( os, d, 16 ); // note precision is 16 so that we get some trailing space that we can remove, - // otherwise, 0.1234 gets converted to "0.12399999..." - - String_type str = os.str(); - - remove_trailing( str ); - - os_ << str; - } - else - { - append_double( os_, d, 17 ); - } - } - - static bool contains_composite_elements( const Array_type& arr ) - { - for( typename Array_type::const_iterator i = arr.begin(); i != arr.end(); ++i ) - { - const Value_type& val = *i; - - if( val.type() == obj_type || - val.type() == array_type ) - { - return true; - } - } - - return false; - } - - template< class Iter > - void output_composite_item( Iter i, Iter last ) - { - output( *i ); - - if( ++i != last ) - { - os_ << ','; - } - } - - void output( const Array_type& arr ) - { - if( single_line_arrays_ && !contains_composite_elements( arr ) ) - { - os_ << '['; space(); - - for( typename Array_type::const_iterator i = arr.begin(); i != arr.end(); ++i ) - { - output_composite_item( i, arr.end() ); - - space(); - } - - os_ << ']'; - } - else - { - output_array_or_obj( arr, '[', ']' ); - } - } - template< class T > void output_array_or_obj( const T& t, Char_type start_char, Char_type end_char ) { @@ -312,9 +182,14 @@ namespace json_spirit for( typename T::const_iterator i = t.begin(); i != t.end(); ++i ) { - indent(); + indent(); output( *i ); - output_composite_item( i, t.end() ); + typename T::const_iterator next = i; + + if( ++next != t.end()) + { + os_ << ','; + } new_line(); } @@ -349,36 +224,22 @@ namespace json_spirit Ostream_type& os_; int indentation_level_; bool pretty_; - bool raw_utf8_; - bool esc_nonascii_; - bool remove_trailing_zeros_; - bool single_line_arrays_; - boost::io::basic_ios_all_saver< Char_type > ios_saver_; // so that ostream state is reset after control is returned to the caller }; - // writes JSON Value to a stream, e.g. - // - // write_stream( value, os, pretty_print ); - // template< class Value_type, class Ostream_type > - void write_stream( const Value_type& value, Ostream_type& os, unsigned int options = 0 ) + void write_stream( const Value_type& value, Ostream_type& os, bool pretty ) { - os << std::dec; - Generator< Value_type, Ostream_type >( value, os, options ); + Generator< Value_type, Ostream_type >( value, os, pretty ); } - // writes JSON Value to a stream, e.g. - // - // const string json_str = write( value, pretty_print ); - // template< class Value_type > - typename Value_type::String_type write_string( const Value_type& value, unsigned int options = 0 ) + typename Value_type::String_type write_string( const Value_type& value, bool pretty ) { typedef typename Value_type::String_type::value_type Char_type; std::basic_ostringstream< Char_type > os; - write_stream( value, os, options ); + write_stream( value, os, pretty ); return os.str(); } @@ -205,7 +205,8 @@ public: } friend bool operator==(const CKey &a, const CKey &b) { - return a.fCompressed == b.fCompressed && memcmp(&a.vch[0], &b.vch[0], 32); + return a.fCompressed == b.fCompressed && a.size() == b.size() && + memcmp(&a.vch[0], &b.vch[0], a.size()) == 0; } // Initialize using begin and end iterators to byte data. @@ -261,9 +262,9 @@ public: // Derive BIP32 child key. bool Derive(CKey& keyChild, unsigned char ccChild[32], unsigned int nChild, const unsigned char cc[32]) const; - + // Load private key and check that public key matches. - bool Load(CPrivKey &privkey, CPubKey &vchPubKey, bool fSkipCheck); + bool Load(CPrivKey &privkey, CPubKey &vchPubKey, bool fSkipCheck); }; struct CExtPubKey { diff --git a/src/main.cpp b/src/main.cpp index 01a1babc7f..875cd67341 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -49,7 +49,7 @@ int64 CTransaction::nMinTxFee = 10000; // Override with -mintxfee /** Fees smaller than this (in satoshi) are considered zero fee (for relaying) */ int64 CTransaction::nMinRelayTxFee = 10000; -CMedianFilter<int> cPeerBlockCounts(8, 0); // Amount of blocks that other nodes claim to have +static CMedianFilter<int> cPeerBlockCounts(8, 0); // Amount of blocks that other nodes claim to have map<uint256, CBlock*> mapOrphanBlocks; multimap<uint256, CBlock*> mapOrphanBlocksByPrev; @@ -74,93 +74,52 @@ int64 nTransactionFee = 0; // These functions dispatch to one or all registered wallets - -void RegisterWallet(CWallet* pwalletIn) -{ - { - LOCK(cs_setpwalletRegistered); - setpwalletRegistered.insert(pwalletIn); - } -} - -void UnregisterWallet(CWallet* pwalletIn) -{ - { - LOCK(cs_setpwalletRegistered); - setpwalletRegistered.erase(pwalletIn); - } +namespace { +struct CMainSignals { + // Notifies listeners of updated transaction data (passing hash, transaction, and optionally the block it is found in. + boost::signals2::signal<void (const uint256 &, const CTransaction &, const CBlock *)> SyncTransaction; + // Notifies listeners of an erased transaction (currently disabled, requires transaction replacement). + boost::signals2::signal<void (const uint256 &)> EraseTransaction; + // Notifies listeners of an updated transaction without new data (for now: a coinbase potentially becoming visible). + boost::signals2::signal<void (const uint256 &)> UpdatedTransaction; + // Notifies listeners of a new active block chain. + boost::signals2::signal<void (const CBlockLocator &)> SetBestChain; + // Notifies listeners about an inventory item being seen on the network. + boost::signals2::signal<void (const uint256 &)> Inventory; + // Tells listeners to broadcast their data. + boost::signals2::signal<void ()> Broadcast; +} g_signals; } -void UnregisterAllWallets() -{ - LOCK(cs_setpwalletRegistered); - setpwalletRegistered.clear(); +void RegisterWallet(CWalletInterface* pwalletIn) { + g_signals.SyncTransaction.connect(boost::bind(&CWalletInterface::SyncTransaction, pwalletIn, _1, _2, _3)); + g_signals.EraseTransaction.connect(boost::bind(&CWalletInterface::EraseFromWallet, pwalletIn, _1)); + g_signals.UpdatedTransaction.connect(boost::bind(&CWalletInterface::UpdatedTransaction, pwalletIn, _1)); + g_signals.SetBestChain.connect(boost::bind(&CWalletInterface::SetBestChain, pwalletIn, _1)); + g_signals.Inventory.connect(boost::bind(&CWalletInterface::Inventory, pwalletIn, _1)); + g_signals.Broadcast.connect(boost::bind(&CWalletInterface::ResendWalletTransactions, pwalletIn)); } -// get the wallet transaction with the given hash (if it exists) -bool static GetTransaction(const uint256& hashTx, CWalletTx& wtx) -{ - LOCK(cs_setpwalletRegistered); - BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) - if (pwallet->GetTransaction(hashTx,wtx)) - return true; - return false; +void UnregisterWallet(CWalletInterface* pwalletIn) { + g_signals.Broadcast.disconnect(boost::bind(&CWalletInterface::ResendWalletTransactions, pwalletIn)); + g_signals.Inventory.disconnect(boost::bind(&CWalletInterface::Inventory, pwalletIn, _1)); + g_signals.SetBestChain.disconnect(boost::bind(&CWalletInterface::SetBestChain, pwalletIn, _1)); + g_signals.UpdatedTransaction.disconnect(boost::bind(&CWalletInterface::UpdatedTransaction, pwalletIn, _1)); + g_signals.EraseTransaction.disconnect(boost::bind(&CWalletInterface::EraseFromWallet, pwalletIn, _1)); + g_signals.SyncTransaction.disconnect(boost::bind(&CWalletInterface::SyncTransaction, pwalletIn, _1, _2, _3)); } -// erases transaction with the given hash from all wallets -void static EraseFromWallets(uint256 hash) -{ - LOCK(cs_setpwalletRegistered); - BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) - pwallet->EraseFromWallet(hash); +void UnregisterAllWallets() { + g_signals.Broadcast.disconnect_all_slots(); + g_signals.Inventory.disconnect_all_slots(); + g_signals.SetBestChain.disconnect_all_slots(); + g_signals.UpdatedTransaction.disconnect_all_slots(); + g_signals.EraseTransaction.disconnect_all_slots(); + g_signals.SyncTransaction.disconnect_all_slots(); } -// make sure all wallets know about the given transaction, in the given block -void SyncWithWallets(const uint256 &hash, const CTransaction& tx, const CBlock* pblock, bool fUpdate) -{ - LOCK(cs_setpwalletRegistered); - BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) - pwallet->AddToWalletIfInvolvingMe(hash, tx, pblock, fUpdate); -} - -// notify wallets about a new best chain -void static SetBestChain(const CBlockLocator& loc) -{ - LOCK(cs_setpwalletRegistered); - BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) - pwallet->SetBestChain(loc); -} - -// notify wallets about an updated transaction -void static UpdatedTransaction(const uint256& hashTx) -{ - LOCK(cs_setpwalletRegistered); - BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) - pwallet->UpdatedTransaction(hashTx); -} - -// dump all wallets -void static PrintWallets(const CBlock& block) -{ - LOCK(cs_setpwalletRegistered); - BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) - pwallet->PrintWallet(block); -} - -// notify wallets about an incoming inventory (for request counts) -void static Inventory(const uint256& hash) -{ - LOCK(cs_setpwalletRegistered); - BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) - pwallet->Inventory(hash); -} - -// ask wallets to resend their transactions -void static ResendWalletTransactions() -{ - LOCK(cs_setpwalletRegistered); - BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) - pwallet->ResendWalletTransactions(); +void SyncWithWallets(const uint256 &hash, const CTransaction &tx, const CBlock *pblock) { + g_signals.SyncTransaction(hash, tx, pblock); } ////////////////////////////////////////////////////////////////////////////// @@ -931,8 +890,8 @@ bool CTxMemPool::accept(CValidationState &state, const CTransaction &tx, bool fL ///// are we sure this is ok when loading transactions or restoring block txes // If updated, erase old tx from wallet if (ptxOld) - EraseFromWallets(ptxOld->GetHash()); - SyncWithWallets(hash, tx, NULL, true); + g_signals.EraseTransaction(ptxOld->GetHash()); + g_signals.SyncTransaction(hash, tx, NULL); LogPrint("mempool", "CTxMemPool::accept() : accepted %s (poolsz %"PRIszu")\n", hash.ToString().c_str(), @@ -1095,27 +1054,6 @@ bool CMerkleTx::AcceptToMemoryPool(bool fLimitFree) } - -bool CWalletTx::AcceptWalletTransaction() -{ - { - LOCK(mempool.cs); - // Add previous supporting transactions first - BOOST_FOREACH(CMerkleTx& tx, vtxPrev) - { - if (!tx.IsCoinBase()) - { - uint256 hash = tx.GetHash(); - if (!mempool.exists(hash) && pcoinsTip->HaveCoins(hash)) - tx.AcceptToMemoryPool(false); - } - } - return AcceptToMemoryPool(false); - } - return false; -} - - // Return transaction in tx, and if it was found inside a block, its hash is placed in hashBlock bool GetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock, bool fAllowSlow) { @@ -1750,12 +1688,12 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex const CTransaction &tx = block.vtx[i]; uint256 hash = tx.GetHash(); - // check that all outputs are available - if (!view.HaveCoins(hash)) { - fClean = fClean && error("DisconnectBlock() : outputs still spent? database corrupted"); - view.SetCoins(hash, CCoins()); - } - CCoins &outs = view.GetCoins(hash); + // Check that all outputs are available and match the outputs in the block itself + // exactly. Note that transactions with only provably unspendable outputs won't + // have outputs available even in the block itself, so we handle that case + // specially with outsEmpty. + CCoins outsEmpty; + CCoins &outs = view.HaveCoins(hash) ? view.GetCoins(hash) : outsEmpty; outs.ClearUnspendable(); CCoins outsBlock = CCoins(tx, pindex->nHeight); @@ -1992,7 +1930,7 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C // Watch for transactions paying to me for (unsigned int i = 0; i < block.vtx.size(); i++) - SyncWithWallets(block.GetTxHash(i), block.vtx[i], &block, true); + g_signals.SyncTransaction(block.GetTxHash(i), block.vtx[i], &block); return true; } @@ -2126,7 +2064,7 @@ bool SetBestChain(CValidationState &state, CBlockIndex* pindexNew) // Update best block in wallet (so we can detect restored wallets) if ((pindexNew->nHeight % 20160) == 0 || (!fIsInitialDownload && (pindexNew->nHeight % 144) == 0)) - ::SetBestChain(chainActive.GetLocator(pindexNew)); + g_signals.SetBestChain(chainActive.GetLocator(pindexNew)); // New best block nTimeBestReceived = GetTime(); @@ -2206,7 +2144,7 @@ bool AddToBlockIndex(CBlock& block, CValidationState& state, const CDiskBlockPos CheckForkWarningConditions(); // Notify UI to display prev block's coinbase if it was ours static uint256 hashPrevBestCoinBase; - UpdatedTransaction(hashPrevBestCoinBase); + g_signals.UpdatedTransaction(hashPrevBestCoinBase); hashPrevBestCoinBase = block.GetTxHash(0); } else CheckForkWarningConditionsOnNewFork(pindexNew); @@ -2355,7 +2293,7 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo uniqueTx.insert(block.GetTxHash(i)); } if (uniqueTx.size() != block.vtx.size()) - return state.DoS(100, error("CheckBlock() : duplicate transaction")); + return state.DoS(100, error("CheckBlock() : duplicate transaction"), true); unsigned int nSigOps = 0; BOOST_FOREACH(const CTransaction& tx, block.vtx) @@ -3041,8 +2979,6 @@ void PrintBlockTree() DateTimeStrFormat("%Y-%m-%d %H:%M:%S", block.GetBlockTime()).c_str(), block.vtx.size()); - PrintWallets(block); - // put the main time-chain first vector<CBlockIndex*>& vNext = mapNext[pindex]; for (unsigned int i = 0; i < vNext.size(); i++) @@ -3331,7 +3267,7 @@ void static ProcessGetData(CNode* pfrom) } // Track requests for our stuff. - Inventory(inv.hash); + g_signals.Inventory(inv.hash); } } @@ -3460,8 +3396,9 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) 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()); - LOCK(cs_main); AddTimeData(pfrom->addr, nTime); + + LOCK(cs_main); cPeerBlockCounts.input(pfrom->nStartingHeight); } @@ -3593,7 +3530,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) } // Track requests for our stuff - Inventory(inv.hash); + g_signals.Inventory(inv.hash); } } @@ -3608,10 +3545,10 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) return error("message getdata size() = %"PRIszu"", vInv.size()); } - if (fDebugNet || (vInv.size() != 1)) + if (fDebug || (vInv.size() != 1)) LogPrint("net", "received getdata (%"PRIszu" invsz)\n", vInv.size()); - if ((fDebugNet && vInv.size() > 0) || (vInv.size() == 1)) + if ((fDebug && vInv.size() > 0) || (vInv.size() == 1)) LogPrint("net", "received getdata for: %s\n", vInv[0].ToString().c_str()); pfrom->vRecvGetData.insert(pfrom->vRecvGetData.end(), vInv.begin(), vInv.end()); @@ -3783,7 +3720,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) LOCK(cs_main); CValidationState state; - if (ProcessBlock(state, pfrom, &block)) + if (ProcessBlock(state, pfrom, &block) || state.CorruptionPossible()) mapAlreadyAskedFor.erase(inv); int nDoS = 0; if (state.IsInvalid(nDoS)) @@ -3814,8 +3751,10 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) if ((pfrom->pfilter && pfrom->pfilter->IsRelevantAndUpdate(mempool.lookup(hash), hash)) || (!pfrom->pfilter)) vInv.push_back(inv); - if (vInv.size() == MAX_INV_SZ) - break; + if (vInv.size() == MAX_INV_SZ) { + pfrom->PushMessage("inv", vInv); + vInv.clear(); + } } if (vInv.size() > 0) pfrom->PushMessage("inv", vInv); @@ -4213,7 +4152,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle) // transactions become unconfirmed and spams other nodes. if (!fReindex && !fImporting && !IsInitialBlockDownload()) { - ResendWalletTransactions(); + g_signals.Broadcast(); } // @@ -4241,15 +4180,6 @@ bool SendMessages(CNode* pto, bool fSendTrickle) hashRand = Hash(BEGIN(hashRand), END(hashRand)); bool fTrickleWait = ((hashRand & 3) != 0); - // always trickle our own transactions - if (!fTrickleWait) - { - CWalletTx wtx; - if (GetTransaction(inv.hash, wtx)) - if (wtx.fFromMe) - fTrickleWait = true; - } - if (fTrickleWait) { vInvWait.push_back(inv); @@ -4284,7 +4214,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle) const CInv& inv = (*pto->mapAskFor.begin()).second; if (!AlreadyHave(inv)) { - if (fDebugNet) + if (fDebug) LogPrint("net", "sending getdata: %s\n", inv.ToString().c_str()); vGetData.push_back(inv); if (vGetData.size() >= 1000) diff --git a/src/main.h b/src/main.h index 76de47071e..b56a4a5e19 100644 --- a/src/main.h +++ b/src/main.h @@ -17,7 +17,6 @@ #include <list> -class CWallet; class CBlock; class CBlockIndex; class CKeyItem; @@ -81,8 +80,6 @@ extern uint64 nLastBlockTx; extern uint64 nLastBlockSize; extern const std::string strMessageMagic; extern int64 nTimeBestReceived; -extern CCriticalSection cs_setpwalletRegistered; -extern std::set<CWallet*> setpwalletRegistered; extern bool fImporting; extern bool fReindex; extern bool fBenchmark; @@ -108,17 +105,18 @@ class CCoinsView; class CCoinsViewCache; class CScriptCheck; class CValidationState; +class CWalletInterface; struct CBlockTemplate; /** Register a wallet to receive updates from core */ -void RegisterWallet(CWallet* pwalletIn); +void RegisterWallet(CWalletInterface* pwalletIn); /** Unregister a wallet from core */ -void UnregisterWallet(CWallet* pwalletIn); +void UnregisterWallet(CWalletInterface* pwalletIn); /** Unregister all wallets from core */ void UnregisterAllWallets(); /** Push an updated transaction to all registered wallets */ -void SyncWithWallets(const uint256 &hash, const CTransaction& tx, const CBlock* pblock = NULL, bool fUpdate = false); +void SyncWithWallets(const uint256 &hash, const CTransaction& tx, const CBlock* pblock = NULL); /** Register with a network node to receive its signals */ void RegisterNodeSignals(CNodeSignals& nodeSignals); @@ -190,9 +188,6 @@ bool AbortNode(const std::string &msg); - -bool GetWalletFile(CWallet* pwallet, std::string &strWalletFileOut); - struct CDiskBlockPos { int nFile; @@ -946,13 +941,15 @@ private: MODE_ERROR, // run-time error } mode; int nDoS; + bool corruptionPossible; public: CValidationState() : mode(MODE_VALID), nDoS(0) {} - bool DoS(int level, bool ret = false) { + bool DoS(int level, bool ret = false, bool corruptionIn = false) { if (mode == MODE_ERROR) return ret; nDoS += level; mode = MODE_INVALID; + corruptionPossible = corruptionIn; return ret; } bool Invalid(bool ret = false) { @@ -982,6 +979,9 @@ public: } return false; } + bool CorruptionPossible() { + return corruptionPossible; + } }; /** An in-memory indexed chain of blocks. */ @@ -1256,4 +1256,18 @@ public: ) }; + +class CWalletInterface { +protected: + virtual void SyncTransaction(const uint256 &hash, const CTransaction &tx, const CBlock *pblock) =0; + virtual void EraseFromWallet(const uint256 &hash) =0; + virtual void SetBestChain(const CBlockLocator &locator) =0; + virtual void UpdatedTransaction(const uint256 &hash) =0; + virtual void Inventory(const uint256 &hash) =0; + virtual void ResendWalletTransactions() =0; + friend void ::RegisterWallet(CWalletInterface*); + friend void ::UnregisterWallet(CWalletInterface*); + friend void ::UnregisterAllWallets(); +}; + #endif diff --git a/src/net.cpp b/src/net.cpp index d223b3999e..de8543da59 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1894,3 +1894,38 @@ uint64 CNode::GetTotalBytesSent() LOCK(cs_totalBytesSent); return nTotalBytesSent; } + +void CNode::Fuzz(int nChance) +{ + if (!fSuccessfullyConnected) return; // Don't fuzz initial handshake + if (GetRand(nChance) != 0) return; // Fuzz 1 of every nChance messages + + switch (GetRand(3)) + { + case 0: + // xor a random byte with a random value: + if (!ssSend.empty()) { + CDataStream::size_type pos = GetRand(ssSend.size()); + ssSend[pos] ^= (unsigned char)(GetRand(256)); + } + break; + case 1: + // delete a random byte: + if (!ssSend.empty()) { + CDataStream::size_type pos = GetRand(ssSend.size()); + ssSend.erase(ssSend.begin()+pos); + } + break; + case 2: + // insert a random byte at a random position + { + CDataStream::size_type pos = GetRand(ssSend.size()); + char ch = (char)GetRand(256); + ssSend.insert(ssSend.begin()+pos, ch); + } + break; + } + // Chance of more than one change half the time: + // (more changes exponentially less likely): + Fuzz(2); +} @@ -218,6 +218,9 @@ protected: static CCriticalSection cs_setBanned; int nMisbehavior; + // Basic fuzz-testing + void Fuzz(int nChance); // modifies ssSend + public: uint256 hashContinue; CBlockIndex* pindexLastGetBlocksBegin; @@ -434,12 +437,17 @@ public: // TODO: Document the precondition of this function. Is cs_vSend locked? void EndMessage() UNLOCK_FUNCTION(cs_vSend) { - if (mapArgs.count("-dropmessagestest") && GetRand(atoi(mapArgs["-dropmessagestest"])) == 0) + // The -*messagestest options are intentionally not documented in the help message, + // since they are only used during development to debug the networking code and are + // not intended for end-users. + if (mapArgs.count("-dropmessagestest") && GetRand(GetArg("-dropmessagestest", 2)) == 0) { LogPrint("net", "dropmessages DROPPING SEND MESSAGE\n"); AbortMessage(); return; } + if (mapArgs.count("-fuzzmessagestest")) + Fuzz(GetArg("-fuzzmessagestest", 10)); if (ssSend.size() == 0) return; diff --git a/src/qt/Makefile.am b/src/qt/Makefile.am index 5892f6aca0..4ecd5629ea 100644 --- a/src/qt/Makefile.am +++ b/src/qt/Makefile.am @@ -34,7 +34,8 @@ QT_TS = locale/bitcoin_ach.ts locale/bitcoin_af_ZA.ts locale/bitcoin_ar.ts \ QT_FORMS_UI = forms/aboutdialog.ui forms/addressbookpage.ui \ forms/askpassphrasedialog.ui forms/editaddressdialog.ui forms/intro.ui \ - forms/optionsdialog.ui forms/overviewpage.ui forms/qrcodedialog.ui \ + forms/optionsdialog.ui forms/overviewpage.ui forms/receiverequestdialog.ui \ + forms/receivecoinsdialog.ui \ forms/rpcconsole.ui forms/sendcoinsdialog.ui forms/sendcoinsentry.ui \ forms/signverifymessagedialog.ui forms/transactiondescdialog.ui @@ -46,7 +47,8 @@ QT_MOC_CPP = moc_aboutdialog.cpp moc_addressbookpage.cpp \ moc_intro.cpp moc_macdockiconhandler.cpp moc_macnotificationhandler.cpp \ moc_monitoreddatamapper.cpp moc_notificator.cpp moc_optionsdialog.cpp \ moc_optionsmodel.cpp moc_overviewpage.cpp moc_paymentserver.cpp \ - moc_qrcodedialog.cpp moc_qvalidatedlineedit.cpp moc_qvaluecombobox.cpp \ + moc_receiverequestdialog.cpp moc_qvalidatedlineedit.cpp moc_qvaluecombobox.cpp \ + moc_receivecoinsdialog.cpp \ moc_rpcconsole.cpp moc_sendcoinsdialog.cpp moc_sendcoinsentry.cpp \ moc_signverifymessagedialog.cpp moc_splashscreen.cpp moc_trafficgraphwidget.cpp moc_transactiondesc.cpp \ moc_transactiondescdialog.cpp moc_transactionfilterproxy.cpp \ @@ -54,7 +56,6 @@ QT_MOC_CPP = moc_aboutdialog.cpp moc_addressbookpage.cpp \ moc_walletmodel.cpp moc_walletview.cpp BITCOIN_MM = macdockiconhandler.mm macnotificationhandler.mm -QR_CPP = qrcodedialog.cpp QT_MOC = intro.moc overviewpage.moc rpcconsole.moc @@ -71,7 +72,8 @@ BITCOIN_QT_H = aboutdialog.h addressbookpage.h addresstablemodel.h \ editaddressdialog.h guiconstants.h guiutil.h intro.h macdockiconhandler.h \ macnotificationhandler.h monitoreddatamapper.h notificator.h optionsdialog.h \ optionsmodel.h overviewpage.h paymentrequestplus.h paymentserver.h \ - qrcodedialog.h qvalidatedlineedit.h qvaluecombobox.h rpcconsole.h \ + receivecoinsdialog.h \ + receiverequestdialog.h qvalidatedlineedit.h qvaluecombobox.h rpcconsole.h \ sendcoinsdialog.h sendcoinsentry.h signverifymessagedialog.h splashscreen.h \ trafficgraphwidget.h transactiondescdialog.h transactiondesc.h transactionfilterproxy.h \ transactionrecord.h transactiontablemodel.h transactionview.h walletframe.h \ @@ -101,6 +103,7 @@ BITCOIN_QT_CPP = aboutdialog.cpp addressbookpage.cpp \ guiutil.cpp intro.cpp monitoreddatamapper.cpp notificator.cpp \ optionsdialog.cpp optionsmodel.cpp overviewpage.cpp paymentrequestplus.cpp \ paymentserver.cpp qvalidatedlineedit.cpp qvaluecombobox.cpp \ + receivecoinsdialog.cpp receiverequestdialog.cpp \ rpcconsole.cpp sendcoinsdialog.cpp sendcoinsentry.cpp \ signverifymessagedialog.cpp splashscreen.cpp trafficgraphwidget.cpp transactiondesc.cpp \ transactiondescdialog.cpp transactionfilterproxy.cpp transactionrecord.cpp \ @@ -135,9 +138,6 @@ endif if TARGET_WINDOWS libbitcoinqt_a_SOURCES += $(BITCOIN_RC) endif -if USE_QRCODE - libbitcoinqt_a_SOURCES += $(QR_CPP) -endif # # bitcoin-qt binary # @@ -159,7 +159,7 @@ QT_QM=$(QT_TS:.ts=.qm) bitcoinstrings.cpp: FORCE $(MAKE) -C $(top_srcdir)/src qt/bitcoinstrings.cpp -translate: bitcoinstrings.cpp $(QT_FORMS_UI) $(QT_FORMS_UI) $(BITCOIN_QT_CPP) $(BITCOIN_QT_H) $(BITCOIN_MM) $(QR_CPP) +translate: bitcoinstrings.cpp $(QT_FORMS_UI) $(QT_FORMS_UI) $(BITCOIN_QT_CPP) $(BITCOIN_QT_H) $(BITCOIN_MM) @test -n $(LUPDATE) || echo "lupdate is required for updating translations" @$(LUPDATE) $^ -locations relative -no-obsolete -ts locale/bitcoin_en.ts diff --git a/src/qt/addressbookpage.cpp b/src/qt/addressbookpage.cpp index 5b8d44481e..ba5de4660a 100644 --- a/src/qt/addressbookpage.cpp +++ b/src/qt/addressbookpage.cpp @@ -12,10 +12,6 @@ #include "csvmodelwriter.h" #include "guiutil.h" -#ifdef USE_QRCODE -#include "qrcodedialog.h" -#endif - #include <QSortFilterProxyModel> #include <QClipboard> #include <QMessageBox> @@ -35,25 +31,29 @@ AddressBookPage::AddressBookPage(Mode mode, Tabs tab, QWidget *parent) : ui->newAddress->setIcon(QIcon()); ui->copyAddress->setIcon(QIcon()); ui->deleteAddress->setIcon(QIcon()); - ui->verifyMessage->setIcon(QIcon()); - ui->signMessage->setIcon(QIcon()); ui->exportButton->setIcon(QIcon()); #endif -#ifndef USE_QRCODE - ui->showQRCode->setVisible(false); -#endif - switch(mode) { - case ForSending: + case ForSelection: + switch(tab) + { + case SendingTab: setWindowTitle(tr("Choose the address to send coins to")); break; + case ReceivingTab: setWindowTitle(tr("Choose the address to receive coins with")); break; + } connect(ui->tableView, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(accept())); ui->tableView->setEditTriggers(QAbstractItemView::NoEditTriggers); ui->tableView->setFocus(); + ui->closeButton->setText(tr("C&hoose")); ui->exportButton->hide(); break; case ForEditing: - ui->buttonBox->setVisible(false); + switch(tab) + { + case SendingTab: setWindowTitle(tr("Sending addresses")); break; + case ReceivingTab: setWindowTitle(tr("Receiving addresses")); break; + } break; } switch(tab) @@ -61,23 +61,17 @@ AddressBookPage::AddressBookPage(Mode mode, Tabs tab, QWidget *parent) : case SendingTab: ui->labelExplanation->setText(tr("These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins.")); ui->deleteAddress->setVisible(true); - ui->signMessage->setVisible(false); break; case ReceivingTab: - ui->labelExplanation->setText(tr("These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you.")); + ui->labelExplanation->setText(tr("These are your Bitcoin addresses for receiving payments. It is recommended to use a new receiving address for each transaction.")); ui->deleteAddress->setVisible(false); - ui->signMessage->setVisible(true); break; } // Context menu actions - QAction *copyAddressAction = new QAction(ui->copyAddress->text(), this); + QAction *copyAddressAction = new QAction(tr("&Copy Address"), this); QAction *copyLabelAction = new QAction(tr("Copy &Label"), this); QAction *editAction = new QAction(tr("&Edit"), this); - QAction *sendCoinsAction = new QAction(tr("Send &Coins"), this); - QAction *showQRCodeAction = new QAction(ui->showQRCode->text(), this); - QAction *signMessageAction = new QAction(ui->signMessage->text(), this); - QAction *verifyMessageAction = new QAction(ui->verifyMessage->text(), this); deleteAction = new QAction(ui->deleteAddress->text(), this); // Build context menu @@ -88,30 +82,16 @@ AddressBookPage::AddressBookPage(Mode mode, Tabs tab, QWidget *parent) : if(tab == SendingTab) contextMenu->addAction(deleteAction); contextMenu->addSeparator(); - if(tab == SendingTab) - contextMenu->addAction(sendCoinsAction); -#ifdef USE_QRCODE - contextMenu->addAction(showQRCodeAction); -#endif - if(tab == ReceivingTab) - contextMenu->addAction(signMessageAction); - else if(tab == SendingTab) - contextMenu->addAction(verifyMessageAction); // Connect signals for context menu actions connect(copyAddressAction, SIGNAL(triggered()), this, SLOT(on_copyAddress_clicked())); connect(copyLabelAction, SIGNAL(triggered()), this, SLOT(onCopyLabelAction())); connect(editAction, SIGNAL(triggered()), this, SLOT(onEditAction())); connect(deleteAction, SIGNAL(triggered()), this, SLOT(on_deleteAddress_clicked())); - connect(sendCoinsAction, SIGNAL(triggered()), this, SLOT(onSendCoinsAction())); - connect(showQRCodeAction, SIGNAL(triggered()), this, SLOT(on_showQRCode_clicked())); - connect(signMessageAction, SIGNAL(triggered()), this, SLOT(on_signMessage_clicked())); - connect(verifyMessageAction, SIGNAL(triggered()), this, SLOT(on_verifyMessage_clicked())); connect(ui->tableView, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(contextualMenu(QPoint))); - // Pass through accept action from button box - connect(ui->buttonBox, SIGNAL(accepted()), this, SLOT(accept())); + connect(ui->closeButton, SIGNAL(clicked()), this, SLOT(accept())); } AddressBookPage::~AddressBookPage() @@ -197,42 +177,6 @@ void AddressBookPage::onEditAction() dlg.exec(); } -void AddressBookPage::on_signMessage_clicked() -{ - QTableView *table = ui->tableView; - QModelIndexList indexes = table->selectionModel()->selectedRows(AddressTableModel::Address); - - foreach (QModelIndex index, indexes) - { - QString address = index.data().toString(); - emit signMessage(address); - } -} - -void AddressBookPage::on_verifyMessage_clicked() -{ - QTableView *table = ui->tableView; - QModelIndexList indexes = table->selectionModel()->selectedRows(AddressTableModel::Address); - - foreach (QModelIndex index, indexes) - { - QString address = index.data().toString(); - emit verifyMessage(address); - } -} - -void AddressBookPage::onSendCoinsAction() -{ - QTableView *table = ui->tableView; - QModelIndexList indexes = table->selectionModel()->selectedRows(AddressTableModel::Address); - - foreach (QModelIndex index, indexes) - { - QString address = index.data().toString(); - emit sendCoins(address); - } -} - void AddressBookPage::on_newAddress_clicked() { if(!model) @@ -278,32 +222,20 @@ void AddressBookPage::selectionChanged() ui->deleteAddress->setEnabled(true); ui->deleteAddress->setVisible(true); deleteAction->setEnabled(true); - ui->signMessage->setEnabled(false); - ui->signMessage->setVisible(false); - ui->verifyMessage->setEnabled(true); - ui->verifyMessage->setVisible(true); break; case ReceivingTab: // Deleting receiving addresses, however, is not allowed ui->deleteAddress->setEnabled(false); ui->deleteAddress->setVisible(false); deleteAction->setEnabled(false); - ui->signMessage->setEnabled(true); - ui->signMessage->setVisible(true); - ui->verifyMessage->setEnabled(false); - ui->verifyMessage->setVisible(false); break; } ui->copyAddress->setEnabled(true); - ui->showQRCode->setEnabled(true); } else { ui->deleteAddress->setEnabled(false); - ui->showQRCode->setEnabled(false); ui->copyAddress->setEnabled(false); - ui->signMessage->setEnabled(false); - ui->verifyMessage->setEnabled(false); } } @@ -312,9 +244,6 @@ void AddressBookPage::done(int retval) QTableView *table = ui->tableView; if(!table->selectionModel() || !table->model()) return; - // When this is a tab/widget and not a model dialog, ignore "done" - if(mode == ForEditing) - return; // Figure out which address was selected, and return it QModelIndexList indexes = table->selectionModel()->selectedRows(AddressTableModel::Address); @@ -339,7 +268,7 @@ void AddressBookPage::on_exportButton_clicked() // CSV is currently the only supported format QString filename = GUIUtil::getSaveFileName( this, - tr("Export Address Book Data"), QString(), + tr("Export Address List"), QString(), tr("Comma separated file (*.csv)")); if (filename.isNull()) return; @@ -358,25 +287,6 @@ void AddressBookPage::on_exportButton_clicked() } } -void AddressBookPage::on_showQRCode_clicked() -{ -#ifdef USE_QRCODE - QTableView *table = ui->tableView; - QModelIndexList indexes = table->selectionModel()->selectedRows(AddressTableModel::Address); - - foreach (QModelIndex index, indexes) - { - QString address = index.data().toString(); - QString label = index.sibling(index.row(), 0).data(Qt::EditRole).toString(); - - QRCodeDialog *dialog = new QRCodeDialog(address, label, tab == ReceivingTab, this); - dialog->setModel(optionsModel); - dialog->setAttribute(Qt::WA_DeleteOnClose); - dialog->show(); - } -#endif -} - void AddressBookPage::contextualMenu(const QPoint &point) { QModelIndex index = ui->tableView->indexAt(point); diff --git a/src/qt/addressbookpage.h b/src/qt/addressbookpage.h index 34465aa65f..9255e58144 100644 --- a/src/qt/addressbookpage.h +++ b/src/qt/addressbookpage.h @@ -30,7 +30,7 @@ public: }; enum Mode { - ForSending, /**< Open address book to pick address for sending */ + ForSelection, /**< Open address book to pick address */ ForEditing /**< Open address book for editing */ }; @@ -63,14 +63,6 @@ private slots: void on_newAddress_clicked(); /** Copy address of currently selected address entry to clipboard */ void on_copyAddress_clicked(); - /** Open the sign message tab in the Sign/Verify Message dialog with currently selected address */ - void on_signMessage_clicked(); - /** Open the verify message tab in the Sign/Verify Message dialog with currently selected address */ - void on_verifyMessage_clicked(); - /** Open send coins dialog for currently selected address (no button) */ - void onSendCoinsAction(); - /** Generate a QR Code from the currently selected address */ - void on_showQRCode_clicked(); /** Copy label of currently selected address entry to clipboard (no button) */ void onCopyLabelAction(); /** Edit currently selected address entry (no button) */ @@ -86,8 +78,6 @@ private slots: void selectNewAddress(const QModelIndex &parent, int begin, int /*end*/); signals: - void signMessage(QString addr); - void verifyMessage(QString addr); void sendCoins(QString addr); }; diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index e73a82978a..09f2a53680 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -331,8 +331,6 @@ int main(int argc, char *argv[]) &window, SLOT(handlePaymentRequest(SendCoinsRecipient))); QObject::connect(&walletModel, SIGNAL(coinsSent(CWallet*,SendCoinsRecipient,QByteArray)), paymentServer, SLOT(fetchPaymentACK(CWallet*,const SendCoinsRecipient&,QByteArray))); - QObject::connect(paymentServer, SIGNAL(receivedPaymentACK(QString)), - &window, SLOT(showPaymentACK(QString))); QObject::connect(paymentServer, SIGNAL(message(QString,QString,unsigned int)), guiref, SLOT(message(QString,QString,unsigned int))); QTimer::singleShot(100, paymentServer, SLOT(uiReady())); diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 3336a8afd3..2279d4fb4b 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -7,14 +7,12 @@ #include "bitcoingui.h" -#include "transactiontablemodel.h" #include "optionsdialog.h" #include "aboutdialog.h" #include "clientmodel.h" #include "walletmodel.h" #include "walletframe.h" #include "optionsmodel.h" -#include "transactiondescdialog.h" #include "bitcoinunits.h" #include "guiconstants.h" #include "notificator.h" @@ -194,7 +192,7 @@ void BitcoinGUI::createActions(bool fIsTestnet) tabGroup->addAction(sendCoinsAction); receiveCoinsAction = new QAction(QIcon(":/icons/receiving_addresses"), tr("&Receive"), this); - receiveCoinsAction->setStatusTip(tr("Show the list of addresses for receiving payments")); + receiveCoinsAction->setStatusTip(tr("Request payments (generates QR codes and bitcoin: URIs)")); receiveCoinsAction->setToolTip(receiveCoinsAction->statusTip()); receiveCoinsAction->setCheckable(true); receiveCoinsAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_3)); @@ -207,13 +205,6 @@ void BitcoinGUI::createActions(bool fIsTestnet) historyAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_4)); tabGroup->addAction(historyAction); - addressBookAction = new QAction(QIcon(":/icons/address-book"), tr("&Addresses"), this); - addressBookAction->setStatusTip(tr("Edit the list of stored addresses and labels")); - addressBookAction->setToolTip(addressBookAction->statusTip()); - addressBookAction->setCheckable(true); - addressBookAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_5)); - tabGroup->addAction(addressBookAction); - connect(overviewAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized())); connect(overviewAction, SIGNAL(triggered()), this, SLOT(gotoOverviewPage())); connect(sendCoinsAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized())); @@ -222,8 +213,6 @@ void BitcoinGUI::createActions(bool fIsTestnet) connect(receiveCoinsAction, SIGNAL(triggered()), this, SLOT(gotoReceiveCoinsPage())); connect(historyAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized())); connect(historyAction, SIGNAL(triggered()), this, SLOT(gotoHistoryPage())); - connect(addressBookAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized())); - connect(addressBookAction, SIGNAL(triggered()), this, SLOT(gotoAddressBookPage())); quitAction = new QAction(QIcon(":/icons/quit"), tr("E&xit"), this); quitAction->setStatusTip(tr("Quit application")); @@ -239,7 +228,7 @@ void BitcoinGUI::createActions(bool fIsTestnet) aboutQtAction = new QAction(QIcon(":/trolltech/qmessagebox/images/qtlogo-64.png"), tr("About &Qt"), this); #else aboutQtAction = new QAction(QIcon(":/qt-project.org/qmessagebox/images/qtlogo-64.png"), tr("About &Qt"), this); -#endif +#endif aboutQtAction->setStatusTip(tr("Show information about Qt")); aboutQtAction->setMenuRole(QAction::AboutQtRole); optionsAction = new QAction(QIcon(":/icons/options"), tr("&Options..."), this); @@ -266,6 +255,11 @@ void BitcoinGUI::createActions(bool fIsTestnet) openRPCConsoleAction = new QAction(QIcon(":/icons/debugwindow"), tr("&Debug window"), this); openRPCConsoleAction->setStatusTip(tr("Open debugging and diagnostic console")); + usedSendingAddressesAction = new QAction(QIcon(":/icons/address-book"), tr("&Used sending addresses..."), this); + usedSendingAddressesAction->setStatusTip(tr("Show the list of used sending addresses and labels")); + usedReceivingAddressesAction = new QAction(QIcon(":/icons/address-book"), tr("Used &receiving addresses..."), this); + usedReceivingAddressesAction->setStatusTip(tr("Show the list of used receiving addresses and labels")); + connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit())); connect(aboutAction, SIGNAL(triggered()), this, SLOT(aboutClicked())); connect(aboutQtAction, SIGNAL(triggered()), qApp, SLOT(aboutQt())); @@ -276,6 +270,8 @@ void BitcoinGUI::createActions(bool fIsTestnet) connect(changePassphraseAction, SIGNAL(triggered()), walletFrame, SLOT(changePassphrase())); connect(signMessageAction, SIGNAL(triggered()), this, SLOT(gotoSignMessageTab())); connect(verifyMessageAction, SIGNAL(triggered()), this, SLOT(gotoVerifyMessageTab())); + connect(usedSendingAddressesAction, SIGNAL(triggered()), walletFrame, SLOT(usedSendingAddresses())); + connect(usedReceivingAddressesAction, SIGNAL(triggered()), walletFrame, SLOT(usedReceivingAddresses())); } void BitcoinGUI::createMenuBar() @@ -294,6 +290,9 @@ void BitcoinGUI::createMenuBar() file->addAction(signMessageAction); file->addAction(verifyMessageAction); file->addSeparator(); + file->addAction(usedSendingAddressesAction); + file->addAction(usedReceivingAddressesAction); + file->addSeparator(); file->addAction(quitAction); QMenu *settings = appMenuBar->addMenu(tr("&Settings")); @@ -317,7 +316,6 @@ void BitcoinGUI::createToolBars() toolbar->addAction(sendCoinsAction); toolbar->addAction(receiveCoinsAction); toolbar->addAction(historyAction); - toolbar->addAction(addressBookAction); } void BitcoinGUI::setClientModel(ClientModel *clientModel) @@ -457,12 +455,6 @@ void BitcoinGUI::gotoHistoryPage() if (walletFrame) walletFrame->gotoHistoryPage(); } -void BitcoinGUI::gotoAddressBookPage() -{ - addressBookAction->setChecked(true); - if (walletFrame) walletFrame->gotoAddressBookPage(); -} - void BitcoinGUI::gotoReceiveCoinsPage() { receiveCoinsAction->setChecked(true); @@ -643,6 +635,8 @@ void BitcoinGUI::message(const QString &title, const QString &message, unsigned if (!(buttons = (QMessageBox::StandardButton)(style & CClientUIInterface::BTN_MASK))) buttons = QMessageBox::Ok; + // Ensure we get users attention + showNormalIfMinimized(); QMessageBox mBox((QMessageBox::Icon)nMBoxIcon, strTitle, message, buttons, this); int r = mBox.exec(); if (ret != NULL) @@ -694,9 +688,8 @@ void BitcoinGUI::askFee(qint64 nFeeRequired, bool *payFee) QString strMessage = tr("This transaction is over the size limit. You can still send it for a fee of %1, " "which goes to the nodes that process your transaction and helps to support the network. " "Do you want to pay the fee?").arg(BitcoinUnits::formatWithUnit(clientModel->getOptionsModel()->getDisplayUnit(), nFeeRequired)); - QMessageBox::StandardButton retval = QMessageBox::question( - this, tr("Confirm transaction fee"), strMessage, - QMessageBox::Yes|QMessageBox::Cancel, QMessageBox::Yes); + QMessageBox::StandardButton retval = QMessageBox::question(this, tr("Confirm transaction fee"), strMessage, + QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Yes); *payFee = (retval == QMessageBox::Yes); } @@ -739,7 +732,7 @@ void BitcoinGUI::dropEvent(QDropEvent *event) walletFrame->gotoSendCoinsPage(); else message(tr("URI handling"), tr("URI can not be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters."), - CClientUIInterface::ICON_WARNING); + CClientUIInterface::ICON_WARNING); } event->acceptProposedAction(); @@ -757,14 +750,17 @@ bool BitcoinGUI::eventFilter(QObject *object, QEvent *event) return QMainWindow::eventFilter(object, event); } -void BitcoinGUI::handlePaymentRequest(const SendCoinsRecipient& recipient) +bool BitcoinGUI::handlePaymentRequest(const SendCoinsRecipient& recipient) { - walletFrame->handlePaymentRequest(recipient); -} - -void BitcoinGUI::showPaymentACK(const QString& msg) -{ - message(tr("Payment acknowledged"), GUIUtil::HtmlEscape(msg), CClientUIInterface::MODAL); + // URI has to be valid + if (walletFrame->handlePaymentRequest(recipient)) + { + showNormalIfMinimized(); + gotoSendCoinsPage(); + return true; + } + else + return false; } void BitcoinGUI::setEncryptionStatus(int status) diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index e5a92fed93..215bb6fa05 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -5,15 +5,12 @@ #include <QSystemTrayIcon> #include <QMap> -class TransactionTableModel; class WalletFrame; class WalletView; class ClientModel; class WalletModel; class WalletStack; -class TransactionView; class OverviewPage; -class AddressBookPage; class SendCoinsDialog; class SendCoinsRecipient; class SignVerifyMessageDialog; @@ -51,11 +48,11 @@ public: The client model represents the part of the core that communicates with the P2P network, and is wallet-agnostic. */ void setClientModel(ClientModel *clientModel); + /** Set the wallet model. The wallet model represents a bitcoin wallet, and offers access to the list of transactions, address book and sending functionality. */ - bool addWallet(const QString& name, WalletModel *walletModel); bool setCurrentWallet(const QString& name); @@ -83,7 +80,8 @@ private: QAction *historyAction; QAction *quitAction; QAction *sendCoinsAction; - QAction *addressBookAction; + QAction *usedSendingAddressesAction; + QAction *usedReceivingAddressesAction; QAction *signMessageAction; QAction *verifyMessageAction; QAction *aboutAction; @@ -98,7 +96,6 @@ private: QSystemTrayIcon *trayIcon; Notificator *notificator; - TransactionView *transactionView; RPCConsole *rpcConsole; QMovie *syncIconMovie; @@ -135,6 +132,7 @@ public slots: @param[in] ret pointer to a bool that will be modified to whether Ok was clicked (modal only) */ void message(const QString &title, const QString &message, unsigned int style, bool *ret = NULL); + /** Asks the user whether to pay the transaction fee or to cancel the transaction. It is currently not possible to pass a return value to another thread through BlockingQueuedConnection, so an indirected pointer is used. @@ -145,8 +143,7 @@ public slots: */ void askFee(qint64 nFeeRequired, bool *payFee); - void handlePaymentRequest(const SendCoinsRecipient& recipient); - void showPaymentACK(const QString& msg); + bool handlePaymentRequest(const SendCoinsRecipient& recipient); /** Show incoming transaction notification for new transactions. */ void incomingTransaction(const QString& date, int unit, qint64 amount, const QString& type, const QString& address); @@ -156,8 +153,6 @@ private slots: void gotoOverviewPage(); /** Switch to history (transactions) page */ void gotoHistoryPage(); - /** Switch to address book page */ - void gotoAddressBookPage(); /** Switch to receive coins page */ void gotoReceiveCoinsPage(); /** Switch to send coins page */ diff --git a/src/qt/bitcoinstrings.cpp b/src/qt/bitcoinstrings.cpp index bfe9494b17..457090b1f5 100644 --- a/src/qt/bitcoinstrings.cpp +++ b/src/qt/bitcoinstrings.cpp @@ -19,8 +19,8 @@ QT_TRANSLATE_NOOP("bitcoin-core", "" "It is also recommended to set alertnotify so you are notified of problems;\n" "for example: alertnotify=echo %%s | mail -s \"Bitcoin Alert\" admin@foo.com\n"), QT_TRANSLATE_NOOP("bitcoin-core", "" -"Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:" -"@STRENGTH)"), +"Acceptable ciphers (default: TLSv1.2+HIGH:TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!" +"3DES:@STRENGTH)"), QT_TRANSLATE_NOOP("bitcoin-core", "" "An error occurred while setting up the RPC port %u for listening on IPv4: %s"), QT_TRANSLATE_NOOP("bitcoin-core", "" @@ -98,6 +98,7 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Add a node to connect to and attempt to keep QT_TRANSLATE_NOOP("bitcoin-core", "Allow DNS lookups for -addnode, -seednode and -connect"), QT_TRANSLATE_NOOP("bitcoin-core", "Allow JSON-RPC connections from specified IP address"), QT_TRANSLATE_NOOP("bitcoin-core", "Attempt to recover private keys from a corrupt wallet.dat"), +QT_TRANSLATE_NOOP("bitcoin-core", "Bitcoin RPC client version"), QT_TRANSLATE_NOOP("bitcoin-core", "Bitcoin version"), QT_TRANSLATE_NOOP("bitcoin-core", "Block creation options:"), QT_TRANSLATE_NOOP("bitcoin-core", "Cannot downgrade wallet"), @@ -106,6 +107,7 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Cannot resolve -externalip address: '%s'"), QT_TRANSLATE_NOOP("bitcoin-core", "Cannot write default address"), QT_TRANSLATE_NOOP("bitcoin-core", "Connect only to the specified node(s)"), QT_TRANSLATE_NOOP("bitcoin-core", "Connect through socks proxy"), +QT_TRANSLATE_NOOP("bitcoin-core", "Connect to JSON-RPC on <port> (default: 8332 or testnet: 18332)"), QT_TRANSLATE_NOOP("bitcoin-core", "Connect to a node to retrieve peer addresses, and disconnect"), QT_TRANSLATE_NOOP("bitcoin-core", "Corrupted block database detected"), QT_TRANSLATE_NOOP("bitcoin-core", "Discover own IP address (default: 1 when listening and no -externalip)"), @@ -143,8 +145,8 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Imports blocks from external blk000??.dat fil QT_TRANSLATE_NOOP("bitcoin-core", "Incorrect or no genesis block found. Wrong datadir for network?"), QT_TRANSLATE_NOOP("bitcoin-core", "Information"), QT_TRANSLATE_NOOP("bitcoin-core", "Insufficient funds"), +QT_TRANSLATE_NOOP("bitcoin-core", "Invalid -onion address: '%s'"), QT_TRANSLATE_NOOP("bitcoin-core", "Invalid -proxy address: '%s'"), -QT_TRANSLATE_NOOP("bitcoin-core", "Invalid -tor address: '%s'"), QT_TRANSLATE_NOOP("bitcoin-core", "Invalid amount for -minrelaytxfee=<amount>: '%s'"), QT_TRANSLATE_NOOP("bitcoin-core", "Invalid amount for -mintxfee=<amount>: '%s'"), QT_TRANSLATE_NOOP("bitcoin-core", "Invalid amount for -paytxfee=<amount>: '%s'"), @@ -172,7 +174,7 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Rescanning..."), QT_TRANSLATE_NOOP("bitcoin-core", "Run in the background as a daemon and accept commands"), QT_TRANSLATE_NOOP("bitcoin-core", "SSL options: (see the Bitcoin Wiki for SSL setup instructions)"), QT_TRANSLATE_NOOP("bitcoin-core", "Select the version of socks proxy to use (4-5, default: 5)"), -QT_TRANSLATE_NOOP("bitcoin-core", "Send command to -server or bitcoind"), +QT_TRANSLATE_NOOP("bitcoin-core", "Send command to Bitcoin server"), QT_TRANSLATE_NOOP("bitcoin-core", "Send commands to node running on <ip> (default: 127.0.0.1)"), QT_TRANSLATE_NOOP("bitcoin-core", "Send trace/debug info to console instead of debug.log file"), QT_TRANSLATE_NOOP("bitcoin-core", "Send trace/debug info to debugger"), @@ -191,6 +193,7 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Specify data directory"), QT_TRANSLATE_NOOP("bitcoin-core", "Specify pid file (default: bitcoind.pid)"), QT_TRANSLATE_NOOP("bitcoin-core", "Specify wallet file (within data directory)"), QT_TRANSLATE_NOOP("bitcoin-core", "Specify your own public address"), +QT_TRANSLATE_NOOP("bitcoin-core", "Start Bitcoin server"), QT_TRANSLATE_NOOP("bitcoin-core", "System error: "), QT_TRANSLATE_NOOP("bitcoin-core", "This help message"), QT_TRANSLATE_NOOP("bitcoin-core", "Threshold for disconnecting misbehaving peers (default: 100)"), @@ -202,6 +205,7 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Unable to bind to %s on this computer (bind r QT_TRANSLATE_NOOP("bitcoin-core", "Unknown -socks proxy version requested: %i"), QT_TRANSLATE_NOOP("bitcoin-core", "Unknown network specified in -onlynet: '%s'"), QT_TRANSLATE_NOOP("bitcoin-core", "Upgrade wallet to latest format"), +QT_TRANSLATE_NOOP("bitcoin-core", "Usage (deprecated, use bitcoin-cli):"), QT_TRANSLATE_NOOP("bitcoin-core", "Usage:"), QT_TRANSLATE_NOOP("bitcoin-core", "Use OpenSSL (https) for JSON-RPC connections"), QT_TRANSLATE_NOOP("bitcoin-core", "Use UPnP to map the listening port (default: 0)"), diff --git a/src/qt/forms/addressbookpage.ui b/src/qt/forms/addressbookpage.ui index a2a7da34dd..49221f41c1 100644 --- a/src/qt/forms/addressbookpage.ui +++ b/src/qt/forms/addressbookpage.ui @@ -10,9 +10,6 @@ <height>380</height> </rect> </property> - <property name="windowTitle"> - <string>Address Book</string> - </property> <layout class="QVBoxLayout" name="verticalLayout"> <item> <widget class="QLabel" name="labelExplanation"> @@ -60,7 +57,7 @@ <string>Create a new address</string> </property> <property name="text"> - <string>&New Address</string> + <string>&New</string> </property> <property name="icon"> <iconset resource="../bitcoin.qrc"> @@ -74,7 +71,7 @@ <string>Copy the currently selected address to the system clipboard</string> </property> <property name="text"> - <string>&Copy Address</string> + <string>&Copy</string> </property> <property name="icon"> <iconset resource="../bitcoin.qrc"> @@ -83,45 +80,6 @@ </widget> </item> <item> - <widget class="QPushButton" name="showQRCode"> - <property name="text"> - <string>Show &QR Code</string> - </property> - <property name="icon"> - <iconset resource="../bitcoin.qrc"> - <normaloff>:/icons/qrcode</normaloff>:/icons/qrcode</iconset> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="signMessage"> - <property name="toolTip"> - <string>Sign a message to prove you own a Bitcoin address</string> - </property> - <property name="text"> - <string>Sign &Message</string> - </property> - <property name="icon"> - <iconset resource="../bitcoin.qrc"> - <normaloff>:/icons/edit</normaloff>:/icons/edit</iconset> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="verifyMessage"> - <property name="toolTip"> - <string>Verify a message to ensure it was signed with a specified Bitcoin address</string> - </property> - <property name="text"> - <string>&Verify Message</string> - </property> - <property name="icon"> - <iconset resource="../bitcoin.qrc"> - <normaloff>:/icons/transaction_0</normaloff>:/icons/transaction_0</iconset> - </property> - </widget> - </item> - <item> <widget class="QPushButton" name="deleteAddress"> <property name="toolTip"> <string>Delete the currently selected address from the list</string> @@ -163,15 +121,9 @@ </widget> </item> <item> - <widget class="QDialogButtonBox" name="buttonBox"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Maximum" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="standardButtons"> - <set>QDialogButtonBox::Ok</set> + <widget class="QPushButton" name="closeButton"> + <property name="text"> + <string>C&lose</string> </property> </widget> </item> diff --git a/src/qt/forms/editaddressdialog.ui b/src/qt/forms/editaddressdialog.ui index b4a4c1b1e9..8ff3805226 100644 --- a/src/qt/forms/editaddressdialog.ui +++ b/src/qt/forms/editaddressdialog.ui @@ -32,7 +32,7 @@ <item row="0" column="1"> <widget class="QLineEdit" name="labelEdit"> <property name="toolTip"> - <string>The label associated with this address book entry</string> + <string>The label associated with this address list entry</string> </property> </widget> </item> @@ -49,7 +49,7 @@ <item row="1" column="1"> <widget class="QLineEdit" name="addressEdit"> <property name="toolTip"> - <string>The address associated with this address book entry. This can only be modified for sending addresses.</string> + <string>The address associated with this address list entry. This can only be modified for sending addresses.</string> </property> </widget> </item> diff --git a/src/qt/forms/qrcodedialog.ui b/src/qt/forms/qrcodedialog.ui deleted file mode 100644 index 1cec9066f8..0000000000 --- a/src/qt/forms/qrcodedialog.ui +++ /dev/null @@ -1,212 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<ui version="4.0"> - <class>QRCodeDialog</class> - <widget class="QDialog" name="QRCodeDialog"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>340</width> - <height>530</height> - </rect> - </property> - <property name="windowTitle"> - <string>QR Code Dialog</string> - </property> - <layout class="QVBoxLayout" name="verticalLayout_3"> - <item> - <widget class="QLabel" name="lblQRCode"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="minimumSize"> - <size> - <width>300</width> - <height>300</height> - </size> - </property> - <property name="textFormat"> - <enum>Qt::PlainText</enum> - </property> - <property name="alignment"> - <set>Qt::AlignCenter</set> - </property> - <property name="wordWrap"> - <bool>true</bool> - </property> - </widget> - </item> - <item> - <widget class="QPlainTextEdit" name="outUri"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Expanding" vsizetype="Minimum"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="minimumSize"> - <size> - <width>0</width> - <height>50</height> - </size> - </property> - <property name="tabChangesFocus"> - <bool>true</bool> - </property> - <property name="textInteractionFlags"> - <set>Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set> - </property> - </widget> - </item> - <item> - <widget class="QWidget" name="widget" native="true"> - <layout class="QVBoxLayout" name="verticalLayout_2"> - <item> - <widget class="QCheckBox" name="chkReqPayment"> - <property name="enabled"> - <bool>true</bool> - </property> - <property name="text"> - <string>Request Payment</string> - </property> - </widget> - </item> - <item> - <layout class="QFormLayout" name="formLayout"> - <property name="fieldGrowthPolicy"> - <enum>QFormLayout::AllNonFixedFieldsGrow</enum> - </property> - <item row="1" column="0"> - <widget class="QLabel" name="lblLabel"> - <property name="text"> - <string>Label:</string> - </property> - <property name="textFormat"> - <enum>Qt::PlainText</enum> - </property> - <property name="alignment"> - <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> - </property> - <property name="buddy"> - <cstring>lnLabel</cstring> - </property> - </widget> - </item> - <item row="1" column="1"> - <widget class="QLineEdit" name="lnLabel"/> - </item> - <item row="2" column="0"> - <widget class="QLabel" name="lblMessage"> - <property name="text"> - <string>Message:</string> - </property> - <property name="textFormat"> - <enum>Qt::PlainText</enum> - </property> - <property name="alignment"> - <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> - </property> - <property name="buddy"> - <cstring>lnMessage</cstring> - </property> - </widget> - </item> - <item row="2" column="1"> - <widget class="QLineEdit" name="lnMessage"/> - </item> - <item row="0" column="0"> - <widget class="QLabel" name="lblAmount"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Maximum"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string>Amount:</string> - </property> - <property name="textFormat"> - <enum>Qt::PlainText</enum> - </property> - <property name="alignment"> - <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> - </property> - <property name="buddy"> - <cstring>lnReqAmount</cstring> - </property> - </widget> - </item> - <item row="0" column="1"> - <widget class="BitcoinAmountField" name="lnReqAmount"> - <property name="enabled"> - <bool>false</bool> - </property> - <property name="minimumSize"> - <size> - <width>80</width> - <height>0</height> - </size> - </property> - </widget> - </item> - </layout> - </item> - <item> - <layout class="QHBoxLayout" name="horizontalLayout"> - <item> - <spacer name="horizontalSpacer"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QPushButton" name="btnSaveAs"> - <property name="text"> - <string>&Save As...</string> - </property> - </widget> - </item> - </layout> - </item> - </layout> - </widget> - </item> - </layout> - </widget> - <customwidgets> - <customwidget> - <class>BitcoinAmountField</class> - <extends>QLineEdit</extends> - <header>bitcoinamountfield.h</header> - </customwidget> - </customwidgets> - <resources/> - <connections> - <connection> - <sender>chkReqPayment</sender> - <signal>clicked(bool)</signal> - <receiver>lnReqAmount</receiver> - <slot>setEnabled(bool)</slot> - <hints> - <hint type="sourcelabel"> - <x>92</x> - <y>285</y> - </hint> - <hint type="destinationlabel"> - <x>98</x> - <y>311</y> - </hint> - </hints> - </connection> - </connections> -</ui> diff --git a/src/qt/forms/receivecoinsdialog.ui b/src/qt/forms/receivecoinsdialog.ui new file mode 100644 index 0000000000..6d1a72ecd2 --- /dev/null +++ b/src/qt/forms/receivecoinsdialog.ui @@ -0,0 +1,194 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>ReceiveCoinsDialog</class> + <widget class="QWidget" name="ReceiveCoinsDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>776</width> + <height>343</height> + </rect> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <layout class="QGridLayout" name="gridLayout"> + <item row="3" column="0"> + <widget class="QLabel" name="label"> + <property name="text"> + <string>&Amount:</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + <property name="buddy"> + <cstring>reqAmount</cstring> + </property> + </widget> + </item> + <item row="3" column="1"> + <widget class="BitcoinAmountField" name="reqAmount"> + <property name="minimumSize"> + <size> + <width>80</width> + <height>0</height> + </size> + </property> + <property name="toolTip"> + <string>The amount to request</string> + </property> + </widget> + </item> + <item row="4" column="0"> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string>&Label:</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + <property name="buddy"> + <cstring>reqLabel</cstring> + </property> + </widget> + </item> + <item row="4" column="1"> + <widget class="QLineEdit" name="reqLabel"> + <property name="toolTip"> + <string>The label to associate with the receiving address</string> + </property> + </widget> + </item> + <item row="5" column="0"> + <widget class="QLabel" name="label_3"> + <property name="text"> + <string>&Message:</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + <property name="buddy"> + <cstring>reqMessage</cstring> + </property> + </widget> + </item> + <item row="5" column="1"> + <widget class="QLineEdit" name="reqMessage"> + <property name="toolTip"> + <string>The message to attach to payment request</string> + </property> + </widget> + </item> + <item row="6" column="0"> + <widget class="QLabel" name="label_4"> + <property name="text"> + <string/> + </property> + </widget> + </item> + <item row="6" column="1"> + <widget class="QCheckBox" name="reuseAddress"> + <property name="toolTip"> + <string>Reuse one of the previously used receiving addresses. Reusing addresses has security and privacy issues. Do not use this unless re-generating a payment request made before.</string> + </property> + <property name="text"> + <string>R&euse an existing receiving address (not recommended)</string> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QLabel" name="label_5"> + <property name="text"> + <string>Use this form to request payments. All fields are optional.</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <spacer name="verticalSpacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QPushButton" name="clearButton"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip"> + <string>Clear all fields of the form.</string> + </property> + <property name="text"> + <string>Clear</string> + </property> + <property name="icon"> + <iconset resource="../bitcoin.qrc"> + <normaloff>:/icons/remove</normaloff>:/icons/remove</iconset> + </property> + <property name="autoRepeatDelay"> + <number>300</number> + </property> + <property name="autoDefault"> + <bool>false</bool> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="receiveButton"> + <property name="minimumSize"> + <size> + <width>150</width> + <height>0</height> + </size> + </property> + <property name="text"> + <string>&Request payment</string> + </property> + <property name="icon"> + <iconset resource="../bitcoin.qrc"> + <normaloff>:/icons/receiving_addresses</normaloff>:/icons/receiving_addresses</iconset> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>BitcoinAmountField</class> + <extends>QLineEdit</extends> + <header>bitcoinamountfield.h</header> + </customwidget> + </customwidgets> + <resources> + <include location="../bitcoin.qrc"/> + </resources> + <connections/> +</ui> diff --git a/src/qt/forms/receiverequestdialog.ui b/src/qt/forms/receiverequestdialog.ui new file mode 100644 index 0000000000..c9cb3de69f --- /dev/null +++ b/src/qt/forms/receiverequestdialog.ui @@ -0,0 +1,166 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>ReceiveRequestDialog</class> + <widget class="QDialog" name="ReceiveRequestDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>487</width> + <height>597</height> + </rect> + </property> + <layout class="QVBoxLayout" name="verticalLayout_3"> + <item> + <widget class="QRImageWidget" name="lblQRCode"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>300</width> + <height>300</height> + </size> + </property> + <property name="toolTip"> + <string>QR Code</string> + </property> + <property name="textFormat"> + <enum>Qt::PlainText</enum> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QTextEdit" name="outUri"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>0</width> + <height>50</height> + </size> + </property> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Plain</enum> + </property> + <property name="tabChangesFocus"> + <bool>true</bool> + </property> + <property name="textInteractionFlags"> + <set>Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QPushButton" name="btnCopyURI"> + <property name="text"> + <string>Copy &URI</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="btnCopyAddress"> + <property name="text"> + <string>Copy &Address</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="btnCopyImage"> + <property name="text"> + <string>&Copy Image</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="btnSaveAs"> + <property name="text"> + <string>&Save Image...</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_2"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="standardButtons"> + <set>QDialogButtonBox::Close</set> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>QRImageWidget</class> + <extends>QLabel</extends> + <header>receiverequestdialog.h</header> + </customwidget> + </customwidgets> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>ReceiveRequestDialog</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>452</x> + <y>573</y> + </hint> + <hint type="destinationlabel"> + <x>243</x> + <y>298</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>ReceiveRequestDialog</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>452</x> + <y>573</y> + </hint> + <hint type="destinationlabel"> + <x>243</x> + <y>298</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/src/qt/forms/sendcoinsdialog.ui b/src/qt/forms/sendcoinsdialog.ui index 2a00fc5455..67ea45d2fd 100644 --- a/src/qt/forms/sendcoinsdialog.ui +++ b/src/qt/forms/sendcoinsdialog.ui @@ -84,7 +84,7 @@ </sizepolicy> </property> <property name="toolTip"> - <string>Remove all transaction fields</string> + <string>Clear all fields of the form.</string> </property> <property name="text"> <string>Clear &All</string> diff --git a/src/qt/forms/sendcoinsentry.ui b/src/qt/forms/sendcoinsentry.ui index 5c6afd6c71..db742d633d 100644 --- a/src/qt/forms/sendcoinsentry.ui +++ b/src/qt/forms/sendcoinsentry.ui @@ -87,7 +87,7 @@ <item> <widget class="QToolButton" name="addressBookButton"> <property name="toolTip"> - <string>Choose address from address book</string> + <string>Choose previously used address</string> </property> <property name="text"> <string/> @@ -137,7 +137,7 @@ <item row="4" column="1"> <widget class="QValidatedLineEdit" name="addAsLabel"> <property name="toolTip"> - <string>Enter a label for this address to add it to your address book</string> + <string>Enter a label for this address to add it to the list of used addresses</string> </property> </widget> </item> @@ -674,7 +674,6 @@ <class>BitcoinAmountField</class> <extends>QLineEdit</extends> <header>bitcoinamountfield.h</header> - <container>1</container> </customwidget> <customwidget> <class>QValidatedLineEdit</class> diff --git a/src/qt/forms/signverifymessagedialog.ui b/src/qt/forms/signverifymessagedialog.ui index 279b2a5052..04d614a1cd 100644 --- a/src/qt/forms/signverifymessagedialog.ui +++ b/src/qt/forms/signverifymessagedialog.ui @@ -58,7 +58,7 @@ <item> <widget class="QPushButton" name="addressBookButton_SM"> <property name="toolTip"> - <string>Choose an address from the address book</string> + <string>Choose previously used address</string> </property> <property name="text"> <string/> @@ -271,7 +271,7 @@ <item> <widget class="QPushButton" name="addressBookButton_VM"> <property name="toolTip"> - <string>Choose an address from the address book</string> + <string>Choose previously used address</string> </property> <property name="text"> <string/> diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index c951b21b80..5951cef99a 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -112,6 +112,11 @@ bool parseBitcoinURI(const QUrl &uri, SendCoinsRecipient *out) rv.label = i->second; fShouldReturnFalse = false; } + if (i->first == "message") + { + rv.message = i->second; + fShouldReturnFalse = false; + } else if (i->first == "amount") { if(!i->second.isEmpty()) @@ -148,6 +153,34 @@ bool parseBitcoinURI(QString uri, SendCoinsRecipient *out) return parseBitcoinURI(uriInstance, out); } +QString formatBitcoinURI(const SendCoinsRecipient &info) +{ + QString ret = QString("bitcoin:%1").arg(info.address); + int paramCount = 0; + + if (info.amount) + { + ret += QString("?amount=%1").arg(BitcoinUnits::format(BitcoinUnits::BTC, info.amount)); + paramCount++; + } + + if (!info.label.isEmpty()) + { + QString lbl(QUrl::toPercentEncoding(info.label)); + ret += QString("%1label=%2").arg(paramCount == 0 ? "?" : "&").arg(lbl); + paramCount++; + } + + if (!info.message.isEmpty()) + { + QString msg(QUrl::toPercentEncoding(info.message));; + ret += QString("%1message=%2").arg(paramCount == 0 ? "?" : "&").arg(msg); + paramCount++; + } + + return ret; +} + bool isDust(const QString& address, qint64 amount) { CTxDestination dest = CBitcoinAddress(address.toStdString()).Get(); @@ -190,10 +223,9 @@ void copyEntryData(QAbstractItemView *view, int column, int role) } } -QString getSaveFileName(QWidget *parent, const QString &caption, - const QString &dir, - const QString &filter, - QString *selectedSuffixOut) +QString getSaveFileName(QWidget *parent, const QString &caption, const QString &dir, + const QString &filter, + QString *selectedSuffixOut) { QString selectedFilter; QString myDir; @@ -209,7 +241,8 @@ QString getSaveFileName(QWidget *parent, const QString &caption, { myDir = dir; } - QString result = QFileDialog::getSaveFileName(parent, caption, myDir, filter, &selectedFilter); + /* Directly convert path to native OS path separators */ + QString result = QDir::toNativeSeparators(QFileDialog::getSaveFileName(parent, caption, myDir, filter, &selectedFilter)); /* Extract first suffix from filter pattern "Description (*.foo)" or "Description (*.foo *.bar ...) */ QRegExp filter_re(".* \\(\\*\\.(.*)[ \\)]"); @@ -527,7 +560,7 @@ HelpMessageBox::HelpMessageBox(QWidget *parent) : tr("Usage:") + "\n" + " bitcoin-qt [" + tr("command-line options") + "] " + "\n"; - coreOptions = QString::fromStdString(HelpMessage()); + coreOptions = QString::fromStdString(HelpMessage(HMM_BITCOIN_QT)); uiOptions = tr("UI options") + ":\n" + " -lang=<lang> " + tr("Set language, for example \"de_DE\" (default: system locale)") + "\n" + diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h index 8472700f48..956f550989 100644 --- a/src/qt/guiutil.h +++ b/src/qt/guiutil.h @@ -35,6 +35,7 @@ namespace GUIUtil // See Bitcoin URI definition discussion here: https://bitcointalk.org/index.php?topic=33490.0 bool parseBitcoinURI(const QUrl &uri, SendCoinsRecipient *out); bool parseBitcoinURI(QString uri, SendCoinsRecipient *out); + QString formatBitcoinURI(const SendCoinsRecipient &info); // Returns true if given address+amount meets "dust" definition bool isDust(const QString& address, qint64 amount); diff --git a/src/qt/locale/bitcoin_en.ts b/src/qt/locale/bitcoin_en.ts index 4d1a8574d0..0dc56ac5dc 100644 --- a/src/qt/locale/bitcoin_en.ts +++ b/src/qt/locale/bitcoin_en.ts @@ -42,12 +42,7 @@ This product includes software developed by the OpenSSL Project for use in the O <context> <name>AddressBookPage</name> <message> - <location filename="../forms/addressbookpage.ui" line="+14"/> - <source>Address Book</source> - <translation>Address Book</translation> - </message> - <message> - <location line="+19"/> + <location filename="../forms/addressbookpage.ui" line="+30"/> <source>Double-click to edit address or label</source> <translation>Double-click to edit address or label</translation> </message> @@ -57,42 +52,32 @@ This product includes software developed by the OpenSSL Project for use in the O <translation>Create a new address</translation> </message> <message> - <location line="+14"/> + <location line="+3"/> + <source>&New</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+11"/> <source>Copy the currently selected address to the system clipboard</source> <translation>Copy the currently selected address to the system clipboard</translation> </message> <message> - <location line="-11"/> - <source>&New Address</source> - <translation>&New Address</translation> + <location line="+3"/> + <source>&Copy</source> + <translation type="unfinished"></translation> </message> <message> - <location filename="../addressbookpage.cpp" line="+67"/> - <source>These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you.</source> - <translation>These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you.</translation> + <location line="+52"/> + <source>C&lose</source> + <translation type="unfinished"></translation> </message> <message> - <location filename="../forms/addressbookpage.ui" line="+14"/> + <location filename="../addressbookpage.cpp" line="+72"/> <source>&Copy Address</source> <translation>&Copy Address</translation> </message> <message> - <location line="+11"/> - <source>Show &QR Code</source> - <translation>Show &QR Code</translation> - </message> - <message> - <location line="+11"/> - <source>Sign a message to prove you own a Bitcoin address</source> - <translation>Sign a message to prove you own a Bitcoin address</translation> - </message> - <message> - <location line="+3"/> - <source>Sign &Message</source> - <translation>Sign &Message</translation> - </message> - <message> - <location line="+25"/> + <location filename="../forms/addressbookpage.ui" line="-41"/> <source>Delete the currently selected address from the list</source> <translation>Delete the currently selected address from the list</translation> </message> @@ -107,27 +92,47 @@ This product includes software developed by the OpenSSL Project for use in the O <translation>&Export</translation> </message> <message> - <location line="-44"/> - <source>Verify a message to ensure it was signed with a specified Bitcoin address</source> - <translation>Verify a message to ensure it was signed with a specified Bitcoin address</translation> + <location line="-27"/> + <source>&Delete</source> + <translation>&Delete</translation> </message> <message> - <location line="+3"/> - <source>&Verify Message</source> - <translation>&Verify Message</translation> + <location filename="../addressbookpage.cpp" line="-30"/> + <source>Choose the address to send coins to</source> + <translation type="unfinished"></translation> </message> <message> - <location line="+14"/> - <source>&Delete</source> - <translation>&Delete</translation> + <location line="+1"/> + <source>Choose the address to receive coins with</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> + <source>C&hoose</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+6"/> + <source>Sending addresses</source> + <translation type="unfinished"></translation> </message> <message> - <location filename="../addressbookpage.cpp" line="-5"/> + <location line="+1"/> + <source>Receiving addresses</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+7"/> <source>These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins.</source> <translation>These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins.</translation> </message> <message> - <location line="+13"/> + <location line="+4"/> + <source>These are your Bitcoin addresses for receiving payments. It is recommended to use a new receiving address for each transaction.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+7"/> <source>Copy &Label</source> <translation>Copy &Label</translation> </message> @@ -137,14 +142,9 @@ This product includes software developed by the OpenSSL Project for use in the O <translation>&Edit</translation> </message> <message> - <location line="+1"/> - <source>Send &Coins</source> - <translation>Send &Coins</translation> - </message> - <message> - <location line="+265"/> - <source>Export Address Book Data</source> - <translation>Export Address Book Data</translation> + <location line="+197"/> + <source>Export Address List</source> + <translation type="unfinished"></translation> </message> <message> <location line="+1"/> @@ -324,17 +324,17 @@ This product includes software developed by the OpenSSL Project for use in the O <context> <name>BitcoinGUI</name> <message> - <location filename="../bitcoingui.cpp" line="+255"/> + <location filename="../bitcoingui.cpp" line="+250"/> <source>Sign &message...</source> <translation>Sign &message...</translation> </message> <message> - <location line="+246"/> + <location line="+254"/> <source>Synchronizing with network...</source> <translation>Synchronizing with network...</translation> </message> <message> - <location line="-321"/> + <location line="-324"/> <source>&Overview</source> <translation>&Overview</translation> </message> @@ -354,17 +354,7 @@ This product includes software developed by the OpenSSL Project for use in the O <translation>Browse transaction history</translation> </message> <message> - <location line="+7"/> - <source>Edit the list of stored addresses and labels</source> - <translation>Edit the list of stored addresses and labels</translation> - </message> - <message> - <location line="-14"/> - <source>Show the list of addresses for receiving payments</source> - <translation>Show the list of addresses for receiving payments</translation> - </message> - <message> - <location line="+31"/> + <location line="+15"/> <source>E&xit</source> <translation>E&xit</translation> </message> @@ -379,12 +369,13 @@ This product includes software developed by the OpenSSL Project for use in the O <translation>Show information about Bitcoin</translation> </message> <message> + <location line="+3"/> <location line="+2"/> <source>About &Qt</source> <translation>About &Qt</translation> </message> <message> - <location line="+1"/> + <location line="+2"/> <source>Show information about Qt</source> <translation>Show information about Qt</translation> </message> @@ -409,7 +400,7 @@ This product includes software developed by the OpenSSL Project for use in the O <translation>&Change Passphrase...</translation> </message> <message> - <location line="+251"/> + <location line="+259"/> <source>Importing blocks from disk...</source> <translation>Importing blocks from disk...</translation> </message> @@ -419,12 +410,12 @@ This product includes software developed by the OpenSSL Project for use in the O <translation>Reindexing blocks on disk...</translation> </message> <message> - <location line="-319"/> + <location line="-322"/> <source>Send coins to a Bitcoin address</source> <translation>Send coins to a Bitcoin address</translation> </message> <message> - <location line="+52"/> + <location line="+47"/> <source>Modify configuration options for Bitcoin</source> <translation>Modify configuration options for Bitcoin</translation> </message> @@ -454,20 +445,20 @@ This product includes software developed by the OpenSSL Project for use in the O <translation>&Verify message...</translation> </message> <message> - <location line="-183"/> + <location line="-180"/> <location line="+6"/> - <location line="+508"/> + <location line="+513"/> <source>Bitcoin</source> <translation>Bitcoin</translation> </message> <message> - <location line="-514"/> + <location line="-519"/> <location line="+6"/> <source>Wallet</source> <translation>Wallet</translation> </message> <message> - <location line="+107"/> + <location line="+109"/> <source>&Send</source> <translation>&Send</translation> </message> @@ -477,18 +468,13 @@ This product includes software developed by the OpenSSL Project for use in the O <translation>&Receive</translation> </message> <message> - <location line="+14"/> - <source>&Addresses</source> - <translation>&Addresses</translation> - </message> - <message> - <location line="+23"/> + <location line="+28"/> <location line="+2"/> <source>&About Bitcoin</source> <translation>&About Bitcoin</translation> </message> <message> - <location line="+10"/> + <location line="+14"/> <location line="+2"/> <source>&Show / Hide</source> <translation>&Show / Hide</translation> @@ -514,12 +500,12 @@ This product includes software developed by the OpenSSL Project for use in the O <translation>Verify messages to ensure they were signed with specified Bitcoin addresses</translation> </message> <message> - <location line="+28"/> + <location line="+35"/> <source>&File</source> <translation>&File</translation> </message> <message> - <location line="+7"/> + <location line="+10"/> <source>&Settings</source> <translation>&Settings</translation> </message> @@ -534,19 +520,44 @@ This product includes software developed by the OpenSSL Project for use in the O <translation>Tabs toolbar</translation> </message> <message> - <location line="-228"/> - <location line="+288"/> + <location line="-235"/> + <location line="+294"/> <source>[testnet]</source> <translation>[testnet]</translation> </message> <message> - <location line="-5"/> + <location line="-177"/> + <source>Request payments (generates QR codes and bitcoin: URIs)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+63"/> + <source>&Used sending addresses...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>Show the list of used sending addresses and labels</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>Used &receiving addresses...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>Show the list of used receiving addresses and labels</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+106"/> <location line="+5"/> <source>Bitcoin client</source> <translation>Bitcoin client</translation> </message> <message numerus="yes"> - <location line="+121"/> + <location line="+120"/> <source>%n active connection(s) to Bitcoin network</source> <translation> <numerusform>%n active connection to Bitcoin network</numerusform> @@ -608,7 +619,7 @@ This product includes software developed by the OpenSSL Project for use in the O <translation>Transactions after this will not yet be visible.</translation> </message> <message> - <location line="+22"/> + <location line="+27"/> <source>Error</source> <translation>Error</translation> </message> @@ -623,12 +634,12 @@ This product includes software developed by the OpenSSL Project for use in the O <translation>Information</translation> </message> <message> - <location line="+73"/> + <location line="+77"/> <source>This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee?</source> <translation>This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee?</translation> </message> <message> - <location line="-143"/> + <location line="-152"/> <source>Up to date</source> <translation>Up to date</translation> </message> @@ -638,7 +649,7 @@ This product includes software developed by the OpenSSL Project for use in the O <translation>Catching up...</translation> </message> <message> - <location line="+116"/> + <location line="+124"/> <source>Confirm transaction fee</source> <translation>Confirm transaction fee</translation> </message> @@ -676,13 +687,7 @@ Address: %4 <translation>URI can not be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters.</translation> </message> <message> - <location line="+27"/> - <location line="+2"/> - <source>Payment acknowledged</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+17"/> + <location line="+45"/> <source>Wallet is <b>encrypted</b> and currently <b>unlocked</b></source> <translation>Wallet is <b>encrypted</b> and currently <b>unlocked</b></translation> </message> @@ -700,7 +705,7 @@ Address: %4 <context> <name>ClientModel</name> <message> - <location filename="../clientmodel.cpp" line="+106"/> + <location filename="../clientmodel.cpp" line="+115"/> <source>Network Alert</source> <translation>Network Alert</translation> </message> @@ -719,18 +724,18 @@ Address: %4 </message> <message> <location line="+10"/> - <source>The label associated with this address book entry</source> - <translation>The label associated with this address book entry</translation> + <source>The label associated with this address list entry</source> + <translation type="unfinished"></translation> </message> <message> - <location line="+7"/> - <source>&Address</source> - <translation>&Address</translation> + <location line="+17"/> + <source>The address associated with this address list entry. This can only be modified for sending addresses.</source> + <translation type="unfinished"></translation> </message> <message> - <location line="+10"/> - <source>The address associated with this address book entry. This can only be modified for sending addresses.</source> - <translation>The address associated with this address book entry. This can only be modified for sending addresses.</translation> + <location line="-10"/> + <source>&Address</source> + <translation>&Address</translation> </message> <message> <location filename="../editaddressdialog.cpp" line="+21"/> @@ -804,7 +809,7 @@ Address: %4 <context> <name>GUIUtil::HelpMessageBox</name> <message> - <location filename="../guiutil.cpp" line="+525"/> + <location filename="../guiutil.cpp" line="+558"/> <location line="+13"/> <source>Bitcoin-Qt</source> <translation>Bitcoin-Qt</translation> @@ -1181,8 +1186,23 @@ Address: %4 <context> <name>PaymentServer</name> <message> - <location filename="../paymentserver.cpp" line="+450"/> - <location line="+41"/> + <location filename="../paymentserver.cpp" line="+392"/> + <source>URI handling</source> + <translation type="unfinished">URI handling</translation> + </message> + <message> + <location line="+1"/> + <source>URI can not be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters.</source> + <translation type="unfinished">URI can not be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters.</translation> + </message> + <message> + <location line="+69"/> + <source>Requested payment amount of %1 is too small (considered dust).</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+4"/> + <location line="+37"/> <source>Payment request error</source> <translation type="unfinished"></translation> </message> @@ -1193,12 +1213,27 @@ Address: %4 </message> <message> <location line="+38"/> - <source>Refund from</source> + <source>Refund from %1</source> <translation type="unfinished"></translation> </message> <message> - <location line="+46"/> - <location line="+28"/> + <location line="+42"/> + <source>Error communicating with %1: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+31"/> + <source>Bad response from server %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+32"/> + <source>Payment acknowledged</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="-58"/> + <location line="+30"/> <location line="+17"/> <source>Network request error</source> <translation type="unfinished"></translation> @@ -1207,7 +1242,7 @@ Address: %4 <context> <name>QObject</name> <message> - <location filename="../bitcoin.cpp" line="+111"/> + <location filename="../bitcoin.cpp" line="+114"/> <location line="+5"/> <location filename="../intro.cpp" line="-32"/> <source>Bitcoin</source> @@ -1228,78 +1263,28 @@ Address: %4 <source>Error: Specified data directory "%1" can not be created.</source> <translation>Error: Specified data directory "%1" can not be created.</translation> </message> - <message> - <location filename="../paymentserver.cpp" line="-175"/> - <source>Requested payment amount (%1) too small</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+126"/> - <source>Error communicating with %1: %2</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+29"/> - <source>Bad response from server %1</source> - <translation type="unfinished"></translation> - </message> </context> <context> - <name>QRCodeDialog</name> - <message> - <location filename="../forms/qrcodedialog.ui" line="+14"/> - <source>QR Code Dialog</source> - <translation>QR Code Dialog</translation> - </message> - <message> - <location line="+59"/> - <source>Request Payment</source> - <translation>Request Payment</translation> - </message> - <message> - <location line="+56"/> - <source>Amount:</source> - <translation>Amount:</translation> - </message> - <message> - <location line="-44"/> - <source>Label:</source> - <translation>Label:</translation> - </message> + <name>QRImageWidget</name> <message> - <location line="+19"/> - <source>Message:</source> - <translation>Message:</translation> - </message> - <message> - <location line="+71"/> - <source>&Save As...</source> - <translation>&Save As...</translation> - </message> - <message> - <location filename="../qrcodedialog.cpp" line="+64"/> - <source>Error encoding URI into QR Code.</source> - <translation>Error encoding URI into QR Code.</translation> - </message> - <message> - <location line="+40"/> - <source>The entered amount is invalid, please check.</source> - <translation>The entered amount is invalid, please check.</translation> + <location filename="../receiverequestdialog.cpp" line="+32"/> + <source>&Save Image...</source> + <translation type="unfinished"></translation> </message> <message> - <location line="+23"/> - <source>Resulting URI too long, try to reduce the text for label / message.</source> - <translation>Resulting URI too long, try to reduce the text for label / message.</translation> + <location line="+3"/> + <source>&Copy Image</source> + <translation type="unfinished"></translation> </message> <message> - <location line="+25"/> + <location line="+28"/> <source>Save QR Code</source> - <translation>Save QR Code</translation> + <translation type="unfinished">Save QR Code</translation> </message> <message> <location line="+0"/> <source>PNG Images (*.png)</source> - <translation>PNG Images (*.png)</translation> + <translation type="unfinished">PNG Images (*.png)</translation> </message> </context> <context> @@ -1319,7 +1304,7 @@ Address: %4 <location line="+53"/> <location line="+23"/> <location line="+23"/> - <location filename="../rpcconsole.cpp" line="+345"/> + <location filename="../rpcconsole.cpp" line="+352"/> <source>N/A</source> <translation>N/A</translation> </message> @@ -1404,7 +1389,32 @@ Address: %4 <translation>&Console</translation> </message> <message> - <location line="-260"/> + <location line="+72"/> + <source>&Network Traffic</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+52"/> + <source>&Clear</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+13"/> + <source>Totals</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+64"/> + <source>In:</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+80"/> + <source>Out:</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="-541"/> <source>Build date</source> <translation>Build date</translation> </message> @@ -1448,20 +1458,184 @@ Address: %4 <source>Type <b>help</b> for an overview of available commands.</source> <translation>Type <b>help</b> for an overview of available commands.</translation> </message> + <message> + <location line="+128"/> + <source>%1 B</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>%1 KB</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>%1 MB</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>%1 GB</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+7"/> + <source>%1 m</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> + <source>%1 h</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>%1 h %2 m</source> + <translation type="unfinished"></translation> + </message> </context> <context> - <name>SendCoinsDialog</name> + <name>ReceiveCoinsDialog</name> + <message> + <location filename="../forms/receivecoinsdialog.ui" line="+22"/> + <source>&Amount:</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+16"/> + <source>The amount to request</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+7"/> + <source>&Label:</source> + <translation type="unfinished">&Label:</translation> + </message> + <message> + <location line="+10"/> + <source>The label to associate with the receiving address</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+7"/> + <source>&Message:</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+10"/> + <source>The message to attach to payment request</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+14"/> + <source>Reuse one of the previously used receiving addresses. Reusing addresses has security and privacy issues. Do not use this unless re-generating a payment request made before.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>R&euse an existing receiving address (not recommended)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+7"/> + <source>Use this form to request payments. All fields are optional.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+17"/> + <source>Clear all fields of the form.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>Clear</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+36"/> + <source>&Request payment</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>ReceiveRequestDialog</name> + <message> + <location filename="../forms/receiverequestdialog.ui" line="+29"/> + <source>QR Code</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+46"/> + <source>Copy &URI</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+7"/> + <source>Copy &Address</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+7"/> + <source>&Copy Image</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+7"/> + <source>&Save Image...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../receiverequestdialog.cpp" line="+58"/> + <source>Request payment to %1</source> + <translation type="unfinished"></translation> + </message> <message> - <location filename="../forms/sendcoinsdialog.ui" line="+14"/> - <location filename="../sendcoinsdialog.cpp" line="+138"/> - <location line="+5"/> - <location line="+5"/> - <location line="+5"/> <location line="+6"/> + <source>Payment information</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>URI</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Address</source> + <translation type="unfinished">Address</translation> + </message> + <message> + <location line="+2"/> + <source>Amount</source> + <translation type="unfinished">Amount</translation> + </message> + <message> + <location line="+2"/> + <source>Label</source> + <translation type="unfinished">Label</translation> + </message> + <message> + <location line="+2"/> + <source>Message</source> + <translation type="unfinished">Message</translation> + </message> + <message> + <location line="+10"/> + <source>Resulting URI too long, try to reduce the text for label / message.</source> + <translation type="unfinished">Resulting URI too long, try to reduce the text for label / message.</translation> + </message> + <message> <location line="+5"/> - <location line="+50"/> - <location line="+145"/> - <location line="+9"/> + <source>Error encoding URI into QR Code.</source> + <translation type="unfinished">Error encoding URI into QR Code.</translation> + </message> +</context> +<context> + <name>SendCoinsDialog</name> + <message> + <location filename="../forms/sendcoinsdialog.ui" line="+14"/> + <location filename="../sendcoinsdialog.cpp" line="+140"/> + <location line="+213"/> <source>Send Coins</source> <translation>Send Coins</translation> </message> @@ -1477,8 +1651,8 @@ Address: %4 </message> <message> <location line="+20"/> - <source>Remove all transaction fields</source> - <translation>Remove all transaction fields</translation> + <source>Clear all fields of the form.</source> + <translation type="unfinished"></translation> </message> <message> <location line="+3"/> @@ -1506,47 +1680,44 @@ Address: %4 <translation>S&end</translation> </message> <message> - <location filename="../sendcoinsdialog.cpp" line="-170"/> + <location filename="../sendcoinsdialog.cpp" line="-154"/> <source>Confirm send coins</source> <translation>Confirm send coins</translation> </message> <message> - <location line="-97"/> - <source>to</source> - <translation type="unfinished">to</translation> - </message> - <message> - <location line="+15"/> - <source><b>%1</b> to %2</source> + <location line="-90"/> + <location line="+5"/> + <location line="+5"/> + <source>%1 to %2</source> <translation type="unfinished"></translation> </message> <message> - <location line="+23"/> + <location line="+26"/> <source>The recipient address is not valid, please recheck.</source> <translation>The recipient address is not valid, please recheck.</translation> </message> <message> - <location line="+5"/> + <location line="+4"/> <source>The amount to pay must be larger than 0.</source> <translation>The amount to pay must be larger than 0.</translation> </message> <message> - <location line="+5"/> + <location line="+4"/> <source>The amount exceeds your balance.</source> <translation>The amount exceeds your balance.</translation> </message> <message> - <location line="+5"/> + <location line="+4"/> <source>The total exceeds your balance when the %1 transaction fee is included.</source> <translation>The total exceeds your balance when the %1 transaction fee is included.</translation> </message> <message> - <location line="+6"/> + <location line="+5"/> <source>Duplicate address found, can only send to each address once per send operation.</source> <translation>Duplicate address found, can only send to each address once per send operation.</translation> </message> <message> - <location line="+5"/> + <location line="+4"/> <source>Error: Transaction creation failed!</source> <translation>Error: Transaction creation failed!</translation> </message> @@ -1571,12 +1742,12 @@ Address: %4 <translation>Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here.</translation> </message> <message> - <location line="+145"/> + <location line="+144"/> <source>Payment request expired</source> <translation type="unfinished"></translation> </message> <message> - <location line="+9"/> + <location line="+8"/> <source>Invalid payment address %1</source> <translation type="unfinished"></translation> </message> @@ -1584,49 +1755,38 @@ Address: %4 <context> <name>SendCoinsEntry</name> <message> - <location filename="../forms/sendcoinsentry.ui" line="+24"/> - <source>Form</source> - <translation>Form</translation> - </message> - <message> - <location line="+15"/> - <location line="+588"/> + <location filename="../forms/sendcoinsentry.ui" line="+33"/> + <location line="+585"/> <source>A&mount:</source> <translation>A&mount:</translation> </message> <message> - <location line="-575"/> - <location line="+588"/> + <location line="-572"/> + <location line="+585"/> <source>Pay &To:</source> <translation>Pay &To:</translation> </message> <message> - <location line="-554"/> + <location line="-551"/> <source>The address to send the payment to (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</source> <translation>The address to send the payment to (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</translation> </message> <message> - <location line="+60"/> <location filename="../sendcoinsentry.cpp" line="+28"/> <source>Enter a label for this address to add it to your address book</source> <translation>Enter a label for this address to add it to your address book</translation> </message> <message> - <location line="-78"/> + <location filename="../forms/sendcoinsentry.ui" line="-18"/> <source>&Label:</source> <translation>&Label:</translation> </message> <message> - <location line="-54"/> - <source>StackedWidget</source> + <location line="+28"/> + <source>Choose previously used address</source> <translation type="unfinished"></translation> </message> <message> - <location line="+82"/> - <source>Choose address from address book</source> - <translation>Choose address from address book</translation> - </message> - <message> <location line="+10"/> <source>Alt+A</source> <translation>Alt+A</translation> @@ -1647,21 +1807,16 @@ Address: %4 <translation>Remove this recipient</translation> </message> <message> - <location line="+466"/> - <source>SecureSend</source> + <location line="+16"/> + <source>Enter a label for this address to add it to the list of used addresses</source> <translation type="unfinished"></translation> </message> <message> - <location line="+18"/> + <location line="+465"/> <source>Memo:</source> <translation type="unfinished"></translation> </message> <message> - <location line="+63"/> - <source>message from merchant</source> - <translation type="unfinished"></translation> - </message> - <message> <location filename="../sendcoinsentry.cpp" line="+1"/> <source>Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</source> <translation>Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</translation> @@ -1692,8 +1847,8 @@ Address: %4 <message> <location line="+10"/> <location line="+213"/> - <source>Choose an address from the address book</source> - <translation>Choose an address from the address book</translation> + <source>Choose previously used address</source> + <translation type="unfinished"></translation> </message> <message> <location line="-203"/> @@ -1874,6 +2029,14 @@ Address: %4 </message> </context> <context> + <name>TrafficGraphWidget</name> + <message> + <location filename="../trafficgraphwidget.cpp" line="+75"/> + <source>KB/s</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> <name>TransactionDesc</name> <message> <location filename="../transactiondesc.cpp" line="+22"/> @@ -1952,12 +2115,12 @@ Address: %4 <location line="+12"/> <location line="+45"/> <location line="+17"/> - <location line="+45"/> + <location line="+48"/> <source>Credit</source> <translation>Credit</translation> </message> <message numerus="yes"> - <location line="-117"/> + <location line="-120"/> <source>matures in %n more block(s)</source> <translation> <numerusform>matures in %n more block</numerusform> @@ -1973,12 +2136,12 @@ Address: %4 <location line="+44"/> <location line="+8"/> <location line="+15"/> - <location line="+45"/> + <location line="+48"/> <source>Debit</source> <translation>Debit</translation> </message> <message> - <location line="-54"/> + <location line="-57"/> <source>Transaction fee</source> <translation>Transaction fee</translation> </message> @@ -2008,12 +2171,12 @@ Address: %4 <translation type="unfinished"></translation> </message> <message> - <location line="+5"/> - <source>Generated coins must mature 120 blocks before they can be spent. When you generated this block, it was broadcast to the network to be added to the block chain. If it fails to get into the chain, its state will change to "not accepted" and it won't be spendable. This may occasionally happen if another node generates a block within a few seconds of yours.</source> - <translation>Generated coins must mature 120 blocks before they can be spent. When you generated this block, it was broadcast to the network to be added to the block chain. If it fails to get into the chain, its state will change to "not accepted" and it won't be spendable. This may occasionally happen if another node generates a block within a few seconds of yours.</translation> + <location line="+7"/> + <source>Generated coins must mature %1 blocks before they can be spent. When you generated this block, it was broadcast to the network to be added to the block chain. If it fails to get into the chain, its state will change to "not accepted" and it won't be spendable. This may occasionally happen if another node generates a block within a few seconds of yours.</source> + <translation type="unfinished"></translation> </message> <message> - <location line="+7"/> + <location line="+8"/> <source>Debug information</source> <translation>Debug information</translation> </message> @@ -2043,7 +2206,7 @@ Address: %4 <translation>false</translation> </message> <message> - <location line="-224"/> + <location line="-227"/> <source>, has not been successfully broadcast yet</source> <translation>, has not been successfully broadcast yet</translation> </message> @@ -2388,7 +2551,7 @@ Address: %4 <translation>Export the data in the current tab to a file</translation> </message> <message> - <location line="+198"/> + <location line="+183"/> <source>Backup Wallet</source> <translation>Backup Wallet</translation> </message> @@ -2421,22 +2584,17 @@ Address: %4 <context> <name>bitcoin-core</name> <message> - <location filename="../bitcoinstrings.cpp" line="+101"/> + <location filename="../bitcoinstrings.cpp" line="+102"/> <source>Bitcoin version</source> <translation>Bitcoin version</translation> </message> <message> - <location line="+104"/> + <location line="+107"/> <source>Usage:</source> <translation>Usage:</translation> </message> <message> - <location line="-30"/> - <source>Send command to -server or bitcoind</source> - <translation>Send command to -server or bitcoind</translation> - </message> - <message> - <location line="-23"/> + <location line="-55"/> <source>List commands</source> <translation>List commands</translation> </message> @@ -2491,12 +2649,12 @@ Address: %4 <translation>Specify your own public address</translation> </message> <message> - <location line="+3"/> + <location line="+4"/> <source>Threshold for disconnecting misbehaving peers (default: 100)</source> <translation>Threshold for disconnecting misbehaving peers (default: 100)</translation> </message> <message> - <location line="-139"/> + <location line="-142"/> <source>Number of seconds to keep misbehaving peers from reconnecting (default: 86400)</source> <translation>Number of seconds to keep misbehaving peers from reconnecting (default: 86400)</translation> </message> @@ -2516,17 +2674,17 @@ Address: %4 <translation>Accept command line and JSON-RPC commands</translation> </message> <message> - <location line="+77"/> + <location line="+79"/> <source>Run in the background as a daemon and accept commands</source> <translation>Run in the background as a daemon and accept commands</translation> </message> <message> - <location line="+38"/> + <location line="+40"/> <source>Use the test network</source> <translation>Use the test network</translation> </message> <message> - <location line="-114"/> + <location line="-118"/> <source>Accept connections from outside (default: 1 if no -proxy or -connect)</source> <translation>Accept connections from outside (default: 1 if no -proxy or -connect)</translation> </message> @@ -2556,7 +2714,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </translation> </message> <message> - <location line="+17"/> + <location line="+12"/> + <source>Acceptable ciphers (default: TLSv1.2+HIGH:TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!3DES:@STRENGTH)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> <source>An error occurred while setting up the RPC port %u for listening on IPv6, falling back to IPv4: %s</source> <translation>An error occurred while setting up the RPC port %u for listening on IPv6, falling back to IPv4: %s</translation> </message> @@ -2636,6 +2799,11 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. <translation>Attempt to recover private keys from a corrupt wallet.dat</translation> </message> <message> + <location line="+1"/> + <source>Bitcoin RPC client version</source> + <translation type="unfinished"></translation> + </message> + <message> <location line="+2"/> <source>Block creation options:</source> <translation>Block creation options:</translation> @@ -2646,7 +2814,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. <translation>Connect only to the specified node(s)</translation> </message> <message> - <location line="+3"/> + <location line="+2"/> + <source>Connect to JSON-RPC on <port> (default: 8332 or testnet: 18332)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> <source>Corrupted block database detected</source> <translation>Corrupted block database detected</translation> </message> @@ -2776,7 +2949,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. <translation>Incorrect or no genesis block found. Wrong datadir for network?</translation> </message> <message> - <location line="+18"/> + <location line="+3"/> + <source>Invalid -onion address: '%s'</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+15"/> <source>Not enough file descriptors available.</source> <translation>Not enough file descriptors available.</translation> </message> @@ -2786,7 +2964,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. <translation>Rebuild block chain index from current blk000??.dat files</translation> </message> <message> - <location line="+16"/> + <location line="+6"/> + <source>Send command to Bitcoin server</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+10"/> <source>Set the number of threads to service RPC calls (default: 4)</source> <translation>Set the number of threads to service RPC calls (default: 4)</translation> </message> @@ -2796,7 +2979,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. <translation>Specify wallet file (within data directory)</translation> </message> <message> - <location line="+20"/> + <location line="+2"/> + <source>Start Bitcoin server</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+12"/> + <source>Usage (deprecated, use bitcoin-cli):</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+8"/> <source>Verifying blocks...</source> <translation>Verifying blocks...</translation> </message> @@ -2816,12 +3009,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. <translation>You need to rebuild the database using -reindex to change -txindex</translation> </message> <message> - <location line="-76"/> + <location line="-78"/> <source>Imports blocks from external blk000??.dat file</source> <translation>Imports blocks from external blk000??.dat file</translation> </message> <message> - <location line="-96"/> + <location line="-98"/> <source>Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message)</source> <translation>Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message)</translation> </message> @@ -2831,17 +3024,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. <translation>Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0)</translation> </message> <message> - <location line="+81"/> + <location line="+83"/> <source>Information</source> <translation>Information</translation> </message> <message> - <location line="+3"/> - <source>Invalid -tor address: '%s'</source> - <translation>Invalid -tor address: '%s'</translation> - </message> - <message> - <location line="+1"/> + <location line="+4"/> <source>Invalid amount for -minrelaytxfee=<amount>: '%s'</source> <translation>Invalid amount for -minrelaytxfee=<amount>: '%s'</translation> </message> @@ -2936,7 +3124,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. <translation>Specify connection timeout in milliseconds (default: 5000)</translation> </message> <message> - <location line="+5"/> + <location line="+6"/> <source>System error: </source> <translation>System error: </translation> </message> @@ -2956,7 +3144,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. <translation>Transaction too large</translation> </message> <message> - <location line="+7"/> + <location line="+8"/> <source>Use UPnP to map the listening port (default: 0)</source> <translation>Use UPnP to map the listening port (default: 0)</translation> </message> @@ -2991,32 +3179,32 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. <translation>wallet.dat corrupt, salvage failed</translation> </message> <message> - <location line="-52"/> + <location line="-54"/> <source>Password for JSON-RPC connections</source> <translation>Password for JSON-RPC connections</translation> </message> <message> - <location line="-68"/> + <location line="-70"/> <source>Allow JSON-RPC connections from specified IP address</source> <translation>Allow JSON-RPC connections from specified IP address</translation> </message> <message> - <location line="+77"/> + <location line="+79"/> <source>Send commands to node running on <ip> (default: 127.0.0.1)</source> <translation>Send commands to node running on <ip> (default: 127.0.0.1)</translation> </message> <message> - <location line="-124"/> + <location line="-126"/> <source>Execute command when the best block changes (%s in cmd is replaced by block hash)</source> <translation>Execute command when the best block changes (%s in cmd is replaced by block hash)</translation> </message> <message> - <location line="+152"/> + <location line="+155"/> <source>Upgrade wallet to latest format</source> <translation>Upgrade wallet to latest format</translation> </message> <message> - <location line="-22"/> + <location line="-23"/> <source>Set key pool size to <n> (default: 100)</source> <translation>Set key pool size to <n> (default: 100)</translation> </message> @@ -3026,12 +3214,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. <translation>Rescan the block chain for missing wallet transactions</translation> </message> <message> - <location line="+36"/> + <location line="+38"/> <source>Use OpenSSL (https) for JSON-RPC connections</source> <translation>Use OpenSSL (https) for JSON-RPC connections</translation> </message> <message> - <location line="-27"/> + <location line="-29"/> <source>Server certificate file (default: server.cert)</source> <translation>Server certificate file (default: server.cert)</translation> </message> @@ -3041,12 +3229,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. <translation>Server private key (default: server.pem)</translation> </message> <message> - <location line="-159"/> - <source>Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH)</source> - <translation>Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH)</translation> - </message> - <message> - <location line="+174"/> + <location line="+16"/> <source>This help message</source> <translation>This help message</translation> </message> @@ -3056,17 +3239,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. <translation>Unable to bind to %s on this computer (bind returned error %d, %s)</translation> </message> <message> - <location line="-93"/> + <location line="-95"/> <source>Connect through socks proxy</source> <translation>Connect through socks proxy</translation> </message> <message> - <location line="-10"/> + <location line="-11"/> <source>Allow DNS lookups for -addnode, -seednode and -connect</source> <translation>Allow DNS lookups for -addnode, -seednode and -connect</translation> </message> <message> - <location line="+56"/> + <location line="+58"/> <source>Loading addresses...</source> <translation>Loading addresses...</translation> </message> @@ -3081,17 +3264,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. <translation>Error loading wallet.dat: Wallet requires newer version of Bitcoin</translation> </message> <message> - <location line="+96"/> + <location line="+98"/> <source>Wallet needed to be rewritten: restart Bitcoin to complete</source> <translation>Wallet needed to be rewritten: restart Bitcoin to complete</translation> </message> <message> - <location line="-98"/> + <location line="-100"/> <source>Error loading wallet.dat</source> <translation>Error loading wallet.dat</translation> </message> <message> - <location line="+29"/> + <location line="+30"/> <source>Invalid -proxy address: '%s'</source> <translation>Invalid -proxy address: '%s'</translation> </message> @@ -3106,7 +3289,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. <translation>Unknown -socks proxy version requested: %i</translation> </message> <message> - <location line="-98"/> + <location line="-100"/> <source>Cannot resolve -bind address: '%s'</source> <translation>Cannot resolve -bind address: '%s'</translation> </message> @@ -3116,7 +3299,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. <translation>Cannot resolve -externalip address: '%s'</translation> </message> <message> - <location line="+45"/> + <location line="+46"/> <source>Invalid amount for -paytxfee=<amount>: '%s'</source> <translation>Invalid amount for -paytxfee=<amount>: '%s'</translation> </message> @@ -3136,7 +3319,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. <translation>Loading block index...</translation> </message> <message> - <location line="-58"/> + <location line="-60"/> <source>Add a node to connect to and attempt to keep the connection open</source> <translation>Add a node to connect to and attempt to keep the connection open</translation> </message> @@ -3146,7 +3329,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. <translation>Unable to bind to %s on this computer. Bitcoin is probably already running.</translation> </message> <message> - <location line="+67"/> + <location line="+69"/> <source>Fee per KB to add to transactions you send</source> <translation>Fee per KB to add to transactions you send</translation> </message> @@ -3156,7 +3339,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. <translation>Loading wallet...</translation> </message> <message> - <location line="-53"/> + <location line="-54"/> <source>Cannot downgrade wallet</source> <translation>Cannot downgrade wallet</translation> </message> @@ -3166,7 +3349,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. <translation>Cannot write default address</translation> </message> <message> - <location line="+65"/> + <location line="+66"/> <source>Rescanning...</source> <translation>Rescanning...</translation> </message> @@ -3176,17 +3359,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. <translation>Done loading</translation> </message> <message> - <location line="+84"/> + <location line="+85"/> <source>To use the %s option</source> <translation>To use the %s option</translation> </message> <message> - <location line="-76"/> + <location line="-77"/> <source>Error</source> <translation>Error</translation> </message> <message> - <location line="-31"/> + <location line="-33"/> <source>You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions.</source> diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index 95efc58320..4db048dcce 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -6,6 +6,9 @@ #include "bitcoinunits.h" #include "init.h" +#include "core.h" +#include "wallet.h" +#include "netbase.h" #include "walletdb.h" #include "guiutil.h" diff --git a/src/qt/paymentrequestplus.cpp b/src/qt/paymentrequestplus.cpp index f6a898ff7c..c8afd837d2 100644 --- a/src/qt/paymentrequestplus.cpp +++ b/src/qt/paymentrequestplus.cpp @@ -75,8 +75,7 @@ bool PaymentRequestPlus::getMerchant(X509_STORE* certStore, QString& merchant) c digestAlgorithm = EVP_sha1(); } else if (paymentRequest.pki_type() == "none") { - if (fDebug) - qDebug() << "PaymentRequestPlus::getMerchant : Payment request: pki_type == none"; + qDebug() << "PaymentRequestPlus::getMerchant : Payment request: pki_type == none"; return false; } else { diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp index af75d6b4e5..0f386680ac 100644 --- a/src/qt/paymentserver.cpp +++ b/src/qt/paymentserver.cpp @@ -87,9 +87,7 @@ static QList<QString> savedPaymentRequests; static void ReportInvalidCertificate(const QSslCertificate& cert) { - if (fDebug) { - qDebug() << "ReportInvalidCertificate : Payment server found an invalid certificate: " << cert.subjectInfo(QSslCertificate::CommonName); - } + qDebug() << "ReportInvalidCertificate : Payment server found an invalid certificate: " << cert.subjectInfo(QSslCertificate::CommonName); } // @@ -160,8 +158,7 @@ void PaymentServer::LoadRootCAs(X509_STORE* _store) continue; } } - if (fDebug) - qDebug() << "PaymentServer::LoadRootCAs : Loaded " << nRootCerts << " root certificates"; + qDebug() << "PaymentServer::LoadRootCAs : Loaded " << nRootCerts << " root certificates"; // Project for another day: // Fetch certificate revocation lists, and add them to certStore. @@ -250,7 +247,12 @@ bool PaymentServer::ipcSendCommandLine(int argc, char* argv[]) return fResult; } -PaymentServer::PaymentServer(QObject* parent, bool startLocalServer) : QObject(parent), saveURIs(true) +PaymentServer::PaymentServer(QObject* parent, bool startLocalServer) : + QObject(parent), + saveURIs(true), + uriServer(0), + netManager(0), + optionsModel(0) { // Verify that the version of the library that we linked against is // compatible with the version of the headers we compiled against. @@ -258,7 +260,7 @@ PaymentServer::PaymentServer(QObject* parent, bool startLocalServer) : QObject(p // Install global event filter to catch QFileOpenEvents // on Mac: sent when you click bitcoin: links - // other OSes: helpful when dealing with payment-request files (in the future) + // other OSes: helpful when dealing with payment request files (in the future) if (parent) parent->installEventFilter(this); @@ -273,8 +275,10 @@ PaymentServer::PaymentServer(QObject* parent, bool startLocalServer) : QObject(p if (!uriServer->listen(name)) qDebug() << "PaymentServer::PaymentServer : Cannot start bitcoin: click-to-pay handler"; - else + else { connect(uriServer, SIGNAL(newConnection()), this, SLOT(handleURIConnection())); + connect(this, SIGNAL(receivedPaymentACK(QString)), this, SLOT(handlePaymentACK(QString))); + } } // netManager is null until uiReady() is called @@ -316,7 +320,7 @@ void PaymentServer::initNetManager() // netManager is used to fetch paymentrequests given in bitcoin: URIs netManager = new QNetworkAccessManager(this); - // Use proxy settings from optionsModel: + // Use proxy settings from optionsModel QString proxyIP; quint16 proxyPort; if (optionsModel->getProxySettings(proxyIP, proxyPort)) @@ -368,8 +372,7 @@ void PaymentServer::handleURIOrFile(const QString& s) QString decoded = QUrl::fromPercentEncoding(temp); QUrl fetchUrl(decoded, QUrl::StrictMode); - if (fDebug) - qDebug() << "PaymentServer::handleURIOrFile : fetchRequest(" << fetchUrl << ")"; + qDebug() << "PaymentServer::handleURIOrFile : fetchRequest(" << fetchUrl << ")"; if (fetchUrl.isValid()) fetchRequest(fetchUrl); @@ -452,7 +455,7 @@ bool PaymentServer::processPaymentRequest(PaymentRequestPlus& request, QList<Sen foreach(const PAIRTYPE(CScript, qint64)& sendingTo, sendingTos) { CTxOut txOut(sendingTo.second, sendingTo.first); if (txOut.IsDust(CTransaction::nMinRelayTxFee)) { - QString msg = QObject::tr("Requested payment amount (%1) too small") + QString msg = tr("Requested payment amount of %1 is too small (considered dust).") .arg(BitcoinUnits::formatWithUnit(optionsModel->getDisplayUnit(), sendingTo.second)); qDebug() << "PaymentServer::processPaymentRequest : " << msg; @@ -468,8 +471,7 @@ bool PaymentServer::processPaymentRequest(PaymentRequestPlus& request, QList<Sen if (request.getMerchant(PaymentServer::certStore, recipients[0].authenticatedMerchant)) { recipients[0].paymentRequest = request; recipients[0].amount = totalAmount; - if (fDebug) - qDebug() << "PaymentServer::processPaymentRequest : Payment request from " << recipients[0].authenticatedMerchant; + qDebug() << "PaymentServer::processPaymentRequest : Payment request from " << recipients[0].authenticatedMerchant; } else { recipients.clear(); @@ -486,8 +488,7 @@ bool PaymentServer::processPaymentRequest(PaymentRequestPlus& request, QList<Sen if (i == 0) // Tie request to first pay-to, we don't want multiple ACKs recipients[i].paymentRequest = request; recipients[i].address = QString::fromStdString(CBitcoinAddress(dest).ToString()); - if (fDebug) - qDebug() << "PaymentServer::processPaymentRequest : Payment request, insecure " << recipients[i].address; + qDebug() << "PaymentServer::processPaymentRequest : Payment request, insecure " << recipients[i].address; } else { // Insecure payments to custom bitcoin addresses are not supported @@ -532,7 +533,7 @@ void PaymentServer::fetchPaymentACK(CWallet* wallet, SendCoinsRecipient recipien payment.add_transactions(transaction.data(), transaction.size()); // Create a new refund address, or re-use: - QString account = tr("Refund from") + QString(" ") + recipient.authenticatedMerchant; + QString account = tr("Refund from %1").arg(recipient.authenticatedMerchant); std::string strAccount = account.toStdString(); set<CTxDestination> refundAddresses = wallet->GetAccountAddresses(strAccount); if (!refundAddresses.empty()) { @@ -574,9 +575,10 @@ void PaymentServer::netRequestFinished(QNetworkReply* reply) reply->deleteLater(); if (reply->error() != QNetworkReply::NoError) { - QString msg = QObject::tr("Error communicating with %1: %2") + QString msg = tr("Error communicating with %1: %2") .arg(reply->request().url().toString()) .arg(reply->errorString()); + qDebug() << "PaymentServer::netRequestFinished : " << msg; emit message(tr("Network request error"), msg, CClientUIInterface::MSG_ERROR); return; @@ -590,12 +592,13 @@ void PaymentServer::netRequestFinished(QNetworkReply* reply) PaymentRequestPlus request; QList<SendCoinsRecipient> recipients; if (request.parse(data) && processPaymentRequest(request, recipients)) { - foreach (const SendCoinsRecipient& recipient, recipients){ + foreach (const SendCoinsRecipient& recipient, recipients) { emit receivedPaymentRequest(recipient); } } else qDebug() << "PaymentServer::netRequestFinished : Error processing payment request"; + return; } else if (requestType == "PaymentACK") @@ -603,13 +606,14 @@ void PaymentServer::netRequestFinished(QNetworkReply* reply) payments::PaymentACK paymentACK; if (!paymentACK.ParseFromArray(data.data(), data.size())) { - QString msg = QObject::tr("Bad response from server %1") + QString msg = tr("Bad response from server %1") .arg(reply->request().url().toString()); + qDebug() << "PaymentServer::netRequestFinished : " << msg; emit message(tr("Network request error"), msg, CClientUIInterface::MSG_ERROR); } else { - emit receivedPaymentACK(QString::fromStdString(paymentACK.memo())); + emit receivedPaymentACK(GUIUtil::HtmlEscape(paymentACK.memo())); } } } @@ -630,3 +634,9 @@ void PaymentServer::setOptionsModel(OptionsModel *optionsModel) { this->optionsModel = optionsModel; } + +void PaymentServer::handlePaymentACK(const QString& paymentACKMsg) +{ + // currently we don't futher process or store the paymentACK message + emit message(tr("Payment acknowledged"), paymentACKMsg, CClientUIInterface::ICON_INFORMATION | CClientUIInterface::MODAL); +} diff --git a/src/qt/paymentserver.h b/src/qt/paymentserver.h index 042c41ef64..9f43571edc 100644 --- a/src/qt/paymentserver.h +++ b/src/qt/paymentserver.h @@ -88,7 +88,7 @@ signals: void receivedPaymentRequest(SendCoinsRecipient); // Fired when a valid PaymentACK is received - void receivedPaymentACK(QString); + void receivedPaymentACK(const QString &paymentACKMsg); // Fired when a message should be reported to the user void message(const QString &title, const QString &message, unsigned int style); @@ -105,6 +105,7 @@ private slots: void handleURIConnection(); void netRequestFinished(QNetworkReply*); void reportSslErrors(QNetworkReply*, const QList<QSslError> &); + void handlePaymentACK(const QString& paymentACKMsg); private: static bool readPaymentRequest(const QString& filename, PaymentRequestPlus& request); diff --git a/src/qt/qrcodedialog.cpp b/src/qt/qrcodedialog.cpp deleted file mode 100644 index 6ddcaaf5d9..0000000000 --- a/src/qt/qrcodedialog.cpp +++ /dev/null @@ -1,173 +0,0 @@ -#include "qrcodedialog.h" -#include "ui_qrcodedialog.h" - -#include "bitcoinunits.h" -#include "guiconstants.h" -#include "guiutil.h" -#include "optionsmodel.h" - -#include <QPixmap> -#if QT_VERSION < 0x050000 -#include <QUrl> -#endif - -#include <qrencode.h> - -QRCodeDialog::QRCodeDialog(const QString &addr, const QString &label, bool enableReq, QWidget *parent) : - QDialog(parent), - ui(new Ui::QRCodeDialog), - model(0), - address(addr) -{ - ui->setupUi(this); - - setWindowTitle(QString("%1").arg(address)); - - ui->chkReqPayment->setVisible(enableReq); - ui->lblAmount->setVisible(enableReq); - ui->lnReqAmount->setVisible(enableReq); - - ui->lnLabel->setText(label); - - ui->btnSaveAs->setEnabled(false); - - genCode(); -} - -QRCodeDialog::~QRCodeDialog() -{ - delete ui; -} - -void QRCodeDialog::setModel(OptionsModel *model) -{ - this->model = model; - - if (model) - connect(model, SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit())); - - // update the display unit, to not use the default ("BTC") - updateDisplayUnit(); -} - -void QRCodeDialog::genCode() -{ - QString uri = getURI(); - - if (uri != "") - { - ui->lblQRCode->setText(""); - - QRcode *code = QRcode_encodeString(uri.toUtf8().constData(), 0, QR_ECLEVEL_L, QR_MODE_8, 1); - if (!code) - { - ui->lblQRCode->setText(tr("Error encoding URI into QR Code.")); - return; - } - myImage = QImage(code->width + 8, code->width + 8, QImage::Format_RGB32); - myImage.fill(0xffffff); - unsigned char *p = code->data; - for (int y = 0; y < code->width; y++) - { - for (int x = 0; x < code->width; x++) - { - myImage.setPixel(x + 4, y + 4, ((*p & 1) ? 0x0 : 0xffffff)); - p++; - } - } - QRcode_free(code); - - ui->lblQRCode->setPixmap(QPixmap::fromImage(myImage).scaled(300, 300)); - - ui->outUri->setPlainText(uri); - } -} - -QString QRCodeDialog::getURI() -{ - QString ret = QString("bitcoin:%1").arg(address); - int paramCount = 0; - - ui->outUri->clear(); - - if (ui->chkReqPayment->isChecked()) - { - if (ui->lnReqAmount->validate()) - { - // even if we allow a non BTC unit input in lnReqAmount, we generate the URI with BTC as unit (as defined in BIP21) - ret += QString("?amount=%1").arg(BitcoinUnits::format(BitcoinUnits::BTC, ui->lnReqAmount->value())); - paramCount++; - } - else - { - ui->btnSaveAs->setEnabled(false); - ui->lblQRCode->setText(tr("The entered amount is invalid, please check.")); - return QString(""); - } - } - - if (!ui->lnLabel->text().isEmpty()) - { - QString lbl(QUrl::toPercentEncoding(ui->lnLabel->text())); - ret += QString("%1label=%2").arg(paramCount == 0 ? "?" : "&").arg(lbl); - paramCount++; - } - - if (!ui->lnMessage->text().isEmpty()) - { - QString msg(QUrl::toPercentEncoding(ui->lnMessage->text())); - ret += QString("%1message=%2").arg(paramCount == 0 ? "?" : "&").arg(msg); - paramCount++; - } - - // limit URI length to prevent a DoS against the QR-Code dialog - if (ret.length() > MAX_URI_LENGTH) - { - ui->btnSaveAs->setEnabled(false); - ui->lblQRCode->setText(tr("Resulting URI too long, try to reduce the text for label / message.")); - return QString(""); - } - - ui->btnSaveAs->setEnabled(true); - return ret; -} - -void QRCodeDialog::on_lnReqAmount_textChanged() -{ - genCode(); -} - -void QRCodeDialog::on_lnLabel_textChanged() -{ - genCode(); -} - -void QRCodeDialog::on_lnMessage_textChanged() -{ - genCode(); -} - -void QRCodeDialog::on_btnSaveAs_clicked() -{ - QString fn = GUIUtil::getSaveFileName(this, tr("Save QR Code"), QString(), tr("PNG Images (*.png)")); - if (!fn.isEmpty()) - myImage.scaled(EXPORT_IMAGE_SIZE, EXPORT_IMAGE_SIZE).save(fn); -} - -void QRCodeDialog::on_chkReqPayment_toggled(bool fChecked) -{ - if (!fChecked) - // if chkReqPayment is not active, don't display lnReqAmount as invalid - ui->lnReqAmount->setValid(true); - - genCode(); -} - -void QRCodeDialog::updateDisplayUnit() -{ - if (model) - { - // Update lnReqAmount with the current unit - ui->lnReqAmount->setDisplayUnit(model->getDisplayUnit()); - } -} diff --git a/src/qt/qrcodedialog.h b/src/qt/qrcodedialog.h deleted file mode 100644 index c55c34bce6..0000000000 --- a/src/qt/qrcodedialog.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef QRCODEDIALOG_H -#define QRCODEDIALOG_H - -#include <QDialog> -#include <QImage> - -namespace Ui { - class QRCodeDialog; -} -class OptionsModel; - -class QRCodeDialog : public QDialog -{ - Q_OBJECT - -public: - explicit QRCodeDialog(const QString &addr, const QString &label, bool enableReq, QWidget *parent = 0); - ~QRCodeDialog(); - - void setModel(OptionsModel *model); - -private slots: - void on_lnReqAmount_textChanged(); - void on_lnLabel_textChanged(); - void on_lnMessage_textChanged(); - void on_btnSaveAs_clicked(); - void on_chkReqPayment_toggled(bool fChecked); - - void updateDisplayUnit(); - -private: - Ui::QRCodeDialog *ui; - OptionsModel *model; - QString address; - QImage myImage; - - void genCode(); - QString getURI(); -}; - -#endif // QRCODEDIALOG_H diff --git a/src/qt/receivecoinsdialog.cpp b/src/qt/receivecoinsdialog.cpp new file mode 100644 index 0000000000..f3ab343fea --- /dev/null +++ b/src/qt/receivecoinsdialog.cpp @@ -0,0 +1,107 @@ +#include "receivecoinsdialog.h" +#include "ui_receivecoinsdialog.h" + +#include "walletmodel.h" +#include "bitcoinunits.h" +#include "addressbookpage.h" +#include "optionsmodel.h" +#include "guiutil.h" +#include "receiverequestdialog.h" +#include "addresstablemodel.h" + +#include <QMessageBox> +#include <QTextDocument> +#include <QScrollBar> + +ReceiveCoinsDialog::ReceiveCoinsDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::ReceiveCoinsDialog), + model(0) +{ + ui->setupUi(this); + +#ifdef Q_OS_MAC // Icons on push buttons are very uncommon on Mac + ui->clearButton->setIcon(QIcon()); + ui->receiveButton->setIcon(QIcon()); +#endif + connect(ui->clearButton, SIGNAL(clicked()), this, SLOT(clear())); +} + +void ReceiveCoinsDialog::setModel(WalletModel *model) +{ + this->model = model; + + if(model && model->getOptionsModel()) + { + connect(model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit())); + updateDisplayUnit(); + } +} + +ReceiveCoinsDialog::~ReceiveCoinsDialog() +{ + delete ui; +} + +void ReceiveCoinsDialog::clear() +{ + ui->reqAmount->clear(); + ui->reqLabel->setText(""); + ui->reqMessage->setText(""); + ui->reuseAddress->setChecked(false); + updateDisplayUnit(); +} + +void ReceiveCoinsDialog::reject() +{ + clear(); +} + +void ReceiveCoinsDialog::accept() +{ + clear(); +} + +void ReceiveCoinsDialog::updateDisplayUnit() +{ + if(model && model->getOptionsModel()) + { + ui->reqAmount->setDisplayUnit(model->getOptionsModel()->getDisplayUnit()); + } +} + +void ReceiveCoinsDialog::on_receiveButton_clicked() +{ + if(!model || !model->getOptionsModel() || !model->getAddressTableModel()) + return; + + QString address; + QString label = ui->reqLabel->text(); + if(ui->reuseAddress->isChecked()) + { + /* Choose existing receiving address */ + AddressBookPage dlg(AddressBookPage::ForSelection, AddressBookPage::ReceivingTab, this); + dlg.setModel(model->getAddressTableModel()); + if(dlg.exec()) + { + address = dlg.getReturnValue(); + if(label.isEmpty()) /* If no label provided, use the previously used label */ + { + label = model->getAddressTableModel()->labelForAddress(address); + } + } else { + return; + } + } else { + /* Generate new receiving address */ + address = model->getAddressTableModel()->addRow(AddressTableModel::Receive, label, ""); + } + SendCoinsRecipient info(address, label, + ui->reqAmount->value(), ui->reqMessage->text()); + ReceiveRequestDialog *dialog = new ReceiveRequestDialog(this); + dialog->setModel(model->getOptionsModel()); + dialog->setInfo(info); + dialog->setAttribute(Qt::WA_DeleteOnClose); + dialog->show(); + clear(); +} diff --git a/src/qt/receivecoinsdialog.h b/src/qt/receivecoinsdialog.h new file mode 100644 index 0000000000..8d12e55afe --- /dev/null +++ b/src/qt/receivecoinsdialog.h @@ -0,0 +1,38 @@ +#ifndef RECEIVECOINSDIALOG_H +#define RECEIVECOINSDIALOG_H + +#include <QDialog> +#include <QVariant> + +namespace Ui { + class ReceiveCoinsDialog; +} +class WalletModel; +class OptionsModel; + +/** Dialog for requesting payment of bitcoins */ +class ReceiveCoinsDialog : public QDialog +{ + Q_OBJECT + +public: + explicit ReceiveCoinsDialog(QWidget *parent = 0); + ~ReceiveCoinsDialog(); + + void setModel(WalletModel *model); + +public slots: + void clear(); + void reject(); + void accept(); + +private: + Ui::ReceiveCoinsDialog *ui; + WalletModel *model; + +private slots: + void on_receiveButton_clicked(); + void updateDisplayUnit(); +}; + +#endif // RECEIVECOINSDIALOG_H diff --git a/src/qt/receiverequestdialog.cpp b/src/qt/receiverequestdialog.cpp new file mode 100644 index 0000000000..896acfd233 --- /dev/null +++ b/src/qt/receiverequestdialog.cpp @@ -0,0 +1,185 @@ +#include "receiverequestdialog.h" +#include "ui_receiverequestdialog.h" + +#include "bitcoinunits.h" +#include "guiconstants.h" +#include "guiutil.h" +#include "optionsmodel.h" +#include "walletmodel.h" + +#include <QPixmap> +#include <QClipboard> +#include <QMouseEvent> +#include <QDrag> +#include <QMimeData> +#if QT_VERSION < 0x050000 +#include <QUrl> +#endif + +#if defined(HAVE_CONFIG_H) +#include "bitcoin-config.h" /* for USE_QRCODE */ +#endif + +#ifdef USE_QRCODE +#include <qrencode.h> +#endif + +QRImageWidget::QRImageWidget(QWidget *parent): + QLabel(parent) +{ + setContextMenuPolicy(Qt::ActionsContextMenu); + + QAction *saveImageAction = new QAction(tr("&Save Image..."), this); + connect(saveImageAction, SIGNAL(triggered()), this, SLOT(saveImage())); + addAction(saveImageAction); + QAction *copyImageAction = new QAction(tr("&Copy Image"), this); + connect(copyImageAction, SIGNAL(triggered()), this, SLOT(copyImage())); + addAction(copyImageAction); +} + +QImage QRImageWidget::exportImage() +{ + return pixmap()->toImage().scaled(EXPORT_IMAGE_SIZE, EXPORT_IMAGE_SIZE); +} + +void QRImageWidget::mousePressEvent(QMouseEvent *event) +{ + if(event->button() == Qt::LeftButton) + { + event->accept(); + QMimeData *mimeData = new QMimeData; + mimeData->setImageData(exportImage()); + + QDrag *drag = new QDrag(this); + drag->setMimeData(mimeData); + drag->exec(); + } else { + QLabel::mousePressEvent(event); + } +} + +void QRImageWidget::saveImage() +{ + QString fn = GUIUtil::getSaveFileName(this, tr("Save QR Code"), QString(), tr("PNG Images (*.png)")); + if (!fn.isEmpty()) + { + exportImage().save(fn); + } +} + +void QRImageWidget::copyImage() +{ + QApplication::clipboard()->setImage(exportImage()); +} + +ReceiveRequestDialog::ReceiveRequestDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::ReceiveRequestDialog), + model(0) +{ + ui->setupUi(this); + +#ifndef USE_QRCODE + ui->btnSaveAs->setVisible(false); + ui->btnCopyImage->setVisible(false); + ui->lblQRCode->setVisible(false); +#endif + + connect(ui->btnSaveAs, SIGNAL(clicked()), ui->lblQRCode, SLOT(saveImage())); + connect(ui->btnCopyImage, SIGNAL(clicked()), ui->lblQRCode, SLOT(copyImage())); +} + +ReceiveRequestDialog::~ReceiveRequestDialog() +{ + delete ui; +} + +void ReceiveRequestDialog::setModel(OptionsModel *model) +{ + this->model = model; + + if (model) + connect(model, SIGNAL(displayUnitChanged(int)), this, SLOT(update())); + + // update the display unit if necessary + update(); +} + +void ReceiveRequestDialog::setInfo(const SendCoinsRecipient &info) +{ + this->info = info; + update(); +} + +void ReceiveRequestDialog::update() +{ + if(!model) + return; + QString target = info.label; + if(target.isEmpty()) + target = info.address; + setWindowTitle(tr("Request payment to %1").arg(target)); + + QString uri = GUIUtil::formatBitcoinURI(info); + ui->btnSaveAs->setEnabled(false); + QString html; + html += "<html><font face='verdana, arial, helvetica, sans-serif'>"; + html += "<b>"+tr("Payment information")+"</b><br>"; + html += "<b>"+tr("URI")+"</b>: "; + html += "<a href=\""+uri+"\">" + GUIUtil::HtmlEscape(uri) + "</a><br>"; + html += "<b>"+tr("Address")+"</b>: " + GUIUtil::HtmlEscape(info.address) + "<br>"; + if(info.amount) + html += "<b>"+tr("Amount")+"</b>: " + BitcoinUnits::formatWithUnit(model->getDisplayUnit(), info.amount) + "<br>"; + if(!info.label.isEmpty()) + html += "<b>"+tr("Label")+"</b>: " + GUIUtil::HtmlEscape(info.label) + "<br>"; + if(!info.message.isEmpty()) + html += "<b>"+tr("Message")+"</b>: " + GUIUtil::HtmlEscape(info.message) + "<br>"; + ui->outUri->setText(html); + +#ifdef USE_QRCODE + ui->lblQRCode->setText(""); + if(!uri.isEmpty()) + { + // limit URI length + if (uri.length() > MAX_URI_LENGTH) + { + ui->lblQRCode->setText(tr("Resulting URI too long, try to reduce the text for label / message.")); + } else { + QRcode *code = QRcode_encodeString(uri.toUtf8().constData(), 0, QR_ECLEVEL_L, QR_MODE_8, 1); + if (!code) + { + ui->lblQRCode->setText(tr("Error encoding URI into QR Code.")); + return; + } + QImage myImage = QImage(code->width + 8, code->width + 8, QImage::Format_RGB32); + myImage.fill(0xffffff); + unsigned char *p = code->data; + for (int y = 0; y < code->width; y++) + { + for (int x = 0; x < code->width; x++) + { + myImage.setPixel(x + 4, y + 4, ((*p & 1) ? 0x0 : 0xffffff)); + p++; + } + } + QRcode_free(code); + + ui->lblQRCode->setPixmap(QPixmap::fromImage(myImage).scaled(300, 300)); + ui->btnSaveAs->setEnabled(true); + } + } +#endif +} + +void ReceiveRequestDialog::on_btnCopyURI_clicked() +{ + QString uri = GUIUtil::formatBitcoinURI(info); + QApplication::clipboard()->setText(uri, QClipboard::Clipboard); + QApplication::clipboard()->setText(uri, QClipboard::Selection); +} + +void ReceiveRequestDialog::on_btnCopyAddress_clicked() +{ + QApplication::clipboard()->setText(info.address, QClipboard::Clipboard); + QApplication::clipboard()->setText(info.address, QClipboard::Selection); +} diff --git a/src/qt/receiverequestdialog.h b/src/qt/receiverequestdialog.h new file mode 100644 index 0000000000..1beb873dfd --- /dev/null +++ b/src/qt/receiverequestdialog.h @@ -0,0 +1,57 @@ +#ifndef QRCODEDIALOG_H +#define QRCODEDIALOG_H + +#include "walletmodel.h" + +#include <QDialog> +#include <QImage> +#include <QLabel> + +namespace Ui { + class ReceiveRequestDialog; +} +class OptionsModel; + +/* Label widget for QR code. This image can be dragged, dropped, copied and saved + * to disk. + */ +class QRImageWidget : public QLabel +{ + Q_OBJECT + +public: + explicit QRImageWidget(QWidget *parent = 0); + QImage exportImage(); + +public slots: + void saveImage(); + void copyImage(); + +protected: + virtual void mousePressEvent(QMouseEvent *event); +}; + +class ReceiveRequestDialog : public QDialog +{ + Q_OBJECT + +public: + explicit ReceiveRequestDialog(QWidget *parent = 0); + ~ReceiveRequestDialog(); + + void setModel(OptionsModel *model); + void setInfo(const SendCoinsRecipient &info); + +private slots: + void on_btnCopyURI_clicked(); + void on_btnCopyAddress_clicked(); + + void update(); + +private: + Ui::ReceiveRequestDialog *ui; + OptionsModel *model; + SendCoinsRecipient info; +}; + +#endif // QRCODEDIALOG_H diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index e31310c2b6..e7dcdf62a1 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -159,7 +159,7 @@ void RPCExecutor::request(const QString &command) else if (result.type() == json_spirit::str_type) strPrint = result.get_str(); else - strPrint = write_string(result, json_spirit::pretty_print | json_spirit::raw_utf8); + strPrint = write_string(result, true); emit reply(RPCConsole::CMD_REPLY, QString::fromStdString(strPrint)); } @@ -173,7 +173,7 @@ void RPCExecutor::request(const QString &command) } catch(std::runtime_error &) // raised when converting to invalid type, i.e. missing code or message { // Show raw JSON object - emit reply(RPCConsole::CMD_ERROR, QString::fromStdString(write_string(json_spirit::Value(objError), json_spirit::raw_utf8))); + emit reply(RPCConsole::CMD_ERROR, QString::fromStdString(write_string(json_spirit::Value(objError), false))); } } catch (std::exception& e) diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index 3fd4a26e76..51304bc05c 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -1,14 +1,13 @@ #include "sendcoinsdialog.h" #include "ui_sendcoinsdialog.h" -#include "walletmodel.h" #include "bitcoinunits.h" -#include "addressbookpage.h" #include "optionsmodel.h" #include "sendcoinsentry.h" #include "guiutil.h" #include "askpassphrasedialog.h" #include "base58.h" +#include "ui_interface.h" #include <QMessageBox> #include <QTextDocument> @@ -137,41 +136,9 @@ void SendCoinsDialog::on_sendButton_clicked() // prepare transaction for getting txFee earlier WalletModelTransaction currentTransaction(recipients); WalletModel::SendCoinsReturn prepareStatus = model->prepareTransaction(currentTransaction); - - QString strSendCoins = tr("Send Coins"); - switch(prepareStatus.status) - { - case WalletModel::InvalidAddress: - QMessageBox::warning(this, strSendCoins, - tr("The recipient address is not valid, please recheck.")); - break; - case WalletModel::InvalidAmount: - QMessageBox::warning(this, strSendCoins, - tr("The amount to pay must be larger than 0.")); - break; - case WalletModel::AmountExceedsBalance: - QMessageBox::warning(this, strSendCoins, - tr("The amount exceeds your balance.")); - break; - case WalletModel::AmountWithFeeExceedsBalance: - QMessageBox::warning(this, strSendCoins, - tr("The total exceeds your balance when the %1 transaction fee is included."). - arg(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), currentTransaction.getTransactionFee()))); - break; - case WalletModel::DuplicateAddress: - QMessageBox::warning(this, strSendCoins, - tr("Duplicate address found, can only send to each address once per send operation.")); - break; - case WalletModel::TransactionCreationFailed: - QMessageBox::warning(this, strSendCoins, - tr("Error: Transaction creation failed!")); - break; - case WalletModel::TransactionCommitFailed: - case WalletModel::OK: - case WalletModel::Aborted: // User aborted, nothing to do - default: - break; - } + // process prepareStatus and on error generate message shown to user + processSendCoinsReturn(prepareStatus, + BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), currentTransaction.getTransactionFee())); if(prepareStatus.status != WalletModel::OK) { fNewRecipientAllowed = true; @@ -209,19 +176,13 @@ void SendCoinsDialog::on_sendButton_clicked() } // now send the prepared transaction - WalletModel::SendCoinsReturn sendstatus = model->sendCoins(currentTransaction); - switch(sendstatus.status) + WalletModel::SendCoinsReturn sendStatus = model->sendCoins(currentTransaction); + // process sendStatus and on error generate message shown to user + processSendCoinsReturn(sendStatus); + + if (sendStatus.status == WalletModel::OK) { - case WalletModel::TransactionCommitFailed: - QMessageBox::warning(this, strSendCoins, - tr("Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here.")); - break; - case WalletModel::OK: accept(); - break; - case WalletModel::Aborted: // User aborted, nothing to do - default: - break; } fNewRecipientAllowed = true; } @@ -357,16 +318,16 @@ bool SendCoinsDialog::handlePaymentRequest(const SendCoinsRecipient &rv) const payments::PaymentDetails& details = rv.paymentRequest.getDetails(); if (details.has_expires() && (int64)details.expires() < GetTime()) { - QMessageBox::warning(this, strSendCoins, - tr("Payment request expired")); + emit message(strSendCoins, tr("Payment request expired"), + CClientUIInterface::MSG_WARNING); return false; } } else { CBitcoinAddress address(rv.address.toStdString()); if (!address.IsValid()) { - QMessageBox::warning(this, strSendCoins, - tr("Invalid payment address %1").arg(rv.address)); + emit message(strSendCoins, tr("Invalid payment address %1").arg(rv.address), + CClientUIInterface::MSG_WARNING); return false; } } @@ -390,3 +351,47 @@ void SendCoinsDialog::updateDisplayUnit() { setBalance(model->getBalance(), 0, 0); } + +void SendCoinsDialog::processSendCoinsReturn(const WalletModel::SendCoinsReturn &sendCoinsReturn, const QString &msgArg) +{ + QPair<QString, CClientUIInterface::MessageBoxFlags> msgParams; + // Default to a warning message, override if error message is needed + msgParams.second = CClientUIInterface::MSG_WARNING; + + // This comment is specific to SendCoinsDialog usage of WalletModel::SendCoinsReturn. + // WalletModel::TransactionCommitFailed is used only in WalletModel::sendCoins() + // all others are used only in WalletModel::prepareTransaction() + switch(sendCoinsReturn.status) + { + case WalletModel::InvalidAddress: + msgParams.first = tr("The recipient address is not valid, please recheck."); + break; + case WalletModel::InvalidAmount: + msgParams.first = tr("The amount to pay must be larger than 0."); + break; + case WalletModel::AmountExceedsBalance: + msgParams.first = tr("The amount exceeds your balance."); + break; + case WalletModel::AmountWithFeeExceedsBalance: + msgParams.first = tr("The total exceeds your balance when the %1 transaction fee is included.").arg(msgArg); + break; + case WalletModel::DuplicateAddress: + msgParams.first = tr("Duplicate address found, can only send to each address once per send operation."); + break; + case WalletModel::TransactionCreationFailed: + msgParams.first = tr("Transaction creation failed!"); + msgParams.second = CClientUIInterface::MSG_ERROR; + break; + case WalletModel::TransactionCommitFailed: + msgParams.first = tr("The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here."); + msgParams.second = CClientUIInterface::MSG_ERROR; + break; + // OK and Aborted are included to prevent a compiler warning. + case WalletModel::OK: + case WalletModel::Aborted: + default: + return; + } + + emit message(tr("Send Coins"), msgParams.first, msgParams.second); +} diff --git a/src/qt/sendcoinsdialog.h b/src/qt/sendcoinsdialog.h index f4bffedc9b..4e68e26731 100644 --- a/src/qt/sendcoinsdialog.h +++ b/src/qt/sendcoinsdialog.h @@ -1,16 +1,17 @@ #ifndef SENDCOINSDIALOG_H #define SENDCOINSDIALOG_H +#include "walletmodel.h" + #include <QDialog> #include <QVariant> +#include <QPair> namespace Ui { class SendCoinsDialog; } -class WalletModel; class SendCoinsEntry; class SendCoinsRecipient; -class OptionsModel; QT_BEGIN_NAMESPACE class QUrl; @@ -48,10 +49,19 @@ private: WalletModel *model; bool fNewRecipientAllowed; + // Process WalletModel::SendCoinsReturn and generate a pair consisting + // of a message and message flags for use in emit message(). + // Additional parameter msgArg can be used via .arg(msgArg). + void processSendCoinsReturn(const WalletModel::SendCoinsReturn &sendCoinsReturn, const QString &msgArg = QString()); + private slots: void on_sendButton_clicked(); void removeEntry(SendCoinsEntry* entry); void updateDisplayUnit(); + +signals: + // Fired when a message should be reported to the user + void message(const QString &title, const QString &message, unsigned int style); }; #endif // SENDCOINSDIALOG_H diff --git a/src/qt/sendcoinsentry.cpp b/src/qt/sendcoinsentry.cpp index 188b8860a9..2d42ecb568 100644 --- a/src/qt/sendcoinsentry.cpp +++ b/src/qt/sendcoinsentry.cpp @@ -49,7 +49,7 @@ void SendCoinsEntry::on_addressBookButton_clicked() { if(!model) return; - AddressBookPage dlg(AddressBookPage::ForSending, AddressBookPage::SendingTab, this); + AddressBookPage dlg(AddressBookPage::ForSelection, AddressBookPage::SendingTab, this); dlg.setModel(model->getAddressTableModel()); if(dlg.exec()) { diff --git a/src/qt/signverifymessagedialog.cpp b/src/qt/signverifymessagedialog.cpp index 1e9c84fe1a..ff3d00b326 100644 --- a/src/qt/signverifymessagedialog.cpp +++ b/src/qt/signverifymessagedialog.cpp @@ -86,7 +86,7 @@ void SignVerifyMessageDialog::on_addressBookButton_SM_clicked() { if (model && model->getAddressTableModel()) { - AddressBookPage dlg(AddressBookPage::ForSending, AddressBookPage::ReceivingTab, this); + AddressBookPage dlg(AddressBookPage::ForSelection, AddressBookPage::ReceivingTab, this); dlg.setModel(model->getAddressTableModel()); if (dlg.exec()) { @@ -178,7 +178,7 @@ void SignVerifyMessageDialog::on_addressBookButton_VM_clicked() { if (model && model->getAddressTableModel()) { - AddressBookPage dlg(AddressBookPage::ForSending, AddressBookPage::SendingTab, this); + AddressBookPage dlg(AddressBookPage::ForSelection, AddressBookPage::SendingTab, this); dlg.setModel(model->getAddressTableModel()); if (dlg.exec()) { diff --git a/src/qt/test/uritests.cpp b/src/qt/test/uritests.cpp index 802d74719e..df4df3154b 100644 --- a/src/qt/test/uritests.cpp +++ b/src/qt/test/uritests.cpp @@ -50,9 +50,8 @@ void URITests::uriTests() QVERIFY(rv.address == QString("175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W")); QVERIFY(rv.label == QString()); - // We currently don't implement the message parameter (ok, yea, we break spec...) uri.setUrl(QString("bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?req-message=Wikipedia Example Address")); - QVERIFY(!GUIUtil::parseBitcoinURI(uri, &rv)); + QVERIFY(GUIUtil::parseBitcoinURI(uri, &rv)); uri.setUrl(QString("bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?amount=1,000&label=Wikipedia Example")); QVERIFY(!GUIUtil::parseBitcoinURI(uri, &rv)); diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp index 93fc8cab22..63a72c4553 100644 --- a/src/qt/transactiondesc.cpp +++ b/src/qt/transactiondesc.cpp @@ -234,7 +234,10 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, int vout, int u } if (wtx.IsCoinBase()) - strHTML += "<br>" + tr("Generated coins must mature 120 blocks before they can be spent. When you generated this block, it was broadcast to the network to be added to the block chain. If it fails to get into the chain, its state will change to \"not accepted\" and it won't be spendable. This may occasionally happen if another node generates a block within a few seconds of yours.") + "<br>"; + { + quint32 numBlocksToMaturity = COINBASE_MATURITY + 1; + strHTML += "<br>" + tr("Generated coins must mature %1 blocks before they can be spent. When you generated this block, it was broadcast to the network to be added to the block chain. If it fails to get into the chain, its state will change to \"not accepted\" and it won't be spendable. This may occasionally happen if another node generates a block within a few seconds of yours.").arg(QString::number(numBlocksToMaturity)) + "<br>"; + } // // Debug view diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp index a43e29c476..89ecf99656 100644 --- a/src/qt/transactionview.cpp +++ b/src/qt/transactionview.cpp @@ -11,6 +11,7 @@ #include "editaddressdialog.h" #include "optionsmodel.h" #include "guiutil.h" +#include "ui_interface.h" #include <QScrollBar> #include <QComboBox> @@ -20,7 +21,6 @@ #include <QLineEdit> #include <QTableView> #include <QHeaderView> -#include <QMessageBox> #include <QPoint> #include <QMenu> #include <QLabel> @@ -266,12 +266,12 @@ void TransactionView::changedAmount(const QString &amount) void TransactionView::exportClicked() { // CSV is currently the only supported format - QString filename = GUIUtil::getSaveFileName( - this, - tr("Export Transaction Data"), QString(), - tr("Comma separated file (*.csv)")); + QString filename = GUIUtil::getSaveFileName(this, + tr("Export Transaction History"), QString(), + tr("Comma separated file (*.csv)")); - if (filename.isNull()) return; + if (filename.isNull()) + return; CSVModelWriter writer(filename); @@ -285,10 +285,13 @@ void TransactionView::exportClicked() writer.addColumn(tr("Amount"), 0, TransactionTableModel::FormattedAmountRole); writer.addColumn(tr("ID"), 0, TransactionTableModel::TxIDRole); - if(!writer.write()) - { - QMessageBox::critical(this, tr("Error exporting"), tr("Could not write to file %1.").arg(filename), - QMessageBox::Abort, QMessageBox::Abort); + if(!writer.write()) { + emit message(tr("Exporting Failed"), tr("There was an error trying to save the transaction history to %1.").arg(filename), + CClientUIInterface::MSG_ERROR); + } + else { + emit message(tr("Exporting Successful"), tr("The transaction history was successfully saved to %1.").arg(filename), + CClientUIInterface::MSG_INFORMATION); } } diff --git a/src/qt/transactionview.h b/src/qt/transactionview.h index bb41a83e32..464ba3e8ce 100644 --- a/src/qt/transactionview.h +++ b/src/qt/transactionview.h @@ -71,6 +71,9 @@ private slots: signals: void doubleClicked(const QModelIndex&); + /** Fired when a message should be reported to the user */ + void message(const QString &title, const QString &message, unsigned int style); + public slots: void chooseDate(int idx); void chooseType(int idx); diff --git a/src/qt/walletframe.cpp b/src/qt/walletframe.cpp index f754bd5e71..d2807f465a 100644 --- a/src/qt/walletframe.cpp +++ b/src/qt/walletframe.cpp @@ -62,7 +62,7 @@ bool WalletFrame::setCurrentWallet(const QString& name) WalletView *walletView = mapWalletViews.value(name); walletStack->setCurrentWidget(walletView); - walletView->setEncryptionStatus(); + walletView->updateEncryptionStatus(); return true; } @@ -115,13 +115,6 @@ void WalletFrame::gotoHistoryPage() i.value()->gotoHistoryPage(); } -void WalletFrame::gotoAddressBookPage() -{ - QMap<QString, WalletView*>::const_iterator i; - for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i) - i.value()->gotoAddressBookPage(); -} - void WalletFrame::gotoReceiveCoinsPage() { QMap<QString, WalletView*>::const_iterator i; @@ -178,9 +171,16 @@ void WalletFrame::unlockWallet() walletView->unlockWallet(); } -void WalletFrame::setEncryptionStatus() +void WalletFrame::usedSendingAddresses() +{ + WalletView *walletView = (WalletView*)walletStack->currentWidget(); + if (walletView) + walletView->usedSendingAddresses(); +} + +void WalletFrame::usedReceivingAddresses() { WalletView *walletView = (WalletView*)walletStack->currentWidget(); if (walletView) - walletView->setEncryptionStatus(); + walletView->usedReceivingAddresses(); } diff --git a/src/qt/walletframe.h b/src/qt/walletframe.h index 5011987963..edf2390dbc 100644 --- a/src/qt/walletframe.h +++ b/src/qt/walletframe.h @@ -52,8 +52,6 @@ public slots: void gotoOverviewPage(); /** Switch to history (transactions) page */ void gotoHistoryPage(); - /** Switch to address book page */ - void gotoAddressBookPage(); /** Switch to receive coins page */ void gotoReceiveCoinsPage(); /** Switch to send coins page */ @@ -73,11 +71,10 @@ public slots: /** Ask for passphrase to unlock wallet temporarily */ void unlockWallet(); - /** Set the encryption status as shown in the UI. - @param[in] status current encryption status - @see WalletModel::EncryptionStatus - */ - void setEncryptionStatus(); + /** Show used sending addresses */ + void usedSendingAddresses(); + /** Show used receiving addresses */ + void usedReceivingAddresses(); }; #endif // WALLETFRAME_H diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h index 6abcdaf8cb..2e99eaddcb 100644 --- a/src/qt/walletmodel.h +++ b/src/qt/walletmodel.h @@ -21,11 +21,14 @@ QT_END_NAMESPACE class SendCoinsRecipient { public: - SendCoinsRecipient() : amount(0) { } + explicit SendCoinsRecipient() : amount(0) { } + explicit SendCoinsRecipient(const QString &addr, const QString &label, quint64 amount, const QString &message): + address(addr), label(label), amount(amount), message(message) {} QString address; QString label; qint64 amount; + QString message; // If from a payment request, paymentRequest.IsInitialized() will be true PaymentRequestPlus paymentRequest; diff --git a/src/qt/walletview.cpp b/src/qt/walletview.cpp index d7cef971ed..d1e5e47bd5 100644 --- a/src/qt/walletview.cpp +++ b/src/qt/walletview.cpp @@ -9,6 +9,7 @@ #include "transactiontablemodel.h" #include "addressbookpage.h" #include "sendcoinsdialog.h" +#include "receivecoinsdialog.h" #include "signverifymessagedialog.h" #include "clientmodel.h" #include "walletmodel.h" @@ -17,21 +18,15 @@ #include "overviewpage.h" #include "askpassphrasedialog.h" #include "ui_interface.h" +#include "guiutil.h" #include <QHBoxLayout> #include <QVBoxLayout> #include <QAction> -#if QT_VERSION < 0x050000 -#include <QDesktopServices> -#else -#include <QStandardPaths> -#endif -#include <QFileDialog> #include <QPushButton> WalletView::WalletView(QWidget *parent): QStackedWidget(parent), - gui(0), clientModel(0), walletModel(0) { @@ -53,30 +48,27 @@ WalletView::WalletView(QWidget *parent): vbox->addLayout(hbox_buttons); transactionsPage->setLayout(vbox); - addressBookPage = new AddressBookPage(AddressBookPage::ForEditing, AddressBookPage::SendingTab); - receiveCoinsPage = new AddressBookPage(AddressBookPage::ForEditing, AddressBookPage::ReceivingTab); + receiveCoinsPage = new ReceiveCoinsDialog(); sendCoinsPage = new SendCoinsDialog(); addWidget(overviewPage); addWidget(transactionsPage); - addWidget(addressBookPage); addWidget(receiveCoinsPage); addWidget(sendCoinsPage); - // Clicking on a transaction on the overview page simply sends you to transaction history page + // Clicking on a transaction on the overview pre-selects the transaction on the transaction history page connect(overviewPage, SIGNAL(transactionClicked(QModelIndex)), transactionView, SLOT(focusTransaction(QModelIndex))); // Double-clicking on a transaction on the transaction history page shows details connect(transactionView, SIGNAL(doubleClicked(QModelIndex)), transactionView, SLOT(showDetails())); - // Clicking on "Send Coins" in the address book sends you to the send coins tab - connect(addressBookPage, SIGNAL(sendCoins(QString)), this, SLOT(gotoSendCoinsPage(QString))); - // Clicking on "Verify Message" in the address book opens the verify message tab in the Sign/Verify Message dialog - connect(addressBookPage, SIGNAL(verifyMessage(QString)), this, SLOT(gotoVerifyMessageTab(QString))); - // Clicking on "Sign Message" in the receive coins page opens the sign message tab in the Sign/Verify Message dialog - connect(receiveCoinsPage, SIGNAL(signMessage(QString)), this, SLOT(gotoSignMessageTab(QString))); // Clicking on "Export" allows to export the transaction list connect(exportButton, SIGNAL(clicked()), transactionView, SLOT(exportClicked())); + + // Pass through messages from sendCoinsPage + connect(sendCoinsPage, SIGNAL(message(QString,QString,unsigned int)), this, SIGNAL(message(QString,QString,unsigned int))); + // Pass through messages from transactionView + connect(transactionView, SIGNAL(message(QString,QString,unsigned int)), this, SIGNAL(message(QString,QString,unsigned int))); } WalletView::~WalletView() @@ -85,52 +77,58 @@ WalletView::~WalletView() void WalletView::setBitcoinGUI(BitcoinGUI *gui) { - this->gui = gui; - if(gui) + if (gui) { + // Clicking on a transaction on the overview page simply sends you to transaction history page connect(overviewPage, SIGNAL(transactionClicked(QModelIndex)), gui, SLOT(gotoHistoryPage())); + + // Receive and report messages + connect(this, SIGNAL(message(QString,QString,unsigned int)), gui, SLOT(message(QString,QString,unsigned int))); + + // Pass through encryption status changed signals + connect(this, SIGNAL(encryptionStatusChanged(int)), gui, SLOT(setEncryptionStatus(int))); + + // Pass through transaction notifications + connect(this, SIGNAL(incomingTransaction(QString,int,qint64,QString,QString)), gui, SLOT(incomingTransaction(QString,int,qint64,QString,QString))); } } void WalletView::setClientModel(ClientModel *clientModel) { this->clientModel = clientModel; - if (clientModel) - { - overviewPage->setClientModel(clientModel); - addressBookPage->setOptionsModel(clientModel->getOptionsModel()); - receiveCoinsPage->setOptionsModel(clientModel->getOptionsModel()); - } + + overviewPage->setClientModel(clientModel); } void WalletView::setWalletModel(WalletModel *walletModel) { this->walletModel = walletModel; - if (walletModel && gui) - { - // Receive and report messages from wallet thread - connect(walletModel, SIGNAL(message(QString,QString,unsigned int)), gui, SLOT(message(QString,QString,unsigned int))); - // Put transaction list in tabs - transactionView->setModel(walletModel); - overviewPage->setWalletModel(walletModel); - addressBookPage->setModel(walletModel->getAddressTableModel()); - receiveCoinsPage->setModel(walletModel->getAddressTableModel()); - sendCoinsPage->setModel(walletModel); + // Put transaction list in tabs + transactionView->setModel(walletModel); + overviewPage->setWalletModel(walletModel); + receiveCoinsPage->setModel(walletModel); + sendCoinsPage->setModel(walletModel); + + if (walletModel) + { + // Receive and pass through messages from wallet model + connect(walletModel, SIGNAL(message(QString,QString,unsigned int)), this, SIGNAL(message(QString,QString,unsigned int))); - setEncryptionStatus(); - connect(walletModel, SIGNAL(encryptionStatusChanged(int)), gui, SLOT(setEncryptionStatus(int))); + // Handle changes in encryption status + connect(walletModel, SIGNAL(encryptionStatusChanged(int)), this, SIGNAL(encryptionStatusChanged(int))); + updateEncryptionStatus(); // Balloon pop-up for new transaction connect(walletModel->getTransactionTableModel(), SIGNAL(rowsInserted(QModelIndex,int,int)), - this, SLOT(incomingTransaction(QModelIndex,int,int))); + this, SLOT(processNewTransaction(QModelIndex,int,int))); // Ask for passphrase if needed connect(walletModel, SIGNAL(requireUnlock()), this, SLOT(unlockWallet())); } } -void WalletView::incomingTransaction(const QModelIndex& parent, int start, int /*end*/) +void WalletView::processNewTransaction(const QModelIndex& parent, int start, int /*end*/) { // Prevent balloon-spam when initial block download is in progress if (!walletModel || !clientModel || clientModel->inInitialBlockDownload()) @@ -143,7 +141,7 @@ void WalletView::incomingTransaction(const QModelIndex& parent, int start, int / QString type = ttm->index(start, TransactionTableModel::Type, parent).data().toString(); QString address = ttm->index(start, TransactionTableModel::ToAddress, parent).data().toString(); - gui->incomingTransaction(date, walletModel->getOptionsModel()->getDisplayUnit(), amount, type, address); + emit incomingTransaction(date, walletModel->getOptionsModel()->getDisplayUnit(), amount, type, address); } void WalletView::gotoOverviewPage() @@ -156,11 +154,6 @@ void WalletView::gotoHistoryPage() setCurrentWidget(transactionsPage); } -void WalletView::gotoAddressBookPage() -{ - setCurrentWidget(addressBookPage); -} - void WalletView::gotoReceiveCoinsPage() { setCurrentWidget(receiveCoinsPage); @@ -200,15 +193,7 @@ void WalletView::gotoVerifyMessageTab(QString addr) bool WalletView::handlePaymentRequest(const SendCoinsRecipient& recipient) { - // URI has to be valid - if (sendCoinsPage->handlePaymentRequest(recipient)) - { - gotoSendCoinsPage(); - emit showNormalIfMinimized(); - return true; - } - else - return false; + return sendCoinsPage->handlePaymentRequest(recipient); } void WalletView::showOutOfSyncWarning(bool fShow) @@ -216,9 +201,9 @@ void WalletView::showOutOfSyncWarning(bool fShow) overviewPage->showOutOfSyncWarning(fShow); } -void WalletView::setEncryptionStatus() +void WalletView::updateEncryptionStatus() { - gui->setEncryptionStatus(walletModel->getEncryptionStatus()); + emit encryptionStatusChanged(walletModel->getEncryptionStatus()); } void WalletView::encryptWallet(bool status) @@ -229,25 +214,25 @@ void WalletView::encryptWallet(bool status) dlg.setModel(walletModel); dlg.exec(); - setEncryptionStatus(); + updateEncryptionStatus(); } void WalletView::backupWallet() { -#if QT_VERSION < 0x050000 - QString saveDir = QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation); -#else - QString saveDir = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation); -#endif - QString filename = QFileDialog::getSaveFileName(this, tr("Backup Wallet"), saveDir, tr("Wallet Data (*.dat)")); - if (!filename.isEmpty()) { - if (!walletModel->backupWallet(filename)) { - gui->message(tr("Backup Failed"), tr("There was an error trying to save the wallet data to the new location."), - CClientUIInterface::MSG_ERROR); + QString filename = GUIUtil::getSaveFileName(this, + tr("Backup Wallet"), QString(), + tr("Wallet Data (*.dat)")); + + if (filename.isEmpty()) + return; + + if (!walletModel->backupWallet(filename)) { + emit message(tr("Backup Failed"), tr("There was an error trying to save the wallet data to %1.").arg(filename), + CClientUIInterface::MSG_ERROR); } - else - gui->message(tr("Backup Successful"), tr("The wallet data was successfully saved to the new location."), - CClientUIInterface::MSG_INFORMATION); + else { + emit message(tr("Backup Successful"), tr("The wallet data was successfully saved to %1.").arg(filename), + CClientUIInterface::MSG_INFORMATION); } } @@ -270,3 +255,23 @@ void WalletView::unlockWallet() dlg.exec(); } } + +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->show(); +} + +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->show(); +} diff --git a/src/qt/walletview.h b/src/qt/walletview.h index e3ff253d3c..61515047ca 100644 --- a/src/qt/walletview.h +++ b/src/qt/walletview.h @@ -14,8 +14,8 @@ class ClientModel; class WalletModel; class TransactionView; class OverviewPage; -class AddressBookPage; class SendCoinsDialog; +class ReceiveCoinsDialog; class SendCoinsRecipient; class SignVerifyMessageDialog; class RPCConsole; @@ -55,14 +55,12 @@ public: void showOutOfSyncWarning(bool fShow); private: - BitcoinGUI *gui; ClientModel *clientModel; WalletModel *walletModel; OverviewPage *overviewPage; QWidget *transactionsPage; - AddressBookPage *addressBookPage; - AddressBookPage *receiveCoinsPage; + ReceiveCoinsDialog *receiveCoinsPage; SendCoinsDialog *sendCoinsPage; TransactionView *transactionView; @@ -72,8 +70,6 @@ public slots: void gotoOverviewPage(); /** Switch to history (transactions) page */ void gotoHistoryPage(); - /** Switch to address book page */ - void gotoAddressBookPage(); /** Switch to receive coins page */ void gotoReceiveCoinsPage(); /** Switch to send coins page */ @@ -88,7 +84,7 @@ public slots: The new items are those between start and end inclusive, under the given parent item. */ - void incomingTransaction(const QModelIndex& parent, int start, int /*end*/); + void processNewTransaction(const QModelIndex& parent, int start, int /*end*/); /** Encrypt the wallet */ void encryptWallet(bool status); /** Backup the wallet */ @@ -98,11 +94,22 @@ public slots: /** Ask for passphrase to unlock wallet temporarily */ void unlockWallet(); - void setEncryptionStatus(); + /** Show used sending addresses */ + void usedSendingAddresses(); + /** Show used receiving addresses */ + void usedReceivingAddresses(); + /** Re-emit encryption status signal */ + void updateEncryptionStatus(); signals: /** Signal that we want to show the main window */ void showNormalIfMinimized(); + /** Fired when a message should be reported to the user */ + void message(const QString &title, const QString &message, unsigned int style); + /** Encryption status of wallet changed */ + void encryptionStatusChanged(int status); + /** Notify that a new transaction appeared */ + void incomingTransaction(const QString& date, int unit, qint64 amount, const QString& type, const QString& address); }; #endif // WALLETVIEW_H diff --git a/src/rpcdump.cpp b/src/rpcdump.cpp index 3589b45900..a5f7a542de 100644 --- a/src/rpcdump.cpp +++ b/src/rpcdump.cpp @@ -6,6 +6,7 @@ #include <fstream> #include "init.h" // for pwalletMain +#include "wallet.h" #include "bitcoinrpc.h" #include "ui_interface.h" #include "base58.h" diff --git a/src/rpcnet.cpp b/src/rpcnet.cpp index 3c92739852..5d87a2449f 100644 --- a/src/rpcnet.cpp +++ b/src/rpcnet.cpp @@ -27,7 +27,7 @@ Value ping(const Array& params, bool fHelp) "Requests that a ping be sent to all other nodes, to measure ping time.\n" "Results provided in getpeerinfo, pingtime and pingwait fields are decimal seconds.\n" "Ping command is handled in queue with all other commands, so it measures processing backlog, not just network ping."); - + // Request that each node send a ping during next message processing pass LOCK(cs_vNodes); BOOST_FOREACH(CNode* pNode, vNodes) { @@ -120,13 +120,13 @@ Value addnode(const Array& params, bool fHelp) if (strCommand == "add") { if (it != vAddedNodes.end()) - throw JSONRPCError(-23, "Error: Node already added"); + throw JSONRPCError(RPC_CLIENT_NODE_ALREADY_ADDED, "Error: Node already added"); vAddedNodes.push_back(strNode); } else if(strCommand == "remove") { if (it == vAddedNodes.end()) - throw JSONRPCError(-24, "Error: Node has not been added."); + throw JSONRPCError(RPC_CLIENT_NODE_NOT_ADDED, "Error: Node has not been added."); vAddedNodes.erase(it); } @@ -163,7 +163,7 @@ Value getaddednodeinfo(const Array& params, bool fHelp) break; } if (laddedNodes.size() == 0) - throw JSONRPCError(-24, "Error: Node has not been added."); + throw JSONRPCError(RPC_CLIENT_NODE_NOT_ADDED, "Error: Node has not been added."); } if (!fDns) diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp index cb571947a9..49987ecc47 100644 --- a/src/rpcrawtransaction.cpp +++ b/src/rpcrawtransaction.cpp @@ -560,7 +560,7 @@ Value sendrawtransaction(const Array& params, bool fHelp) // Not in block, but already in the memory pool; will drop // through to re-relay it. } else { - SyncWithWallets(hashTx, tx, NULL, true); + SyncWithWallets(hashTx, tx, NULL); } RelayTransaction(tx, hashTx); diff --git a/src/rpcwallet.cpp b/src/rpcwallet.cpp index 7aae9ddb73..fe22dfe54c 100644 --- a/src/rpcwallet.cpp +++ b/src/rpcwallet.cpp @@ -1271,7 +1271,7 @@ Value keypoolrefill(const Array& params, bool fHelp) unsigned int kpSize = max(GetArg("-keypool", 100), 0LL); if (params.size() > 0) { if (params[0].get_int() < 0) - throw JSONRPCError(-8, "Invalid parameter, expected valid size"); + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected valid size"); kpSize = (unsigned int) params[0].get_int(); } @@ -1301,6 +1301,8 @@ Value walletpassphrase(const Array& params, bool fHelp) "Stores the wallet decryption key in memory for <timeout> seconds."); if (fHelp) return true; + if (!fServer) + throw JSONRPCError(RPC_SERVER_NOT_STARTED, "Error: RPC server was not started, use server=1 to change this."); if (!pwalletMain->IsCrypted()) throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrase was called."); diff --git a/src/serialize.h b/src/serialize.h index 4d9aec3426..115ea1d447 100644 --- a/src/serialize.h +++ b/src/serialize.h @@ -901,19 +901,6 @@ public: iterator insert(iterator it, const char& x=char()) { return vch.insert(it, x); } void insert(iterator it, size_type n, const char& x) { vch.insert(it, n, x); } - void insert(iterator it, const_iterator first, const_iterator last) - { - assert(last - first >= 0); - if (it == vch.begin() + nReadPos && (unsigned int)(last - first) <= nReadPos) - { - // special case for inserting at the front when there's room - nReadPos -= (last - first); - memcpy(&vch[nReadPos], &first[0], last - first); - } - else - vch.insert(it, first, last); - } - void insert(iterator it, std::vector<char>::const_iterator first, std::vector<char>::const_iterator last) { assert(last - first >= 0); @@ -1104,8 +1091,8 @@ public: } void GetAndClear(CSerializeData &data) { - vch.swap(data); - CSerializeData().swap(vch); + data.insert(data.end(), begin(), end()); + clear(); } }; diff --git a/src/test/base58_tests.cpp b/src/test/base58_tests.cpp index c435becc61..05675685bd 100644 --- a/src/test/base58_tests.cpp +++ b/src/test/base58_tests.cpp @@ -20,7 +20,7 @@ BOOST_AUTO_TEST_CASE(base58_EncodeBase58) BOOST_FOREACH(Value& tv, tests) { Array test = tv.get_array(); - std::string strTest = write_string(tv, raw_utf8); + std::string strTest = write_string(tv, false); if (test.size() < 2) // Allow for extra stuff (useful for comments) { BOOST_ERROR("Bad test: " << strTest); @@ -43,7 +43,7 @@ BOOST_AUTO_TEST_CASE(base58_DecodeBase58) BOOST_FOREACH(Value& tv, tests) { Array test = tv.get_array(); - std::string strTest = write_string(tv, raw_utf8); + std::string strTest = write_string(tv, false); if (test.size() < 2) // Allow for extra stuff (useful for comments) { BOOST_ERROR("Bad test: " << strTest); @@ -113,7 +113,7 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_parse) BOOST_FOREACH(Value& tv, tests) { Array test = tv.get_array(); - std::string strTest = write_string(tv, raw_utf8); + std::string strTest = write_string(tv, false); if (test.size() < 3) // Allow for extra stuff (useful for comments) { BOOST_ERROR("Bad test: " << strTest); @@ -169,7 +169,7 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_gen) BOOST_FOREACH(Value& tv, tests) { Array test = tv.get_array(); - std::string strTest = write_string(tv, raw_utf8); + std::string strTest = write_string(tv, false); if (test.size() < 3) // Allow for extra stuff (useful for comments) { BOOST_ERROR("Bad test: " << strTest); @@ -240,7 +240,7 @@ BOOST_AUTO_TEST_CASE(base58_keys_invalid) BOOST_FOREACH(Value& tv, tests) { Array test = tv.get_array(); - std::string strTest = write_string(tv, raw_utf8); + std::string strTest = write_string(tv, false); if (test.size() < 1) // Allow for extra stuff (useful for comments) { BOOST_ERROR("Bad test: " << strTest); diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp index 35eabed0e2..25849054eb 100644 --- a/src/test/rpc_tests.cpp +++ b/src/test/rpc_tests.cpp @@ -168,4 +168,35 @@ BOOST_AUTO_TEST_CASE(rpc_rawsign) BOOST_CHECK(find_value(r.get_obj(), "complete").get_bool() == true); } +BOOST_AUTO_TEST_CASE(rpc_format_monetary_values) +{ + BOOST_CHECK(write_string(ValueFromAmount(0LL), false) == "0.00000000"); + BOOST_CHECK(write_string(ValueFromAmount(1LL), false) == "0.00000001"); + BOOST_CHECK(write_string(ValueFromAmount(17622195LL), false) == "0.17622195"); + BOOST_CHECK(write_string(ValueFromAmount(50000000LL), false) == "0.50000000"); + BOOST_CHECK(write_string(ValueFromAmount(89898989LL), false) == "0.89898989"); + BOOST_CHECK(write_string(ValueFromAmount(100000000LL), false) == "1.00000000"); + BOOST_CHECK(write_string(ValueFromAmount(2099999999999990LL), false) == "20999999.99999990"); + BOOST_CHECK(write_string(ValueFromAmount(2099999999999999LL), false) == "20999999.99999999"); +} + +static Value ValueFromString(const std::string &str) +{ + Value value; + BOOST_CHECK(read_string(str, value)); + return value; +} + +BOOST_AUTO_TEST_CASE(rpc_parse_monetary_values) +{ + BOOST_CHECK(AmountFromValue(ValueFromString("0.00000001")) == 1LL); + BOOST_CHECK(AmountFromValue(ValueFromString("0.17622195")) == 17622195LL); + BOOST_CHECK(AmountFromValue(ValueFromString("0.5")) == 50000000LL); + BOOST_CHECK(AmountFromValue(ValueFromString("0.50000000")) == 50000000LL); + BOOST_CHECK(AmountFromValue(ValueFromString("0.89898989")) == 89898989LL); + BOOST_CHECK(AmountFromValue(ValueFromString("1.00000000")) == 100000000LL); + BOOST_CHECK(AmountFromValue(ValueFromString("20999999.9999999")) == 2099999999999990LL); + BOOST_CHECK(AmountFromValue(ValueFromString("20999999.99999999")) == 2099999999999999LL); +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp index 079cc49f60..32be914414 100644 --- a/src/test/script_tests.cpp +++ b/src/test/script_tests.cpp @@ -118,7 +118,7 @@ BOOST_AUTO_TEST_CASE(script_valid) BOOST_FOREACH(Value& tv, tests) { Array test = tv.get_array(); - string strTest = write_string(tv, raw_utf8); + string strTest = write_string(tv, false); if (test.size() < 2) // Allow size > 2; extra stuff ignored (useful for comments) { BOOST_ERROR("Bad test: " << strTest); @@ -142,7 +142,7 @@ BOOST_AUTO_TEST_CASE(script_invalid) BOOST_FOREACH(Value& tv, tests) { Array test = tv.get_array(); - string strTest = write_string(tv, raw_utf8); + string strTest = write_string(tv, false); if (test.size() < 2) // Allow size > 2; extra stuff ignored (useful for comments) { BOOST_ERROR("Bad test: " << strTest); diff --git a/src/test/serialize_tests.cpp b/src/test/serialize_tests.cpp index 50139df09e..7e193c88ce 100644 --- a/src/test/serialize_tests.cpp +++ b/src/test/serialize_tests.cpp @@ -102,4 +102,52 @@ BOOST_AUTO_TEST_CASE(noncanonical) BOOST_CHECK_EXCEPTION(ReadCompactSize(ss), std::ios_base::failure, isCanonicalException); } +BOOST_AUTO_TEST_CASE(insert_delete) +{ + // Test inserting/deleting bytes. + CDataStream ss(SER_DISK, 0); + BOOST_CHECK_EQUAL(ss.size(), 0); + + ss.write("\x00\x01\x02\xff", 4); + BOOST_CHECK_EQUAL(ss.size(), 4); + + char c = (char)11; + + // Inserting at beginning/end/middle: + ss.insert(ss.begin(), c); + BOOST_CHECK_EQUAL(ss.size(), 5); + BOOST_CHECK_EQUAL(ss[0], c); + BOOST_CHECK_EQUAL(ss[1], 0); + + ss.insert(ss.end(), c); + BOOST_CHECK_EQUAL(ss.size(), 6); + BOOST_CHECK_EQUAL(ss[4], (char)0xff); + BOOST_CHECK_EQUAL(ss[5], c); + + ss.insert(ss.begin()+2, c); + BOOST_CHECK_EQUAL(ss.size(), 7); + BOOST_CHECK_EQUAL(ss[2], c); + + // Delete at beginning/end/middle + ss.erase(ss.begin()); + BOOST_CHECK_EQUAL(ss.size(), 6); + BOOST_CHECK_EQUAL(ss[0], 0); + + ss.erase(ss.begin()+ss.size()-1); + BOOST_CHECK_EQUAL(ss.size(), 5); + BOOST_CHECK_EQUAL(ss[4], (char)0xff); + + ss.erase(ss.begin()+1); + BOOST_CHECK_EQUAL(ss.size(), 4); + BOOST_CHECK_EQUAL(ss[0], 0); + BOOST_CHECK_EQUAL(ss[1], 1); + BOOST_CHECK_EQUAL(ss[2], 2); + BOOST_CHECK_EQUAL(ss[3], (char)0xff); + + // Make sure GetAndClear does the right thing: + CSerializeData d; + ss.GetAndClear(d); + BOOST_CHECK_EQUAL(ss.size(), 0); +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp index c6bc2e8aa1..bd999caa14 100644 --- a/src/test/transaction_tests.cpp +++ b/src/test/transaction_tests.cpp @@ -29,7 +29,7 @@ BOOST_AUTO_TEST_CASE(tx_valid) BOOST_FOREACH(Value& tv, tests) { Array test = tv.get_array(); - string strTest = write_string(tv, raw_utf8); + string strTest = write_string(tv, false); if (test[0].type() == array_type) { if (test.size() != 3 || test[1].type() != str_type || test[2].type() != bool_type) @@ -98,7 +98,7 @@ BOOST_AUTO_TEST_CASE(tx_invalid) BOOST_FOREACH(Value& tv, tests) { Array test = tv.get_array(); - string strTest = write_string(tv, raw_utf8); + string strTest = write_string(tv, false); if (test[0].type() == array_type) { if (test.size() != 3 || test[1].type() != str_type || test[2].type() != bool_type) diff --git a/src/util.cpp b/src/util.cpp index 71994587cf..085df8a7d5 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -73,7 +73,6 @@ using namespace std; map<string, string> mapArgs; map<string, vector<string> > mapMultiArgs; bool fDebug = false; -bool fDebugNet = false; bool fPrintToConsole = false; bool fPrintToDebugger = false; bool fDaemon = false; @@ -81,7 +80,6 @@ bool fServer = false; string strMiscWarning; bool fNoListen = false; bool fLogTimestamps = false; -CMedianFilter<int64> vTimeOffsets(200,0); volatile bool fReopenDebugLog = false; // Init OpenSSL library multithreading support @@ -226,10 +224,20 @@ int LogPrint(const char* category, const char* pszFormat, ...) { if (category != NULL) { - if (!fDebug) return 0; - const vector<string>& categories = mapMultiArgs["-debug"]; - if (find(categories.begin(), categories.end(), string(category)) == categories.end()) + if (!fDebug) return 0; + + const vector<string>& categories = mapMultiArgs["-debug"]; + bool allCategories = count(categories.begin(), categories.end(), string("")); + + // Only look for categories, if not -debug/-debug=1 was passed, + // as that implies every category should be logged. + if (!allCategories) + { + // Category was not found (not supplied via -debug=<category>) + if (find(categories.begin(), categories.end(), string(category)) == categories.end()) + return 0; + } } int ret = 0; // Returns total number of characters written @@ -1296,10 +1304,12 @@ void SetMockTime(int64 nMockTimeIn) nMockTime = nMockTimeIn; } +static CCriticalSection cs_nTimeOffset; static int64 nTimeOffset = 0; int64 GetTimeOffset() { + LOCK(cs_nTimeOffset); return nTimeOffset; } @@ -1312,12 +1322,14 @@ void AddTimeData(const CNetAddr& ip, int64 nTime) { int64 nOffsetSample = nTime - GetTime(); + LOCK(cs_nTimeOffset); // Ignore duplicates static set<CNetAddr> setKnown; if (!setKnown.insert(ip).second) return; // Add data + static CMedianFilter<int64> vTimeOffsets(200,0); vTimeOffsets.input(nOffsetSample); LogPrintf("Added time data, samples %d, offset %+"PRI64d" (%+"PRI64d" minutes)\n", vTimeOffsets.size(), nOffsetSample, nOffsetSample/60); if (vTimeOffsets.size() >= 5 && vTimeOffsets.size() % 2 == 1) diff --git a/src/util.h b/src/util.h index 258910e2fb..2573694046 100644 --- a/src/util.h +++ b/src/util.h @@ -140,7 +140,6 @@ inline void MilliSleep(int64 n) extern std::map<std::string, std::string> mapArgs; extern std::map<std::string, std::vector<std::string> > mapMultiArgs; extern bool fDebug; -extern bool fDebugNet; extern bool fPrintToConsole; extern bool fPrintToDebugger; extern bool fDaemon; diff --git a/src/wallet.cpp b/src/wallet.cpp index a7a2992bb9..ea1e01e6e9 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -505,7 +505,7 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn) // Add a transaction to the wallet, or update it. // pblock is optional, but should be provided if the transaction is known to be in a block. // If fUpdate is true, existing transactions will be updated. -bool CWallet::AddToWalletIfInvolvingMe(const uint256 &hash, const CTransaction& tx, const CBlock* pblock, bool fUpdate, bool fFindBlock) +bool CWallet::AddToWalletIfInvolvingMe(const uint256 &hash, const CTransaction& tx, const CBlock* pblock, bool fUpdate) { { LOCK(cs_wallet); @@ -525,16 +525,20 @@ bool CWallet::AddToWalletIfInvolvingMe(const uint256 &hash, const CTransaction& return false; } -bool CWallet::EraseFromWallet(uint256 hash) +void CWallet::SyncTransaction(const uint256 &hash, const CTransaction& tx, const CBlock* pblock) { + AddToWalletIfInvolvingMe(hash, tx, pblock, true); +} + +void CWallet::EraseFromWallet(const uint256 &hash) { if (!fFileBacked) - return false; + return; { LOCK(cs_wallet); if (mapWallet.erase(hash)) CWalletDB(strWalletFile).EraseTx(hash); } - return true; + return; } @@ -773,6 +777,25 @@ void CWalletTx::AddSupportingTransactions() reverse(vtxPrev.begin(), vtxPrev.end()); } +bool CWalletTx::AcceptWalletTransaction() +{ + { + LOCK(mempool.cs); + // Add previous supporting transactions first + BOOST_FOREACH(CMerkleTx& tx, vtxPrev) + { + if (!tx.IsCoinBase()) + { + uint256 hash = tx.GetHash(); + if (!mempool.exists(hash) && pcoinsTip->HaveCoins(hash)) + tx.AcceptToMemoryPool(false); + } + } + return AcceptToMemoryPool(false); + } + return false; +} + bool CWalletTx::WriteToDisk() { return CWalletDB(pwallet->strWalletFile).WriteTx(GetHash(), *this); @@ -1485,33 +1508,6 @@ bool CWallet::DelAddressBook(const CTxDestination& address) return CWalletDB(strWalletFile).EraseName(CBitcoinAddress(address).ToString()); } -void CWallet::PrintWallet(const CBlock& block) -{ - { - LOCK(cs_wallet); - if (mapWallet.count(block.vtx[0].GetHash())) - { - CWalletTx& wtx = mapWallet[block.vtx[0].GetHash()]; - LogPrintf(" mine: %d %d %"PRI64d"", wtx.GetDepthInMainChain(), wtx.GetBlocksToMaturity(), wtx.GetCredit()); - } - } - LogPrintf("\n"); -} - -bool CWallet::GetTransaction(const uint256 &hashTx, CWalletTx& wtx) -{ - { - LOCK(cs_wallet); - map<uint256, CWalletTx>::iterator mi = mapWallet.find(hashTx); - if (mi != mapWallet.end()) - { - wtx = (*mi).second; - return true; - } - } - return false; -} - bool CWallet::SetDefaultKey(const CPubKey &vchPubKey) { if (fFileBacked) @@ -1523,14 +1519,6 @@ bool CWallet::SetDefaultKey(const CPubKey &vchPubKey) return true; } -bool GetWalletFile(CWallet* pwallet, string &strWalletFileOut) -{ - if (!pwallet->fFileBacked) - return false; - strWalletFileOut = pwallet->strWalletFile; - return true; -} - // // Mark old keypool keys as used, // and generate all new keys diff --git a/src/wallet.h b/src/wallet.h index f87e9b08c4..21510f8c39 100644 --- a/src/wallet.h +++ b/src/wallet.h @@ -80,7 +80,7 @@ public: /** A CWallet is an extension of a keystore, which also maintains a set of transactions and balances, * and provides the ability to create new transactions. */ -class CWallet : public CCryptoKeyStore +class CWallet : public CCryptoKeyStore, public CWalletInterface { private: bool SelectCoins(int64 nTargetValue, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64& nValueRet) const; @@ -197,8 +197,9 @@ public: void MarkDirty(); bool AddToWallet(const CWalletTx& wtxIn); - bool AddToWalletIfInvolvingMe(const uint256 &hash, const CTransaction& tx, const CBlock* pblock, bool fUpdate = false, bool fFindBlock = false); - bool EraseFromWallet(uint256 hash); + void SyncTransaction(const uint256 &hash, const CTransaction& tx, const CBlock* pblock); + bool AddToWalletIfInvolvingMe(const uint256 &hash, const CTransaction& tx, const CBlock* pblock, bool fUpdate); + void EraseFromWallet(const uint256 &hash); void WalletUpdateSpent(const CTransaction& prevout); int ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate = false); void ReacceptWalletTransactions(); @@ -302,8 +303,6 @@ public: void UpdatedTransaction(const uint256 &hashTx); - void PrintWallet(const CBlock& block); - void Inventory(const uint256 &hash) { { @@ -319,8 +318,6 @@ public: return setKeyPool.size(); } - bool GetTransaction(const uint256 &hashTx, CWalletTx& wtx); - bool SetDefaultKey(const CPubKey &vchPubKey); // signify that a particular wallet feature is now used. this may change nWalletVersion and nWalletMaxVersion if those are lower @@ -891,6 +888,4 @@ private: std::vector<char> _ssExtra; }; -bool GetWalletFile(CWallet* pwallet, std::string &strWalletFileOut); - #endif |