aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore13
-rw-r--r--COPYING2
-rw-r--r--Makefile.am7
-rw-r--r--README.md49
-rwxr-xr-xautogen.sh3
-rw-r--r--configure.ac18
-rw-r--r--contrib/bitrpc/bitrpc.py12
-rw-r--r--contrib/debian/control1
-rw-r--r--contrib/debian/examples/bitcoin.conf95
-rw-r--r--contrib/debian/manpages/bitcoin-qt.13
-rw-r--r--contrib/gitian-descriptors/deps-linux.yml10
-rw-r--r--contrib/gitian-descriptors/deps-win.yml10
-rw-r--r--contrib/gitian-descriptors/gitian-linux.yml6
-rw-r--r--contrib/gitian-descriptors/gitian-osx-bitcoin.yml26
-rw-r--r--contrib/gitian-descriptors/gitian-osx-depends.yml23
-rw-r--r--contrib/gitian-descriptors/gitian-osx-native.yml15
-rw-r--r--contrib/gitian-descriptors/gitian-osx-qt.yml24
-rw-r--r--contrib/gitian-descriptors/gitian-win.yml6
-rw-r--r--contrib/gitian-descriptors/qt-linux.yml1
-rw-r--r--contrib/gitian-descriptors/qt-win.yml6
-rw-r--r--contrib/gitian-downloader/cfields-key.pgp52
-rw-r--r--contrib/gitian-downloader/linux-download-config3
-rw-r--r--contrib/gitian-downloader/win32-download-config3
-rw-r--r--contrib/macdeploy/README.md4
-rwxr-xr-xcontrib/macdeploy/macdeployqtplus11
-rw-r--r--contrib/verifysfbinaries/README.md2
-rwxr-xr-xcontrib/verifysfbinaries/verify.sh8
-rw-r--r--doc/README_osx.txt14
-rw-r--r--doc/build-osx.md24
-rw-r--r--doc/build-unix.md21
-rw-r--r--doc/coding.md75
-rw-r--r--doc/gitian-building.md72
-rw-r--r--doc/release-notes.md85
-rw-r--r--doc/release-notes/release-notes-0.9.1.md53
-rw-r--r--doc/release-notes/release-notes-0.9.2.1.md207
-rw-r--r--doc/release-notes/release-notes-0.9.2.md207
-rw-r--r--doc/release-process.md86
-rw-r--r--doc/translation_process.md2
-rwxr-xr-xqa/rpc-tests/receivedby.py225
-rwxr-xr-xqa/rpc-tests/rpcbind_test.py22
-rwxr-xr-xqa/rpc-tests/smartfees.py142
-rw-r--r--qa/rpc-tests/util.py178
-rw-r--r--qa/rpc-tests/util.sh8
-rwxr-xr-xqa/rpc-tests/zapwallettxes.sh161
-rwxr-xr-xshare/qt/extract_strings_qt.py5
-rw-r--r--src/Makefile.am170
-rw-r--r--src/Makefile.include79
-rw-r--r--src/Makefile.qt.include417
-rw-r--r--src/Makefile.qttest.include51
-rw-r--r--src/Makefile.test.include109
-rw-r--r--src/addrman.h5
-rw-r--r--src/alert.cpp2
-rw-r--r--src/base58.cpp13
-rw-r--r--src/bitcoin-cli-res.rc1
-rw-r--r--src/bitcoin-cli.cpp193
-rw-r--r--src/bitcoind-res.rc1
-rw-r--r--src/bitcoind.cpp33
-rw-r--r--src/bloom.cpp10
-rw-r--r--src/bloom.h4
-rw-r--r--src/chainparams.cpp95
-rw-r--r--src/chainparams.h93
-rw-r--r--src/chainparamsbase.cpp93
-rw-r--r--src/chainparamsbase.h52
-rw-r--r--src/checkpoints.cpp17
-rw-r--r--src/checkpoints.h7
-rw-r--r--src/clientversion.h7
-rw-r--r--src/coins.cpp16
-rw-r--r--src/coins.h11
-rw-r--r--src/compat/glibc_compat.cpp19
-rw-r--r--src/compat/glibc_sanity.cpp67
-rw-r--r--src/compat/glibcxx_compat.cpp50
-rw-r--r--src/compat/glibcxx_sanity.cpp65
-rw-r--r--src/compat/sanity.h11
-rw-r--r--src/config/.empty0
-rw-r--r--src/core.cpp80
-rw-r--r--src/core.h140
-rw-r--r--src/crypto/common.h93
-rw-r--r--src/crypto/ripemd160.cpp204
-rw-r--r--src/crypto/ripemd160.h27
-rw-r--r--src/crypto/sha1.cpp192
-rw-r--r--src/crypto/sha1.h27
-rw-r--r--src/crypto/sha2.cpp398
-rw-r--r--src/crypto/sha2.h60
-rw-r--r--src/hash.cpp41
-rw-r--r--src/hash.h189
-rw-r--r--src/init.cpp201
-rw-r--r--src/init.h6
-rw-r--r--src/key.cpp177
-rw-r--r--src/key.h7
-rw-r--r--src/keystore.cpp12
-rw-r--r--src/keystore.h19
-rw-r--r--src/leveldbwrapper.h4
-rw-r--r--src/m4/bitcoin_qt.m42
-rw-r--r--src/main.cpp911
-rw-r--r--src/main.h119
-rw-r--r--src/miner.cpp441
-rw-r--r--src/miner.h7
-rw-r--r--src/mruset.h1
-rw-r--r--src/net.cpp207
-rw-r--r--src/net.h52
-rw-r--r--src/netbase.cpp187
-rw-r--r--src/netbase.h13
-rw-r--r--src/pow.cpp119
-rw-r--r--src/pow.h23
-rw-r--r--src/protocol.cpp1
-rw-r--r--src/protocol.h11
-rw-r--r--src/qt/Makefile9
-rw-r--r--src/qt/Makefile.am379
-rw-r--r--src/qt/addressbookpage.cpp2
-rw-r--r--src/qt/addresstablemodel.cpp6
-rw-r--r--src/qt/askpassphrasedialog.cpp2
-rw-r--r--src/qt/bitcoin.cpp17
-rw-r--r--src/qt/bitcoin.qrc76
-rw-r--r--src/qt/bitcoin_locale.qrc75
-rw-r--r--src/qt/bitcoingui.cpp110
-rw-r--r--src/qt/bitcoingui.h42
-rw-r--r--src/qt/bitcoinstrings.cpp79
-rw-r--r--src/qt/bitcoinunits.cpp21
-rw-r--r--src/qt/bitcoinunits.h4
-rw-r--r--src/qt/clientmodel.cpp31
-rw-r--r--src/qt/clientmodel.h8
-rw-r--r--src/qt/coincontroldialog.cpp117
-rw-r--r--src/qt/coincontroldialog.h3
-rw-r--r--src/qt/forms/aboutdialog.ui189
-rw-r--r--src/qt/forms/coincontroldialog.ui2
-rw-r--r--src/qt/forms/helpmessagedialog.ui10
-rw-r--r--src/qt/forms/optionsdialog.ui30
-rw-r--r--src/qt/forms/overviewpage.ui533
-rw-r--r--src/qt/forms/rpcconsole.ui339
-rw-r--r--src/qt/forms/sendcoinsdialog.ui2
-rw-r--r--src/qt/forms/sendcoinsentry.ui2
-rw-r--r--src/qt/forms/signverifymessagedialog.ui4
-rw-r--r--src/qt/guiconstants.h4
-rw-r--r--src/qt/guiutil.cpp60
-rw-r--r--src/qt/guiutil.h5
-rw-r--r--src/qt/locale/bitcoin_da.ts732
-rw-r--r--src/qt/locale/bitcoin_el_GR.ts147
-rw-r--r--src/qt/locale/bitcoin_id_ID.ts72
-rw-r--r--src/qt/locale/bitcoin_ko_KR.ts148
-rw-r--r--src/qt/locale/bitcoin_nb.ts6
-rw-r--r--src/qt/locale/bitcoin_ro_RO.ts6
-rw-r--r--src/qt/locale/bitcoin_sl_SI.ts38
-rw-r--r--src/qt/locale/bitcoin_th_TH.ts96
-rw-r--r--src/qt/locale/bitcoin_zh_CN.ts82
-rw-r--r--src/qt/macdockiconhandler.mm2
-rw-r--r--src/qt/notificator.cpp2
-rw-r--r--src/qt/notificator.h2
-rw-r--r--src/qt/optionsdialog.cpp21
-rw-r--r--src/qt/optionsmodel.cpp87
-rw-r--r--src/qt/optionsmodel.h3
-rw-r--r--src/qt/overviewpage.cpp34
-rw-r--r--src/qt/overviewpage.h6
-rw-r--r--src/qt/paymentrequestplus.cpp23
-rw-r--r--src/qt/paymentrequestplus.h2
-rw-r--r--src/qt/paymentserver.cpp129
-rw-r--r--src/qt/peertablemodel.cpp236
-rw-r--r--src/qt/peertablemodel.h80
-rw-r--r--src/qt/receiverequestdialog.cpp4
-rw-r--r--src/qt/receiverequestdialog.h4
-rw-r--r--src/qt/recentrequeststablemodel.cpp27
-rw-r--r--src/qt/recentrequeststablemodel.h6
-rw-r--r--src/qt/res/bitcoin-qt-res.rc1
-rw-r--r--src/qt/res/icons/unit_btc.pngbin0 -> 2107 bytes
-rw-r--r--src/qt/res/icons/unit_mbtc.pngbin0 -> 2107 bytes
-rw-r--r--src/qt/res/icons/unit_ubtc.pngbin0 -> 2107 bytes
-rw-r--r--src/qt/rpcconsole.cpp212
-rw-r--r--src/qt/rpcconsole.h30
-rw-r--r--src/qt/sendcoinsdialog.cpp39
-rw-r--r--src/qt/sendcoinsdialog.h3
-rw-r--r--src/qt/signverifymessagedialog.cpp1
-rw-r--r--src/qt/splashscreen.cpp2
-rw-r--r--src/qt/test/Makefile6
-rw-r--r--src/qt/test/Makefile.am46
-rw-r--r--src/qt/test/paymentservertests.cpp1
-rw-r--r--src/qt/test/test_main.cpp3
-rw-r--r--src/qt/transactiondesc.cpp86
-rw-r--r--src/qt/transactiondesc.h4
-rw-r--r--src/qt/transactionfilterproxy.cpp4
-rw-r--r--src/qt/transactionrecord.cpp37
-rw-r--r--src/qt/transactionrecord.h27
-rw-r--r--src/qt/transactiontablemodel.cpp48
-rw-r--r--src/qt/transactiontablemodel.h2
-rw-r--r--src/qt/transactionview.cpp2
-rw-r--r--src/qt/utilitydialog.cpp117
-rw-r--r--src/qt/utilitydialog.h25
-rw-r--r--src/qt/walletmodel.cpp55
-rw-r--r--src/qt/walletmodel.h9
-rw-r--r--src/qt/winshutdownmonitor.cpp19
-rw-r--r--src/rpcblockchain.cpp28
-rw-r--r--src/rpcclient.cpp342
-rw-r--r--src/rpcclient.h10
-rw-r--r--src/rpcdump.cpp60
-rw-r--r--src/rpcmining.cpp237
-rw-r--r--src/rpcmisc.cpp63
-rw-r--r--src/rpcnet.cpp14
-rw-r--r--src/rpcprotocol.cpp65
-rw-r--r--src/rpcprotocol.h6
-rw-r--r--src/rpcrawtransaction.cpp21
-rw-r--r--src/rpcserver.cpp181
-rw-r--r--src/rpcserver.h16
-rw-r--r--src/rpcwallet.cpp171
-rw-r--r--src/script.cpp92
-rw-r--r--src/script.h39
-rw-r--r--src/secp256k1/.empty0
-rw-r--r--src/serialize.h34
-rw-r--r--src/test/DoS_tests.cpp94
-rw-r--r--src/test/Makefile6
-rw-r--r--src/test/Makefile.am77
-rw-r--r--src/test/accounting_tests.cpp12
-rw-r--r--src/test/base58_tests.cpp12
-rw-r--r--src/test/bloom_tests.cpp32
-rw-r--r--src/test/crypto_tests.cpp203
-rw-r--r--src/test/data/tx_valid.json48
-rw-r--r--src/test/hmac_tests.cpp129
-rw-r--r--src/test/miner_tests.cpp40
-rw-r--r--src/test/multisig_tests.cpp8
-rw-r--r--src/test/pmt_tests.cpp4
-rw-r--r--src/test/rpc_wallet_tests.cpp87
-rw-r--r--src/test/script_P2SH_tests.cpp134
-rw-r--r--src/test/script_tests.cpp12
-rw-r--r--src/test/sighash_tests.cpp6
-rw-r--r--src/test/skiplist_tests.cpp101
-rw-r--r--src/test/test_bitcoin.cpp3
-rw-r--r--src/test/transaction_tests.cpp14
-rw-r--r--src/test/util_tests.cpp15
-rw-r--r--src/test/wallet_tests.cpp12
-rw-r--r--src/timedata.cpp91
-rw-r--r--src/timedata.h17
-rw-r--r--src/txdb.cpp9
-rw-r--r--src/txdb.h2
-rw-r--r--src/txmempool.cpp407
-rw-r--r--src/txmempool.h33
-rw-r--r--src/ui_interface.h6
-rw-r--r--src/uint256.cpp292
-rw-r--r--src/uint256.h262
-rw-r--r--src/util.cpp239
-rw-r--r--src/util.h34
-rw-r--r--src/version.cpp2
-rw-r--r--src/wallet.cpp331
-rw-r--r--src/wallet.h207
-rw-r--r--src/walletdb.cpp29
-rw-r--r--src/walletdb.h7
242 files changed, 11365 insertions, 5628 deletions
diff --git a/.gitignore b/.gitignore
index 85ddf3871f..4169a2d96c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -13,12 +13,19 @@ autom4te.cache/
config.log
config.status
configure
-src/bitcoin-config.h
-src/bitcoin-config.h.in
+src/config/bitcoin-config.h
+src/config/bitcoin-config.h.in
+src/config/stamp-h1
src/build-aux/
-src/stamp-h1
share/setup.nsi
share/qt/Info.plist
+# Libtool
+libtool
+src/m4/libtool.m4
+src/m4/ltoptions.m4
+src/m4/ltsugar.m4
+src/m4/ltversion.m4
+src/m4/lt~obsolete.m4
src/qt/*.moc
src/qt/moc_*.cpp
diff --git a/COPYING b/COPYING
index c410baa6a0..6219bd75a6 100644
--- a/COPYING
+++ b/COPYING
@@ -1,4 +1,4 @@
-Copyright (c) 2009-2013 Bitcoin Developers
+Copyright (c) 2009-2014 Bitcoin Developers
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/Makefile.am b/Makefile.am
index 04f8368dd7..3a6a6b6d88 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,6 +1,6 @@
ACLOCAL_AMFLAGS = -I src/m4
SUBDIRS = src
-.PHONY: deploy
+.PHONY: deploy FORCE
GZIP_ENV="-9n"
@@ -35,6 +35,7 @@ COVERAGE_INFO = baseline_filtered_combined.info baseline.info block_test.info \
dist-hook:
-$(MAKE) -C $(top_distdir)/src/leveldb clean
+ -$(MAKE) -C $(top_distdir)/src/secp256k1 distclean
-$(GIT) archive --format=tar HEAD -- src/version.cpp | $(AMTAR) -C $(top_distdir) -xf -
distcheck-hook:
@@ -53,8 +54,8 @@ $(BITCOIN_WIN_INSTALLER): $(BITCOIND_BIN) $(BITCOIN_QT_BIN) $(BITCOIN_CLI_BIN)
@test -f $(MAKENSIS) && $(MAKENSIS) $(top_builddir)/share/setup.nsi || \
echo error: could not build $@
-$(BITCOIND_BIN) $(BITCOIN_QT_BIN) $(BITCOIN_CLI_BIN):
- make -C $(dir $@) $(notdir $@)
+$(if $(findstring src/,$(MAKECMDGOALS)),$(MAKECMDGOALS), none): FORCE
+ $(MAKE) -C src $(patsubst src/%,%,$@)
$(OSX_APP)/Contents/PkgInfo:
$(MKDIR_P) $(@D)
diff --git a/README.md b/README.md
index 3e9ec25980..081af80dcf 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
Bitcoin Core integration/staging tree
=====================================
-http://www.bitcoin.org
+https://www.bitcoin.org
Copyright (c) 2009-2014 Bitcoin Core Developers
@@ -15,7 +15,7 @@ out collectively by the network. Bitcoin Core is the name of open source
software which enables the use of this currency.
For more information, as well as an immediately useable, binary version of
-the Bitcoin Core software, see http://www.bitcoin.org/en/download.
+the Bitcoin Core software, see https://www.bitcoin.org/en/download.
License
-------
@@ -49,8 +49,8 @@ Testing
-------
Testing and code review is the bottleneck for development; we get more pull
-requests than we can review and test. Please be patient and help out, and
-remember this is a security-critical project where any mistake might cost people
+requests than we can review and test on short notice. Please be patient and help out by testing
+other people's pull requests, and remember this is a security-critical project where any mistake might cost people
lots of money.
### Automated Testing
@@ -76,8 +76,45 @@ Translations
Changes to translations as well as new translations can be submitted to
[Bitcoin Core's Transifex page](https://www.transifex.com/projects/p/bitcoin/).
-Periodically the translations are pulled from Transifex and merged into the git repository. See the
+Translations are periodically pulled from Transifex and merged into the git repository. See the
[translation process](doc/translation_process.md) for details on how this works.
-**Important**: We do not accept translation changes as github pull request because the next
+**Important**: We do not accept translation changes as GitHub pull requests because the next
pull from Transifex would automatically overwrite them again.
+
+Translators should also subscribe to the [mailing list](https://groups.google.com/forum/#!forum/bitcoin-translators).
+
+Development tips and tricks
+---------------------------
+
+**compiling for debugging**
+
+Run configure with the --enable-debug option, then make. Or run configure with
+CXXFLAGS="-g -ggdb -O0" or whatever debug flags you need.
+
+**debug.log**
+
+If the code is behaving strangely, take a look in the debug.log file in the data directory;
+error and debugging message are written there.
+
+The -debug=... command-line option controls debugging; running with just -debug will turn
+on all categories (and give you a very large debug.log file).
+
+The Qt code routes qDebug() output to debug.log under category "qt": run with -debug=qt
+to see it.
+
+**testnet and regtest modes**
+
+Run with the -testnet option to run with "play bitcoins" on the test network, if you
+are testing multi-machine code that needs to operate across the internet.
+
+If you are testing something that can run on one machine, run with the -regtest option.
+In regression test mode blocks can be created on-demand; see qa/rpc-tests/ for tests
+that run in -regest mode.
+
+**DEBUG_LOCKORDER**
+
+Bitcoin Core is a multithreaded application, and deadlocks or other multithreading bugs
+can be very difficult to track down. Compiling with -DDEBUG_LOCKORDER (configure
+CXXFLAGS="-DDEBUG_LOCKORDER -g") inserts run-time checks to keep track of what locks
+are held, and adds warning to the debug.log file if inconsistencies are detected.
diff --git a/autogen.sh b/autogen.sh
index 5b883a6a4c..50b85bcba0 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -2,4 +2,7 @@
set -e
srcdir="$(dirname $0)"
cd "$srcdir"
+if [ -z ${LIBTOOLIZE} ] && GLIBTOOLIZE="`which glibtoolize 2>/dev/null`"; then
+ export LIBTOOLIZE="${GLIBTOOLIZE}"
+fi
autoreconf --install --force
diff --git a/configure.ac b/configure.ac
index 3a8d33a5a0..dcaec0d4b0 100644
--- a/configure.ac
+++ b/configure.ac
@@ -9,6 +9,7 @@ define(_COPYRIGHT_YEAR, 2014)
AC_INIT([Bitcoin Core],[_CLIENT_VERSION_MAJOR._CLIENT_VERSION_MINOR._CLIENT_VERSION_REVISION],[info@bitcoin.org],[bitcoin])
AC_CONFIG_AUX_DIR([src/build-aux])
AC_CONFIG_MACRO_DIR([src/m4])
+LT_INIT([disable-shared])
AC_CANONICAL_HOST
AH_TOP([#ifndef BITCOIN_CONFIG_H])
AH_TOP([#define BITCOIN_CONFIG_H])
@@ -111,7 +112,7 @@ AC_ARG_WITH([protoc-bindir],[AS_HELP_STRING([--with-protoc-bindir=BIN_DIR],[spec
AC_CONFIG_SRCDIR([src])
-AC_CONFIG_HEADERS([src/bitcoin-config.h])
+AC_CONFIG_HEADERS([src/config/bitcoin-config.h])
dnl Checks for programs.
AC_PROG_CXX
@@ -368,7 +369,14 @@ if test x$TARGET_OS = xdarwin; then
AX_CHECK_LINK_FLAG([[-Wl,-dead_strip]], [LDFLAGS="$LDFLAGS -Wl,-dead_strip"])
fi
-AC_CHECK_HEADERS([stdio.h stdlib.h unistd.h strings.h sys/types.h sys/stat.h])
+AC_CHECK_HEADERS([endian.h stdio.h stdlib.h unistd.h strings.h sys/types.h sys/stat.h sys/select.h])
+AC_SEARCH_LIBS([getaddrinfo_a], [anl], [AC_DEFINE(HAVE_GETADDRINFO_A, 1, [Define this symbol if you have getaddrinfo_a])])
+AC_SEARCH_LIBS([inet_pton], [nsl resolv], [AC_DEFINE(HAVE_INET_PTON, 1, [Define this symbol if you have inet_pton])])
+
+AC_CHECK_DECLS([le32toh, le64toh, htole32, htole64, be32toh, be64toh, htobe32, htobe64],,,
+ [#if HAVE_ENDIAN_H
+ #include <endian.h>
+ #endif])
dnl Check for MSG_NOSIGNAL
AC_MSG_CHECKING(for MSG_NOSIGNAL)
@@ -666,11 +674,15 @@ AM_CONDITIONAL([TARGET_DARWIN], [test x$TARGET_OS = xdarwin])
AM_CONDITIONAL([BUILD_DARWIN], [test x$BUILD_OS = xdarwin])
AM_CONDITIONAL([TARGET_WINDOWS], [test x$TARGET_OS = xwindows])
AM_CONDITIONAL([ENABLE_WALLET],[test x$enable_wallet == xyes])
+AM_CONDITIONAL([ENABLE_TESTS],[test x$use_tests == xyes])
+AM_CONDITIONAL([ENABLE_QT],[test x$bitcoin_enable_qt == xyes])
+AM_CONDITIONAL([ENABLE_QT_TESTS],[test x$use_tests$bitcoin_enable_qt_test = xyesyes])
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])
AM_CONDITIONAL([GLIBC_BACK_COMPAT],[test x$use_glibc_compat = xyes])
+AM_CONDITIONAL([USE_LIBSECP256K1],[test x$use_libsecp256k1 = xyes])
AC_DEFINE(CLIENT_VERSION_MAJOR, _CLIENT_VERSION_MAJOR, [Major version])
AC_DEFINE(CLIENT_VERSION_MINOR, _CLIENT_VERSION_MINOR, [Minor version])
@@ -695,7 +707,7 @@ AC_SUBST(LEVELDB_TARGET_FLAGS)
AC_SUBST(BUILD_TEST)
AC_SUBST(BUILD_QT)
AC_SUBST(BUILD_TEST_QT)
-AC_CONFIG_FILES([Makefile src/Makefile src/test/Makefile src/qt/Makefile src/qt/test/Makefile share/setup.nsi share/qt/Info.plist])
+AC_CONFIG_FILES([Makefile src/Makefile share/setup.nsi share/qt/Info.plist])
AC_CONFIG_FILES([qa/pull-tester/run-bitcoind-for-test.sh],[chmod +x qa/pull-tester/run-bitcoind-for-test.sh])
AC_CONFIG_FILES([qa/pull-tester/build-tests.sh],[chmod +x qa/pull-tester/build-tests.sh])
AC_OUTPUT
diff --git a/contrib/bitrpc/bitrpc.py b/contrib/bitrpc/bitrpc.py
index a84d7e34dd..02577b1b6a 100644
--- a/contrib/bitrpc/bitrpc.py
+++ b/contrib/bitrpc/bitrpc.py
@@ -22,6 +22,18 @@ if cmd == "backupwallet":
print access.backupwallet(path)
except:
print "\n---An error occurred---\n"
+
+elif cmd == "encryptwallet":
+ try:
+ pwd = getpass.getpass(prompt="Enter passphrase: ")
+ pwd2 = getpass.getpass(prompt="Repeat passphrase: ")
+ if pwd == pwd2:
+ access.encryptwallet(pwd)
+ print "\n---Wallet encrypted. Server stopping, restart to run with encrypted wallet---\n"
+ else:
+ print "\n---Passphrases do not match---\n"
+ except:
+ print "\n---An error occurred---\n"
elif cmd == "getaccount":
try:
diff --git a/contrib/debian/control b/contrib/debian/control
index 9e006a7070..a04e88d4e1 100644
--- a/contrib/debian/control
+++ b/contrib/debian/control
@@ -6,6 +6,7 @@ Uploaders: Micah Anderson <micah@debian.org>
Build-Depends: debhelper,
devscripts,
automake,
+ libtool,
bash-completion,
libboost-system-dev (>> 1.35) | libboost-system1.35-dev,
libdb4.8++-dev,
diff --git a/contrib/debian/examples/bitcoin.conf b/contrib/debian/examples/bitcoin.conf
index 10ec36ae7e..0aa8674af9 100644
--- a/contrib/debian/examples/bitcoin.conf
+++ b/contrib/debian/examples/bitcoin.conf
@@ -1,79 +1,110 @@
-# bitcoin.conf configuration file. Lines beginning with # are comments.
-
-
+##
+## bitcoin.conf configuration file. Lines beginning with # are comments.
+##
+
# Network-related settings:
# Run on the test network instead of the real bitcoin network.
-#testnet=1
+#testnet=0
+
+# Run a regression test network
+#regtest=0
# Connect via a socks4 proxy
#proxy=127.0.0.1:9050
+##############################################################
+## Quick Primer on addnode vs connect ##
+## Let's say for instance you use addnode=4.2.2.4 ##
+## addnode will connect you to and tell you about the ##
+## nodes connected to 4.2.2.4. In addition it will tell ##
+## the other nodes connected to it that you exist so ##
+## they can connect to you. ##
+## connect will not do the above when you 'connect' to it. ##
+## It will *only* connect you to 4.2.2.4 and no one else.##
+## ##
+## So if you're behind a firewall, or have other problems ##
+## finding nodes, add some using 'addnode'. ##
+## ##
+## If you want to stay private, use 'connect' to only ##
+## connect to "trusted" nodes. ##
+## ##
+## If you run multiple nodes on a LAN, there's no need for ##
+## all of them to open lots of connections. Instead ##
+## 'connect' them all to one node that is port forwarded ##
+## and has lots of connections. ##
+## Thanks goes to [Noodle] on Freenode. ##
+##############################################################
+
# Use as many addnode= settings as you like to connect to specific peers
#addnode=69.164.218.197
#addnode=10.0.0.2:8333
-# ... or use as many connect= settings as you like to connect ONLY
-# to specific peers:
+# Alternatively use as many connect= settings as you like to connect ONLY to specific peers
#connect=69.164.218.197
#connect=10.0.0.1:8333
+# Listening mode, enabled by default except when 'connect' is being used
+#listen=1
+
# Maximum number of inbound+outbound connections.
#maxconnections=
-
+#
# JSON-RPC options (for controlling a running Bitcoin/bitcoind process)
+#
-# server=1 tells Bitcoin to accept JSON-RPC commands.
-#server=1
+# server=1 tells Bitcoin-QT and bitcoind to accept JSON-RPC commands
+#server=0
# You must set rpcuser and rpcpassword to secure the JSON-RPC api
#rpcuser=Ulysseys
-#rpcpassword=YourSuperGreatPasswordNumber_385593
+#rpcpassword=YourSuperGreatPasswordNumber_DO_NOT_USE_THIS_OR_YOU_WILL_GET_ROBBED_385593
+
+# How many seconds bitcoin will wait for a complete RPC HTTP request.
+# after the HTTP connection is established.
+#rpctimeout=30
-# By default, only RPC connections from localhost are allowed. Specify
-# as many rpcallowip= settings as you like to allow connections from
-# other hosts (and you may use * as a wildcard character):
-#rpcallowip=10.1.1.34
-#rpcallowip=192.168.1.*
+# By default, only RPC connections from localhost are allowed.
+# Specify as many rpcallowip= settings as you like to allow connections from other hosts,
+# either as a single IPv4/IPv6 or with a subnet specification.
+
+# NOTE: opening up the RPC port to hosts outside your local trusted network is NOT RECOMMENDED,
+# because the rpcpassword is transmitted over the network unencrypted.
+
+# server=1 tells Bitcoin-QT to accept JSON-RPC commands.
+# it is also read by bitcoind to determine if RPC should be enabled
+#rpcallowip=10.1.1.34/255.255.255.0
+#rpcallowip=1.2.3.4/24
+#rpcallowip=2001:db8:85a3:0:0:8a2e:370:7334/96
# Listen for RPC connections on this TCP port:
-rpcport=8332
+#rpcport=8332
# You can use Bitcoin or bitcoind to send commands to Bitcoin/bitcoind
# running on another host using this option:
-rpcconnect=127.0.0.1
+#rpcconnect=127.0.0.1
# Use Secure Sockets Layer (also known as TLS or HTTPS) to communicate
# with Bitcoin -server or bitcoind
#rpcssl=1
# OpenSSL settings used when rpcssl=1
-rpcsslciphers=TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH
-rpcsslcertificatechainfile=server.cert
-rpcsslprivatekeyfile=server.pem
+#rpcsslciphers=TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH
+#rpcsslcertificatechainfile=server.cert
+#rpcsslprivatekeyfile=server.pem
# Miscellaneous options
-# Set gen=1 to attempt to generate bitcoins
-gen=0
-
-# Use SSE instructions to try to generate bitcoins faster.
-#4way=1
-
# Pre-generate this many public/private key pairs, so wallet backups will be valid for
# both prior transactions and several dozen future transactions.
-keypool=100
+#keypool=100
# Pay an optional transaction fee every time you send bitcoins. Transactions with fees
# are more likely than free transactions to be included in generated blocks, so may
# be validated sooner.
-paytxfee=0.00
-
-# Allow direct connections for the 'pay via IP address' feature.
-#allowreceivebyip=1
-
+#paytxfee=0.00
# User interface options
diff --git a/contrib/debian/manpages/bitcoin-qt.1 b/contrib/debian/manpages/bitcoin-qt.1
index cd478b1875..25a423f9c4 100644
--- a/contrib/debian/manpages/bitcoin-qt.1
+++ b/contrib/debian/manpages/bitcoin-qt.1
@@ -139,6 +139,9 @@ Execute command when the best block changes (%s in cmd is replaced by block hash
\fB\-walletnotify=\fR<cmd>
Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)
.TP
+\fB\-respendnotify=\fR<cmd>
+Execute command when a network tx respends wallet tx input (%s=respend TxID, %t=wallet TxID)
+.TP
\fB\-alertnotify=\fR<cmd>
Execute command when a relevant alert is received (%s in cmd is replaced by message)
.TP
diff --git a/contrib/gitian-descriptors/deps-linux.yml b/contrib/gitian-descriptors/deps-linux.yml
index af10461b83..8221222133 100644
--- a/contrib/gitian-descriptors/deps-linux.yml
+++ b/contrib/gitian-descriptors/deps-linux.yml
@@ -16,7 +16,7 @@ packages:
reference_datetime: "2013-06-01 00:00:00"
remotes: []
files:
-- "openssl-1.0.1g.tar.gz"
+- "openssl-1.0.1h.tar.gz"
- "miniupnpc-1.9.tar.gz"
- "qrencode-3.4.3.tar.bz2"
- "protobuf-2.5.0.tar.bz2"
@@ -30,15 +30,15 @@ script: |
export TZ=UTC
export LIBRARY_PATH="$STAGING/lib"
# Integrity Check
- echo "53cb818c3b90e507a8348f4f5eaedb05d8bfe5358aabb508b7263cc670c3e028 openssl-1.0.1g.tar.gz" | sha256sum -c
+ echo "9d1c8a9836aa63e2c6adb684186cbd4371c9e9dcc01d6e3bb447abf2d4d3d093 openssl-1.0.1h.tar.gz" | sha256sum -c
echo "2923e453e880bb949e3d4da9f83dd3cb6f08946d35de0b864d0339cf70934464 miniupnpc-1.9.tar.gz" | sha256sum -c
echo "dfd71487513c871bad485806bfd1fdb304dedc84d2b01a8fb8e0940b50597a98 qrencode-3.4.3.tar.bz2" | sha256sum -c
echo "13bfc5ae543cf3aa180ac2485c0bc89495e3ae711fc6fab4f8ffe90dfb4bb677 protobuf-2.5.0.tar.bz2" | sha256sum -c
echo "12edc0df75bf9abd7f82f821795bcee50f42cb2e5f76a6a281b85732798364ef db-4.8.30.NC.tar.gz" | sha256sum -c
#
- tar xzf openssl-1.0.1g.tar.gz
- cd openssl-1.0.1g
+ tar xzf openssl-1.0.1h.tar.gz
+ cd openssl-1.0.1h
# need -fPIC to avoid relocation error in 64 bit builds
./config no-shared no-zlib no-dso no-krb5 --openssldir=$STAGING -fPIC
# need to build OpenSSL with faketime because a timestamp is embedded into cversion.o
@@ -95,4 +95,4 @@ script: |
done
#
cd $STAGING
- find include lib bin host | sort | zip -X@ $OUTDIR/bitcoin-deps-linux${GBUILD_BITS}-gitian-r5.zip
+ find include lib bin host | sort | zip -X@ $OUTDIR/bitcoin-deps-linux${GBUILD_BITS}-gitian-r6.zip
diff --git a/contrib/gitian-descriptors/deps-win.yml b/contrib/gitian-descriptors/deps-win.yml
index 17ac413d80..fabc2949eb 100644
--- a/contrib/gitian-descriptors/deps-win.yml
+++ b/contrib/gitian-descriptors/deps-win.yml
@@ -14,7 +14,7 @@ packages:
reference_datetime: "2011-01-30 00:00:00"
remotes: []
files:
-- "openssl-1.0.1g.tar.gz"
+- "openssl-1.0.1h.tar.gz"
- "db-4.8.30.NC.tar.gz"
- "miniupnpc-1.9.tar.gz"
- "zlib-1.2.8.tar.gz"
@@ -28,7 +28,7 @@ script: |
INDIR=$HOME/build
TEMPDIR=$HOME/tmp
# Input Integrity Check
- echo "53cb818c3b90e507a8348f4f5eaedb05d8bfe5358aabb508b7263cc670c3e028 openssl-1.0.1g.tar.gz" | sha256sum -c
+ echo "9d1c8a9836aa63e2c6adb684186cbd4371c9e9dcc01d6e3bb447abf2d4d3d093 openssl-1.0.1h.tar.gz" | sha256sum -c
echo "12edc0df75bf9abd7f82f821795bcee50f42cb2e5f76a6a281b85732798364ef db-4.8.30.NC.tar.gz" | sha256sum -c
echo "2923e453e880bb949e3d4da9f83dd3cb6f08946d35de0b864d0339cf70934464 miniupnpc-1.9.tar.gz" | sha256sum -c
echo "36658cb768a54c1d4dec43c3116c27ed893e88b02ecfcb44f2166f9c0b7f2a0d zlib-1.2.8.tar.gz" | sha256sum -c
@@ -48,8 +48,8 @@ script: |
mkdir -p $INSTALLPREFIX $BUILDDIR
cd $BUILDDIR
#
- tar xzf $INDIR/openssl-1.0.1g.tar.gz
- cd openssl-1.0.1g
+ tar xzf $INDIR/openssl-1.0.1h.tar.gz
+ cd openssl-1.0.1h
if [ "$BITS" == "32" ]; then
OPENSSL_TGT=mingw
else
@@ -124,5 +124,5 @@ script: |
done
#
cd $INSTALLPREFIX
- find include lib | sort | zip -X@ $OUTDIR/bitcoin-deps-win$BITS-gitian-r12.zip
+ find include lib | sort | zip -X@ $OUTDIR/bitcoin-deps-win$BITS-gitian-r13.zip
done # for BITS in
diff --git a/contrib/gitian-descriptors/gitian-linux.yml b/contrib/gitian-descriptors/gitian-linux.yml
index bb59e1cecb..65a6c3c1e9 100644
--- a/contrib/gitian-descriptors/gitian-linux.yml
+++ b/contrib/gitian-descriptors/gitian-linux.yml
@@ -25,8 +25,8 @@ remotes:
- "url": "https://github.com/bitcoin/bitcoin.git"
"dir": "bitcoin"
files:
-- "bitcoin-deps-linux32-gitian-r5.zip"
-- "bitcoin-deps-linux64-gitian-r5.zip"
+- "bitcoin-deps-linux32-gitian-r6.zip"
+- "bitcoin-deps-linux64-gitian-r6.zip"
- "boost-linux32-1.55.0-gitian-r1.zip"
- "boost-linux64-1.55.0-gitian-r1.zip"
- "qt-linux32-4.6.4-gitian-r1.tar.gz"
@@ -43,7 +43,7 @@ script: |
#
mkdir -p $STAGING
cd $STAGING
- unzip ../build/bitcoin-deps-linux${GBUILD_BITS}-gitian-r5.zip
+ unzip ../build/bitcoin-deps-linux${GBUILD_BITS}-gitian-r6.zip
unzip ../build/boost-linux${GBUILD_BITS}-1.55.0-gitian-r1.zip
tar -zxf ../build/qt-linux${GBUILD_BITS}-4.6.4-gitian-r1.tar.gz
cd ../build
diff --git a/contrib/gitian-descriptors/gitian-osx-bitcoin.yml b/contrib/gitian-descriptors/gitian-osx-bitcoin.yml
index aea4b93a1f..bc3d561c35 100644
--- a/contrib/gitian-descriptors/gitian-osx-bitcoin.yml
+++ b/contrib/gitian-descriptors/gitian-osx-bitcoin.yml
@@ -11,39 +11,35 @@ packages:
- "bsdmainutils"
- "pkg-config"
- "p7zip-full"
+- "libtool"
reference_datetime: "2013-06-01 00:00:00"
remotes:
- "url": "https://github.com/bitcoin/bitcoin.git"
"dir": "bitcoin"
files:
-- "osx-native-depends-r2.tar.gz"
-- "osx-depends-r2.tar.gz"
-- "osx-depends-qt-5.2.1-r2.tar.gz"
-- "MacOSX10.6.pkg"
+- "osx-native-depends-r3.tar.gz"
+- "osx-depends-r4.tar.gz"
+- "osx-depends-qt-5.2.1-r4.tar.gz"
+- "MacOSX10.7.sdk.tar.gz"
script: |
- echo "a2ccf2299de4e0bb88bd17a3355f02b747575b97492c7c2f5b789a64ccc4cbd6 MacOSX10.6.pkg" | sha256sum -c
-
HOST=x86_64-apple-darwin11
PREFIX=`pwd`/osx-cross-depends/prefix
- SDK=`pwd`/osx-cross-depends/SDKs/MacOSX10.6.sdk
+ SDK=`pwd`/osx-cross-depends/SDKs/MacOSX10.7.sdk
NATIVEPREFIX=`pwd`/osx-cross-depends/native-prefix
export TAR_OPTIONS="-m --mtime="$REFERENCE_DATE\\\ $REFERENCE_TIME""
export SOURCES_PATH=`pwd`
- mkdir osx-cross-depends
+ mkdir -p osx-cross-depends/SDKs
- cd osx-cross-depends
- mkdir -p SDKs
- 7z -bd -so -y e ${SOURCES_PATH}/MacOSX10.6.pkg Payload | gzip -d -c | cpio -i
- cd ..
+ tar -C osx-cross-depends/SDKs -xf ${SOURCES_PATH}/MacOSX10.7.sdk.tar.gz
- tar -C osx-cross-depends -xf osx-native-depends-r2.tar.gz
- tar -C osx-cross-depends -xf osx-depends-r2.tar.gz
- tar -C osx-cross-depends -xf osx-depends-qt-5.2.1-r2.tar.gz
+ tar -C osx-cross-depends -xf osx-native-depends-r3.tar.gz
+ tar -C osx-cross-depends -xf osx-depends-r4.tar.gz
+ tar -C osx-cross-depends -xf osx-depends-qt-5.2.1-r4.tar.gz
export PATH=`pwd`/osx-cross-depends/native-prefix/bin:$PATH
cd bitcoin
diff --git a/contrib/gitian-descriptors/gitian-osx-depends.yml b/contrib/gitian-descriptors/gitian-osx-depends.yml
index 8e91a30ded..07a021cf0c 100644
--- a/contrib/gitian-descriptors/gitian-osx-depends.yml
+++ b/contrib/gitian-descriptors/gitian-osx-depends.yml
@@ -15,23 +15,22 @@ files:
- "boost_1_55_0.tar.bz2"
- "db-4.8.30.NC.tar.gz"
- "miniupnpc-1.9.tar.gz"
-- "openssl-1.0.1g.tar.gz"
+- "openssl-1.0.1h.tar.gz"
- "protobuf-2.5.0.tar.bz2"
- "qrencode-3.4.3.tar.bz2"
-- "MacOSX10.6.pkg"
-- "osx-native-depends-r2.tar.gz"
+- "MacOSX10.7.sdk.tar.gz"
+- "osx-native-depends-r3.tar.gz"
script: |
echo "fff00023dd79486d444c8e29922f4072e1d451fc5a4d2b6075852ead7f2b7b52 boost_1_55_0.tar.bz2" | sha256sum -c
echo "12edc0df75bf9abd7f82f821795bcee50f42cb2e5f76a6a281b85732798364ef db-4.8.30.NC.tar.gz" | sha256sum -c
echo "2923e453e880bb949e3d4da9f83dd3cb6f08946d35de0b864d0339cf70934464 miniupnpc-1.9.tar.gz" | sha256sum -c
- echo "53cb818c3b90e507a8348f4f5eaedb05d8bfe5358aabb508b7263cc670c3e028 openssl-1.0.1g.tar.gz" | sha256sum -c
+ echo "9d1c8a9836aa63e2c6adb684186cbd4371c9e9dcc01d6e3bb447abf2d4d3d093 openssl-1.0.1h.tar.gz" | sha256sum -c
echo "13bfc5ae543cf3aa180ac2485c0bc89495e3ae711fc6fab4f8ffe90dfb4bb677 protobuf-2.5.0.tar.bz2" | sha256sum -c
echo "dfd71487513c871bad485806bfd1fdb304dedc84d2b01a8fb8e0940b50597a98 qrencode-3.4.3.tar.bz2" | sha256sum -c
- echo "a2ccf2299de4e0bb88bd17a3355f02b747575b97492c7c2f5b789a64ccc4cbd6 MacOSX10.6.pkg" | sha256sum -c
- REVISION=r2
+ REVISION=r4
export SOURCES_PATH=`pwd`
export TAR_OPTIONS="-m --mtime="$REFERENCE_DATE\\\ $REFERENCE_TIME""
export PATH=$HOME:$PATH
@@ -44,7 +43,7 @@ script: |
PREFIX=`pwd`/prefix
NATIVEPREFIX=`pwd`/native-prefix
BUILD_BASE=`pwd`/build
- SDK=`pwd`/SDKs/MacOSX10.6.sdk
+ SDK=`pwd`/SDKs/MacOSX10.7.sdk
HOST=x86_64-apple-darwin11
MIN_VERSION=10.6
@@ -70,10 +69,10 @@ script: |
mkdir -p ${PREFIX}/lib
mkdir -p ${BUILD_BASE}
- mkdir -p ${SDK}
- 7z -bd -so -y e ${SOURCES_PATH}/MacOSX10.6.pkg Payload | gzip -d -c | cpio -i
+ mkdir -p SDKs
+ tar -C SDKs -xf ${SOURCES_PATH}/MacOSX10.7.sdk.tar.gz
- tar xf /home/ubuntu/build/osx-native-depends-r2.tar.gz
+ tar xf /home/ubuntu/build/osx-native-depends-r3.tar.gz
# bdb
SOURCE_FILE=${SOURCES_PATH}/db-4.8.30.NC.tar.gz
@@ -89,8 +88,8 @@ script: |
popd
# openssl
- SOURCE_FILE=${SOURCES_PATH}/openssl-1.0.1g.tar.gz
- BUILD_DIR=${BUILD_BASE}/openssl-1.0.1g
+ SOURCE_FILE=${SOURCES_PATH}/openssl-1.0.1h.tar.gz
+ BUILD_DIR=${BUILD_BASE}/openssl-1.0.1h
tar -C ${BUILD_BASE} -xf ${SOURCE_FILE}
pushd ${BUILD_DIR}
diff --git a/contrib/gitian-descriptors/gitian-osx-native.yml b/contrib/gitian-descriptors/gitian-osx-native.yml
index 6040e5ac5b..a753ad704f 100644
--- a/contrib/gitian-descriptors/gitian-osx-native.yml
+++ b/contrib/gitian-descriptors/gitian-osx-native.yml
@@ -24,7 +24,7 @@ files:
- "dyld-195.5.tar.gz"
- "ld64-127.2.tar.gz"
- "protobuf-2.5.0.tar.bz2"
-- "MacOSX10.6.pkg"
+- "MacOSX10.7.sdk.tar.gz"
- "cdrkit-1.1.11.tar.gz"
- "libdmg-hfsplus-v0.1.tar.gz"
- "clang-llvm-3.2-x86-linux-ubuntu-12.04.tar.gz"
@@ -38,14 +38,13 @@ script: |
echo "2cf0484c87cf79b606b351a7055a247dae84093ae92c747a74e0cde2c8c8f83c dyld-195.5.tar.gz" | sha256sum -c
echo "97b75547b2bd761306ab3e15ae297f01e7ab9760b922bc657f4ef72e4e052142 ld64-127.2.tar.gz" | sha256sum -c
echo "13bfc5ae543cf3aa180ac2485c0bc89495e3ae711fc6fab4f8ffe90dfb4bb677 protobuf-2.5.0.tar.bz2" | sha256sum -c
- echo "a2ccf2299de4e0bb88bd17a3355f02b747575b97492c7c2f5b789a64ccc4cbd6 MacOSX10.6.pkg" | sha256sum -c
echo "d1c030756ecc182defee9fe885638c1785d35a2c2a297b4604c0e0dcc78e47da cdrkit-1.1.11.tar.gz" | sha256sum -c
echo "6569a02eb31c2827080d7d59001869ea14484c281efab0ae7f2b86af5c3120b3 libdmg-hfsplus-v0.1.tar.gz" | sha256sum -c
echo "b9d57a88f9514fa1f327a1a703756d0c1c960f4c58494a5bd80313245d13ffff clang-llvm-3.2-x86-linux-ubuntu-12.04.tar.gz" | sha256sum -c
echo "cc12bdbd7a09f71cb2a6a3e6ec3e0abe885ca7111c2b47857f5095e5980caf4f cdrkit-deterministic.patch" | sha256sum -c
- REVISION=r2
+ REVISION=r3
export REFERENCE_DATETIME
export TAR_OPTIONS="-m --mtime="$REFERENCE_DATE\\\ $REFERENCE_TIME""
export FAKETIME=$REFERENCE_DATETIME
@@ -78,7 +77,7 @@ script: |
NATIVEPREFIX=`pwd`/native-prefix
BUILD_BASE=`pwd`/build
- SDK=`pwd`/SDKs/MacOSX10.6.sdk
+ SDK=`pwd`/SDKs/MacOSX10.7.sdk
HOST=x86_64-apple-darwin11
MIN_VERSION=10.6
@@ -91,8 +90,8 @@ script: |
mkdir -p ${NATIVEPREFIX}/bin
mkdir -p ${NATIVEPREFIX}/lib
- mkdir -p ${SDK}
- 7z -bd -so -y e ${SOURCES_PATH}/MacOSX10.6.pkg Payload | gzip -d -c | cpio -i
+ mkdir -p SDKs
+ tar -C SDKs -xf ${SOURCES_PATH}/MacOSX10.7.sdk.tar.gz
# Clang
SOURCE_FILE=${SOURCES_PATH}/clang-llvm-3.2-x86-linux-ubuntu-12.04.tar.gz
@@ -112,7 +111,7 @@ script: |
tar -C ${BUILD_BASE} -xf ${SOURCE_FILE}
mkdir -p ${BUILD_DIR}/sdks
pushd ${BUILD_DIR}/sdks;
- ln -sf ${SDK} MacOSX10.6.sdk
+ ln -sf ${SDK} MacOSX10.7.sdk
ln -sf ${SOURCES_PATH}/cctools-809.tar.gz ${BUILD_DIR}/cctools2odcctools/cctools-809.tar.gz
ln -sf ${SOURCES_PATH}/ld64-127.2.tar.gz ${BUILD_DIR}/cctools2odcctools/ld64-127.2.tar.gz
ln -sf ${SOURCES_PATH}/dyld-195.5.tar.gz ${BUILD_DIR}/cctools2odcctools/dyld-195.5.tar.gz
@@ -127,7 +126,7 @@ script: |
sed -i 's/\# Dynamically linked LTO/\t ;\&\n\t linux*)\n# Dynamically linked LTO/' ${BUILD_DIR}/cctools2odcctools/files/configure.ac
cd ${BUILD_DIR}/cctools2odcctools
- ./extract.sh --osxver 10.6
+ ./extract.sh --osxver 10.7
cd odcctools-809
./configure --prefix=${NATIVEPREFIX} --target=${HOST} CFLAGS="${CFLAGS} -I${NATIVEPREFIX}/include -D__DARWIN_UNIX03 -D__STDC_CONSTANT_MACROS -D__STDC_LIMIT_MACROS" LDFLAGS="${LDFLAGS} -Wl,-rpath=\\\$\$ORIGIN/../lib" --with-sysroot=${SDK}
diff --git a/contrib/gitian-descriptors/gitian-osx-qt.yml b/contrib/gitian-descriptors/gitian-osx-qt.yml
index d0be016e68..5e0ad9222a 100644
--- a/contrib/gitian-descriptors/gitian-osx-qt.yml
+++ b/contrib/gitian-descriptors/gitian-osx-qt.yml
@@ -13,16 +13,15 @@ reference_datetime: "2013-06-01 00:00:00"
remotes: []
files:
- "qt-everywhere-opensource-src-5.2.1.tar.gz"
-- "osx-native-depends-r2.tar.gz"
-- "osx-depends-r2.tar.gz"
-- "MacOSX10.6.pkg"
+- "osx-native-depends-r3.tar.gz"
+- "osx-depends-r4.tar.gz"
+- "MacOSX10.7.sdk.tar.gz"
script: |
echo "84e924181d4ad6db00239d87250cc89868484a14841f77fb85ab1f1dbdcd7da1 qt-everywhere-opensource-src-5.2.1.tar.gz" | sha256sum -c
- echo "a2ccf2299de4e0bb88bd17a3355f02b747575b97492c7c2f5b789a64ccc4cbd6 MacOSX10.6.pkg" | sha256sum -c
- REVISION=r2
+ REVISION=r4
export SOURCES_PATH=`pwd`
export TAR_OPTIONS="-m --mtime="$REFERENCE_DATE\\\ $REFERENCE_TIME""
export ZERO_AR_DATE=1
@@ -42,7 +41,7 @@ script: |
PREFIX=`pwd`/prefix
NATIVEPREFIX=`pwd`/native-prefix
BUILD_BASE=`pwd`/build
- SDK=`pwd`/SDKs/MacOSX10.6.sdk
+ SDK=`pwd`/SDKs/MacOSX10.7.sdk
HOST=x86_64-apple-darwin11
MIN_VERSION=10.6
@@ -68,18 +67,13 @@ script: |
mkdir -p ${PREFIX}/lib
mkdir -p ${BUILD_BASE}
- mkdir -p ${SDK}
- 7z -bd -so -y e ${SOURCES_PATH}/MacOSX10.6.pkg Payload | gzip -d -c | cpio -i
-
- tar xf /home/ubuntu/build/osx-native-depends-r2.tar.gz
-
-
mkdir -p SDKs
- 7z -bd -so -y e ${SOURCES_PATH}/MacOSX10.6.pkg Payload | gzip -d -c | cpio -i
+ tar -C SDKs -xf ${SOURCES_PATH}/MacOSX10.7.sdk.tar.gz
+
+ tar xf /home/ubuntu/build/osx-native-depends-r3.tar.gz
- tar xf /home/ubuntu/build/osx-native-depends-r2.tar.gz
export PATH=`pwd`/native-prefix/bin:$PATH
- tar xf /home/ubuntu/build/osx-depends-r2.tar.gz
+ tar xf /home/ubuntu/build/osx-depends-r4.tar.gz
SOURCE_FILE=${SOURCES_PATH}/qt-everywhere-opensource-src-5.2.1.tar.gz
BUILD_DIR=${BUILD_BASE}/qt-everywhere-opensource-src-5.2.1
diff --git a/contrib/gitian-descriptors/gitian-win.yml b/contrib/gitian-descriptors/gitian-win.yml
index 2191fb36c7..245f15ccab 100644
--- a/contrib/gitian-descriptors/gitian-win.yml
+++ b/contrib/gitian-descriptors/gitian-win.yml
@@ -26,8 +26,8 @@ files:
- "qt-win64-5.2.0-gitian-r3.zip"
- "boost-win32-1.55.0-gitian-r6.zip"
- "boost-win64-1.55.0-gitian-r6.zip"
-- "bitcoin-deps-win32-gitian-r12.zip"
-- "bitcoin-deps-win64-gitian-r12.zip"
+- "bitcoin-deps-win32-gitian-r13.zip"
+- "bitcoin-deps-win64-gitian-r13.zip"
- "protobuf-win32-2.5.0-gitian-r4.zip"
- "protobuf-win64-2.5.0-gitian-r4.zip"
script: |
@@ -61,7 +61,7 @@ script: |
cd $STAGING
unzip $INDIR/qt-win${BITS}-5.2.0-gitian-r3.zip
unzip $INDIR/boost-win${BITS}-1.55.0-gitian-r6.zip
- unzip $INDIR/bitcoin-deps-win${BITS}-gitian-r12.zip
+ unzip $INDIR/bitcoin-deps-win${BITS}-gitian-r13.zip
unzip $INDIR/protobuf-win${BITS}-2.5.0-gitian-r4.zip
if [ "$NEEDDIST" == "1" ]; then
# Make source code archive which is architecture independent so it only needs to be done once
diff --git a/contrib/gitian-descriptors/qt-linux.yml b/contrib/gitian-descriptors/qt-linux.yml
index 1462df3289..b163b4bb8c 100644
--- a/contrib/gitian-descriptors/qt-linux.yml
+++ b/contrib/gitian-descriptors/qt-linux.yml
@@ -40,6 +40,7 @@ script: |
tar xzf qt-everywhere-opensource-src-4.6.4.tar.gz
cd qt-everywhere-opensource-src-4.6.4
QTBUILDDIR=$(pwd)
+ sed 's/TODAY=`date +%Y-%m-%d`/TODAY=2011-01-30/' -i configure
# Need to build 4.6-versioned host utilities as well (lrelease/qrc/lupdate/...)
./configure -prefix $INSTALLPREFIX -confirm-license -release -opensource -no-qt3support -no-multimedia -no-audio-backend -no-phonon -no-phonon-backend -no-declarative -no-script -no-scripttools -no-javascript-jit -no-webkit -no-svg -no-xmlpatterns -no-sql-sqlite -no-nis -no-cups -no-iconv -no-dbus -no-gif -no-libtiff -no-opengl -nomake examples -nomake demos -nomake docs
diff --git a/contrib/gitian-descriptors/qt-win.yml b/contrib/gitian-descriptors/qt-win.yml
index 8f24492b53..7000c70051 100644
--- a/contrib/gitian-descriptors/qt-win.yml
+++ b/contrib/gitian-descriptors/qt-win.yml
@@ -15,8 +15,8 @@ reference_datetime: "2011-01-30 00:00:00"
remotes: []
files:
- "qt-everywhere-opensource-src-5.2.0.tar.gz"
-- "bitcoin-deps-win32-gitian-r12.zip"
-- "bitcoin-deps-win64-gitian-r12.zip"
+- "bitcoin-deps-win32-gitian-r13.zip"
+- "bitcoin-deps-win64-gitian-r13.zip"
script: |
# Defines
export TZ=UTC
@@ -48,7 +48,7 @@ script: |
#
# Need mingw-compiled openssl from bitcoin-deps:
cd $DEPSDIR
- unzip $INDIR/bitcoin-deps-win${BITS}-gitian-r12.zip
+ unzip $INDIR/bitcoin-deps-win${BITS}-gitian-r13.zip
#
cd $BUILDDIR
#
diff --git a/contrib/gitian-downloader/cfields-key.pgp b/contrib/gitian-downloader/cfields-key.pgp
new file mode 100644
index 0000000000..6b0bd240ba
--- /dev/null
+++ b/contrib/gitian-downloader/cfields-key.pgp
@@ -0,0 +1,52 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v1.4.12 (GNU/Linux)
+
+mQINBFOHTh4BEADdKsRvmNhX+B+bcPsgMkp8ztwJA5g/rmrOlHQpKOOf4P2tAr6w
+FmXCChWF9Iq3pDFQ0t0iq5rgisFPyrGVT/VToMmH+/PSLTyIdAlgkRYDMAPsMAFV
+MaADH4yiAgJ3cdXtysjaNQV5O25ypqq6/obUjZJD5Enn6b/UgHe2+7LTmTNsskOx
+5s/WPPht79EY1kM4JQfmDx68CsmqeSAlT6yeO3RQcLn/l46cfXiwzMO4h1hsZS1r
+pgciRp0EHK9uAjF2rjqt8v4SDxwyTnwfpBBulzvH9mBf+HRXWzoTMR4sC/oOZext
+hKAH/ex47BxN3HU3ftNhCK2c1xcU1UOGSjbf0RdbwuSCxxa7mktEDumvOxAk9EBB
++PDPv7jO1FBK3rsJdscYQIL0AiRyO49VfNLARa34OqUi8pOAxKBQ9plO02W1gp7a
+DVBPI05TZ46Y8dTR2Bc1raAgOyxnXM7jfiQG2gSULiKAJAI4HwOiodaiiHAxDaIo
+a3mtsmfN25TZUQuA0I0BvHbJvLRlVnyZm3XVOcwReKJpZJV4qRhd3XNrERZdz6ZK
+cAZnyC/X+Uzo4HfnVSsJk1GpIa4seYyrVCFfHMiAA6SkgAUFbV26KCOv4rNR2GlV
+l2fVhu1RKOEUJ8nRcEqf93SehRVYdI67LepIPgmIwi0KG4HhoTbIHDAKWQARAQAB
+tCtDb3J5IEZpZWxkcyA8Y2ZpZWxkc0BiaXRjb2luZm91bmRhdGlvbi5vcmc+iQI4
+BBMBAgAiBQJTh04eAhsDBgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAAKCRAcJJH/
+6w73cBTiEADIGZSueBFmaOTJCgasKGguHns/n8P94EQBZr07rrgN99Rzp85WvDUN
+Qa72wj3GNcAffN7aZlIWv4g+fjyr9AzHekjI/7iwwSYIfjfTR/xRUW7czRfKAOrK
+iwpEzgv440i7PBvkS/AhNdUNkm+cJvaQUej/F2/O52qDLEpHuzvjAUUWlSeF9/oO
+AjM9dfC24L5k5cVwQvH9noxk3EyuE7BuiGE5a+kKiORrtxiHeUG6GYQxuqrPucLU
+fI67ETyXa0YSpYm5/O65BKMTMpmkMvv1JC2kqqsYTrO5p158CrKzq2xvpuG4ABsb
+9KwICUGW31Ndr6TXwQJFa1b7VK4G1g6M1DFkVTOLJnEyOwgYxsXrV5QFpzpAOAji
+6KcxNGeow1avAFYbqjjLgu9UNuq6b8du13hjkQxVs2NAP1Kd/u2ADwxQHMhZGVEC
+9LIcLVSP9ShY6fR8m6fwSlJfpiV81uLNVD8KIyvp+pYTQ/FnxoPhPIwalYquBZKi
+0u38igW75IzZ0fYvJgTumE/8ofSVkutVtrQb21eJclVrJGMNweTlJcJhAWdKkjDC
+e6mSj8GItKV1ef+eusXSzs/wPyTaqgkELvvAOZdwUq3kobQErE5HOuPEOvcwuY96
+DcxLexirCGW5wCUq7Db0c0dUjQwzzb5OTW2jdnPVR0qxi29TnOJ2aLkCDQRTh04e
+ARAAuJKpI6NTCQrjEqe9AYywN8676+fPS5bqXkyb/iub6MXeQdwpH0K42lXAaYMq
+ow/0aLlvGWCHuJJGozoOWpTzQ+VPbhpdARoLCop5fYTpy8Q17ubLeeODDtr6jtDN
+lmg+9PBIErIVUnUS2wNZuJRVsfwlLaU3T2v8kQnQ6AEbl/QwyWW9nB8rAWBu6Hvs
+VdtcBmtHSr9xAGBGfW6rSVhTitikR4lWJPdNJxI3pLaswpLIUIQ1rssKO4glljcp
+C6nhMvRkDLvDFvDP9QnmwY/A4ch5S6ANPrhOjQuu9njjQ+/ImrJTjAXqHwg5KdTc
+NKxufgvi9elOQ422o0No3yKdRoRA4kdcUmqA9gNZDyX0ZTd17aNqc42Zt3aYLJ11
+bLZZp0qnfhkmhbsBZZtaLNkuF+RGPWysxY7KPMm+nHn6f3Wpr18E+T02wi02r4nS
+HOQI+gppDqy3Vq3ZZNoUZynctiLZVHkqi+WYXqfD2tEn8UJKpht7jrZlNgkHFgT7
+T0/U4+JmaQ/HltE+IexAIH0GP0Jt6hmRoZimdoy8Q8NY5t/fn9CQNJm5InrHvooN
+aFmZMvzGTGiTqBqnA/7k9FCUEG98LK11MsIssY8YE/F6HD69R3ISyRvhUbpFvhD8
+c6zOkEKngTWvyRevrDrDz2yoZ1+T1X350+92rbEc/8WyutcAEQEAAYkCHwQYAQIA
+CQUCU4dOHgIbDAAKCRAcJJH/6w73cAakEACv4EUEjtFjqnGB0Lru5FKs1obWcf37
+c4a5yYvOw58dkEZ9hsq34qWGLT128n6R24KEG+3O4CbplAD5Kt2eAPracbPHMAn8
+TGmC+KjiGlBR5xCY9dD0fn5EbRWOa+Fdcj1DpneaqMl9vLnBbqGp7pa/MwSOc+FB
+0Ms2rcGJJMNHgITfP22eCf6pvf/xq7kKbUJ3Kjqdc2hWlRMjC/OOeITdrgycfDk/
+AOzLNqk5q7bYOxna6rWDLGSkCATyQKaBTVK7wRd1VrIhI4vfFqy+BWYXyXJ0pxjS
+eaCDwbWHX/KW+0qLsmHxFMAyHJPjs8LEwK/DRbmWhe1HzPcBKmpyjqlkuxPjAdSl
+hP4+IBvVNLf2Kh3uFHehk9A6oCYZGe3lLfQnOxIantXF7IROTmiZZsb+08w6cIXE
++r6kWG6vP2aCVtzYNfY+2p5xfg3yMxcxENJki1WSCOq6WVf9IWFzSJu+0+eazD3L
+3QpZoSX5VvT6x05C0Ay1ert0Q5MyF84Eh8mDqL4PhpWtQhZMp8SG4jqFVgrhM4sl
+vWGYXGns4tbnNPiiksjBD8TTvG3+mt48sNJIpHThjdWJSZjllYG7jV8oi7HrX8M2
+LOwWWLYxHkqi9wpmrWHSmniex6ABozcqrb+EgSMnHuSd7glmOJxHToJIudJbKG5D
+MrD0ofsytfy1LQ==
+=DE4h
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/contrib/gitian-downloader/linux-download-config b/contrib/gitian-downloader/linux-download-config
index b5e0561aa3..f5e6382b84 100644
--- a/contrib/gitian-downloader/linux-download-config
+++ b/contrib/gitian-downloader/linux-download-config
@@ -37,3 +37,6 @@ signers:
E944AE667CF960B1004BC32FCA662BE18B877A60:
name: "Andreas Schildbach"
key: aschildbach
+ C060A6635913D98A3587D7DB1C2491FFEB0EF770:
+ name: "Cory Fields"
+ key: "cfields"
diff --git a/contrib/gitian-downloader/win32-download-config b/contrib/gitian-downloader/win32-download-config
index 5d56db863e..06c164180d 100644
--- a/contrib/gitian-downloader/win32-download-config
+++ b/contrib/gitian-downloader/win32-download-config
@@ -37,3 +37,6 @@ signers:
E944AE667CF960B1004BC32FCA662BE18B877A60:
name: "Andreas Schildbach"
key: aschildbach
+ C060A6635913D98A3587D7DB1C2491FFEB0EF770:
+ name: "Cory Fields"
+ key: "cfields"
diff --git a/contrib/macdeploy/README.md b/contrib/macdeploy/README.md
index 5f0611f20c..0aa57b4777 100644
--- a/contrib/macdeploy/README.md
+++ b/contrib/macdeploy/README.md
@@ -1,9 +1,5 @@
### MacDeploy ###
-You will need the appscript package for the fancy disk image creation to work:
-
- sudo easy_install appscript
-
For Snow Leopard (which uses [Python 2.6](http://www.python.org/download/releases/2.6/)), you will need the param_parser package:
sudo easy_install argparse
diff --git a/contrib/macdeploy/macdeployqtplus b/contrib/macdeploy/macdeployqtplus
index 599713fbbb..ce4169a410 100755
--- a/contrib/macdeploy/macdeployqtplus
+++ b/contrib/macdeploy/macdeployqtplus
@@ -19,7 +19,6 @@
import subprocess, sys, re, os, shutil, stat, os.path
from string import Template
-from time import sleep
from argparse import ArgumentParser
# This is ported from the original macdeployqt with modifications
@@ -488,16 +487,6 @@ if len(config.fancy) == 1:
sys.stderr.write("Error: Could not import plistlib which is required for fancy disk images.\n")
sys.exit(1)
- if verbose >= 3:
- print "Fancy: Importing appscript..."
- try:
- import appscript
- except ImportError:
- if verbose >= 1:
- sys.stderr.write("Error: Could not import appscript which is required for fancy disk images.\n")
- sys.stderr.write("Please install it e.g. with \"sudo easy_install appscript\".\n")
- sys.exit(1)
-
p = config.fancy[0]
if verbose >= 3:
print "Fancy: Loading \"%s\"..." % p
diff --git a/contrib/verifysfbinaries/README.md b/contrib/verifysfbinaries/README.md
index f646d1efd1..8c038865bd 100644
--- a/contrib/verifysfbinaries/README.md
+++ b/contrib/verifysfbinaries/README.md
@@ -1,5 +1,5 @@
### Verify SF Binaries ###
-This script attempts to download the signature file `SHA256SUMS.asc` from SourceForge.
+This script attempts to download the signature file `SHA256SUMS.asc` from https://bitcoin.org.
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.
diff --git a/contrib/verifysfbinaries/verify.sh b/contrib/verifysfbinaries/verify.sh
index e92295661c..3eb4693883 100755
--- a/contrib/verifysfbinaries/verify.sh
+++ b/contrib/verifysfbinaries/verify.sh
@@ -1,6 +1,6 @@
#!/bin/bash
-### This script attempts to download the signature file SHA256SUMS.asc from SourceForge
+### This script attempts to download the signature file SHA256SUMS.asc from bitcoin.org
### 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.
@@ -18,11 +18,11 @@ WORKINGDIR="/tmp/bitcoin"
TMPFILE="hashes.tmp"
#this URL is used if a version number is not specified as an argument to the script
-SIGNATUREFILE="http://downloads.sourceforge.net/project/bitcoin/Bitcoin/bitcoin-0.9.0rc1/SHA256SUMS.asc"
+SIGNATUREFILE="https://bitcoin.org/bin/0.9.2.1/SHA256SUMS.asc"
SIGNATUREFILENAME="SHA256SUMS.asc"
RCSUBDIR="test/"
-BASEDIR="http://downloads.sourceforge.net/project/bitcoin/Bitcoin/"
+BASEDIR="https://bitcoin.org/bin/"
VERSIONPREFIX="bitcoin-"
RCVERSIONSTRING="rc"
@@ -62,7 +62,7 @@ WGETOUT=$(wget -N "$BASEDIR$SIGNATUREFILENAME" 2>&1)
#and then see if wget completed successfully
if [ $? -ne 0 ]; then
echo "Error: couldn't fetch signature file. Have you specified the version number in the following format?"
- echo "[bitcoin-]<version>-[rc[0-9]] (example: bitcoin-0.7.1-rc1)"
+ echo "[bitcoin-]<version>-[rc[0-9]] (example: bitcoin-0.9.2-rc1)"
echo "wget output:"
echo "$WGETOUT"|sed 's/^/\t/g'
exit 2
diff --git a/doc/README_osx.txt b/doc/README_osx.txt
index 6eae4f5cf1..2be56c1592 100644
--- a/doc/README_osx.txt
+++ b/doc/README_osx.txt
@@ -37,11 +37,15 @@ originally done in toolchain4.
To complicate things further, all builds must target an Apple SDK. These SDKs
are free to download, but not redistributable.
-To obtain it, register for a developer account, then download xcode_3.2.6_and_ios_sdk_4.3.dmg:
-https://developer.apple.com/devcenter/download.action?path=/Developer_Tools/xcode_3.2.6_and_ios_sdk_4.3__final/xcode_3.2.6_and_ios_sdk_4.3.dmg
-This file is several gigabytes in size, but only a single .pkg file inside is
-needed (MacOSX10.6.pkg). From Linux, 7-zip can be used to extract this file.
-The DMG can then be discarded.
+To obtain it, register for a developer account, then download xcode4630916281a.dmg:
+https://developer.apple.com/downloads/download.action?path=Developer_Tools/xcode_4.6.3/xcode4630916281a.dmg
+This file is several gigabytes in size, but only a single directory inside is
+needed: Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.7.sdk
+
+Unfortunately, the usual linux tools (7zip, hpmount, loopback mount) are incapable of opening this file.
+To create a tarball suitable for gitian input, mount the dmg in OSX, then create it with:
+ $ tar -C /Volumes/Xcode/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/ -czf MacOSX10.7.sdk.tar.gz MacOSX10.7.sdk
+
The gitian descriptors build 2 sets of files: Linux tools, then Apple binaries
which are created using these tools. The build process has been designed to
diff --git a/doc/build-osx.md b/doc/build-osx.md
index 0de5c792e9..bc42723b12 100644
--- a/doc/build-osx.md
+++ b/doc/build-osx.md
@@ -22,7 +22,7 @@ Xcode 4.3 or later, you'll need to install its command line tools. This can
be done in `Xcode > Preferences > Downloads > Components` and generally must
be re-done or updated every time Xcode is updated.
-There's an assumption that you already have `git` installed, as well. If
+There's also an assumption that you already have `git` installed. If
not, it's the path of least resistance to install [Github for Mac](https://mac.github.com/)
(OS X 10.7+) or
[Git for OS X](https://code.google.com/p/git-osx-installer/). It is also
@@ -30,11 +30,8 @@ available via Homebrew or MacPorts.
You will also need to install [Homebrew](http://brew.sh)
or [MacPorts](https://www.macports.org/) in order to install library
-dependencies. It's largely a religious decision which to choose, but, as of
-December 2012, MacPorts is a little easier because you can just install the
-dependencies immediately - no other work required. If you're unsure, read
-the instructions through first in order to assess what you want to do.
-Homebrew is a little more popular among those newer to OS X.
+dependencies. It's largely a religious decision which to choose, however, Homebrew
+is now used for building release versions.
The installation of the actual dependencies is covered in the Instructions
sections below.
@@ -44,9 +41,7 @@ Instructions: MacPorts
### Install dependencies
-Installing the dependencies using MacPorts is very straightforward.
-
- sudo port install boost db48@+no_java openssl miniupnpc autoconf pkgconfig automake
+ sudo port install boost db48@+no_java openssl miniupnpc autoconf pkgconfig automake libtool
Optional: install Qt4
@@ -74,13 +69,13 @@ Instructions: Homebrew
#### Install dependencies using Homebrew
- brew install autoconf automake berkeley-db4 boost miniupnpc openssl pkg-config protobuf qt
+ brew install autoconf automake libtool berkeley-db4 boost miniupnpc openssl pkg-config protobuf qt
Note: After you have installed the dependencies, you should check that the Homebrew installed version of OpenSSL is the one available for compilation. You can check this by typing
openssl version
-into Terminal. You should see OpenSSL 1.0.1f 6 Jan 2014.
+into Terminal. You should see OpenSSL 1.0.1h 5 Jun 2014.
If not, you can ensure that the Homebrew OpenSSL is correctly linked by running
@@ -103,7 +98,7 @@ PATH.
./configure
make
-3. It is a good idea to build and run the unit tests, too:
+3. It is also a good idea to build and run the unit tests:
make check
@@ -131,7 +126,7 @@ For MacPorts, that means editing your macports.conf and setting
... and then uninstalling and re-installing, or simply rebuilding, all ports.
As of December 2012, the `boost` port does not obey `macosx_deployment_target`.
-Download `http://gavinandresen-bitcoin.s3.amazonaws.com/boost_macports_fix.zip`
+Download `https://gavinandresen-bitcoin.s3.amazonaws.com/boost_macports_fix.zip`
for a fix.
Once dependencies are compiled, see release-process.md for how the Bitcoin-Qt.app
@@ -149,13 +144,14 @@ commands:
echo -e "rpcuser=bitcoinrpc\nrpcpassword=$(xxd -l 16 -p /dev/urandom)" > "/Users/${USER}/Library/Application Support/Bitcoin/bitcoin.conf"
chmod 600 "/Users/${USER}/Library/Application Support/Bitcoin/bitcoin.conf"
-When next you run it, it will start downloading the blockchain, but it won't
+The next time you run it, it will start downloading the blockchain, but it won't
output anything while it's doing this. This process may take several hours;
you can monitor its process by looking at the debug.log file, like this:
tail -f $HOME/Library/Application\ Support/Bitcoin/debug.log
Other commands:
+-------
./bitcoind -daemon # to start the bitcoin daemon.
./bitcoin-cli --help # for a list of command-line options.
diff --git a/doc/build-unix.md b/doc/build-unix.md
index ab5fbad521..0f381d56c5 100644
--- a/doc/build-unix.md
+++ b/doc/build-unix.md
@@ -2,6 +2,16 @@ UNIX BUILD NOTES
====================
Some notes on how to build Bitcoin in Unix.
+Note
+---------------------
+Always use absolute paths to configure and compile bitcoin and the dependencies,
+for example, when specifying the the path of the dependency:
+
+ ../dist/configure --enable-cxx --disable-shared --with-pic --prefix=$BDB_PREFIX
+
+Here BDB_PREFIX must absolute path - it is defined using $(pwd) which ensures
+the usage of the absolute path.
+
To Build
---------------------
@@ -51,10 +61,8 @@ Dependency Build Instructions: Ubuntu & Debian
----------------------------------------------
Build requirements:
- sudo apt-get install build-essential
- sudo apt-get install libtool autotools-dev autoconf
- sudo apt-get install libssl-dev
-
+ sudo apt-get install build-essential libtool autotools-dev autoconf pkg-config libssl-dev
+
for Ubuntu 12.04 and later:
sudo apt-get install libboost-all-dev
@@ -83,10 +91,9 @@ To enable the change run
sudo apt-get update
-for other Ubuntu & Debian:
+for other Debian & Ubuntu (with ppa):
- sudo apt-get install libdb4.8-dev
- sudo apt-get install libdb4.8++-dev
+ sudo apt-get install libdb4.8-dev libdb4.8++-dev
Optional:
diff --git a/doc/coding.md b/doc/coding.md
index 69388c9ce2..2f332e92f0 100644
--- a/doc/coding.md
+++ b/doc/coding.md
@@ -4,44 +4,65 @@ Coding
Please be consistent with the existing coding style.
Block style:
-
- bool Function(char* psz, int n)
- {
- // Comment summarising what this section of code does
- for (int i = 0; i < n; i++)
- {
- // When something fails, return early
- if (!Something())
- return false;
- ...
- }
-
- // Success return is usually at the end
- return true;
- }
-
+```c++
+ bool Function(char* psz, int n)
+ {
+ // Comment summarising what this section of code does
+ for (int i = 0; i < n; i++)
+ {
+ // When something fails, return early
+ if (!Something())
+ return false;
+ ...
+ }
+
+ // Success return is usually at the end
+ return true;
+ }
+```
- ANSI/Allman block style
- 4 space indenting, no tabs
- No extra spaces inside parenthesis; please don't do ( this )
- No space after function names, one space after if, for and while
+- Includes need to be ordered alphabetically, separate own and foreign headers with a new-line (example key.cpp):
+```c++
+#include "key.h"
+
+#include "crypto/sha2.h"
+#include "util.h"
+#include <openssl/foo.h>
+```
+- Class or struct keywords in header files need to be ordered alphabetically:
+```c++
+class CAlpha;
+class CBeta;
+```
+- When using namespace keyword use the following form:
+```c++
+namespace Foo {
+
+...
+
+} // Foo
+```
Variable names begin with the type in lowercase, like nSomeVariable.
Please don't put the first word of the variable name in lowercase like
someVariable.
Common types:
- n integer number: short, unsigned short, int, unsigned int, int64, uint64, sometimes char if used as a number
- d double, float
- f flag
- hash uint256
- p pointer or array, one p for each level of indirection
- psz pointer to null terminated string
- str string object
- v vector or similar list objects
- map map or multimap
- set set or multiset
- bn CBigNum
+ n integer number: short, unsigned short, int, unsigned int, int64, uint64, sometimes char if used as a number
+ d double, float
+ f flag
+ hash uint256
+ p pointer or array, one p for each level of indirection
+ psz pointer to null terminated string
+ str string object
+ v vector or similar list objects
+ map map or multimap
+ set set or multiset
+ bn CBigNum
Doxygen comments
-----------------
diff --git a/doc/gitian-building.md b/doc/gitian-building.md
index 544bbc12c1..b356a5d88d 100644
--- a/doc/gitian-building.md
+++ b/doc/gitian-building.md
@@ -4,8 +4,8 @@ Gitian building
*Setup instructions for a gitian build of Bitcoin using a Debian VM or physical system.*
Gitian is the deterministic build process that is used to build the Bitcoin
-Core executables [1]. It provides a way to be reasonably sure that the
-executables are really built from source on github. It also makes sure that
+Core executables. It provides a way to be reasonably sure that the
+executables are really built from source on GitHub. It also makes sure that
the same, tested dependencies are used and statically built into the executable.
Multiple developers build the source code by following a specific descriptor
@@ -17,9 +17,6 @@ More independent gitian builders are needed, which is why I wrote this
guide. It is preferred to follow these steps yourself instead of using someone else's
VM image to avoid 'contaminating' the build.
-[1] For all platforms except for MacOSX, at this point. Work for deterministic
-builds for Mac is under way here: https://github.com/theuni/osx-cross-depends .
-
Table of Contents
------------------
@@ -34,19 +31,22 @@ Table of Contents
- [Signing externally](#signing-externally)
- [Uploading signatures](#uploading-signatures)
-Create a new VirtualBox VM
----------------------------
+Preparing the Gitian builder host
+---------------------------------
-The first step is to create a new Virtual Machine, which will be explained in
-this section. This VM will be used to do the Gitian builds. In this guide it
-will be explained how to set up the environment, and how to get the builds
-started.
+The first step is to prepare the host environment that will be used to perform the Gitian builds.
+This guide explains how to set up the environment, and how to start the builds.
-Debian Linux was chosen as the host distribution because it has a lightweight install (in
-contrast to Ubuntu) and is readily available. We here show the steps for
-VirtualBox [1], but any kind of virtualization can be used. You can also install
-on actual hardware instead of using a VM, in this case you can skip this section.
+Debian Linux was chosen as the host distribution because it has a lightweight install (in contrast to Ubuntu) and is readily available.
+Any kind of virtualization can be used, for example:
+- [VirtualBox](https://www.virtualbox.org/), covered by this guide
+- [KVM](http://www.linux-kvm.org/page/Main_Page)
+- [LXC](https://linuxcontainers.org/), see also [Gitian host docker container](https://github.com/gdm85/tenku/tree/master/docker/gitian-bitcoin-host/README.md).
+You can also install on actual hardware instead of using virtualization.
+
+Create a new VirtualBox VM
+---------------------------
In the VirtualBox GUI click "Create" and choose the following parameters in the wizard:
![](gitian-building/create_vm_page1.png)
@@ -74,11 +74,11 @@ In the VirtualBox GUI click "Create" and choose the following parameters in the
- Disk size: at least 40GB; as low as 20GB *may* be possible, but better to err on the safe side
- Push the `Create` button
-Get the [Debian 7.4 net installer](http://cdimage.debian.org/debian-cd/7.4.0/amd64/iso-cd/debian-7.4.0-amd64-netinst.iso).
+Get the [Debian 7.4 net installer](http://ftp.at.debian.org/debian-jigdo/current/amd64/iso-cd/debian-7.4.0-amd64-netinst.iso) (a more recent minor version should also work, see also [Debian Network installation](https://www.debian.org/CD/netinst/)).
This DVD image can be validated using a SHA256 hashing tool, for example on
Unixy OSes by entering the following in a terminal:
- echo "b712a141bc60269db217d3b3e456179bd6b181645f90e4aac9c42ed63de492e9 /home/orion/Downloads/debian-7.4.0-amd64-netinst.iso" | sha256sum -c
+ echo "b712a141bc60269db217d3b3e456179bd6b181645f90e4aac9c42ed63de492e9 debian-7.4.0-amd64-netinst.iso" | sha256sum -c
# (must return OK)
After creating the VM, we need to configure it.
@@ -106,8 +106,6 @@ Then start the VM. On the first launch you will be asked for a CD or DVD image.
![](gitian-building/select_startup_disk.png)
-[1] https://www.virtualbox.org/
-
Installing Debian
------------------
@@ -133,7 +131,7 @@ and proceed, just press `Enter`. To select a different button, press `Tab`.
![](gitian-building/debian_install_5_configure_the_network.png)
-- Choose a root password and enter it twice (and remember it for later)
+- Choose a root password and enter it twice (remember it for later)
![](gitian-building/debian_install_6a_set_up_root_password.png)
@@ -142,7 +140,7 @@ and proceed, just press `Enter`. To select a different button, press `Tab`.
![](gitian-building/debian_install_7_set_up_user_fullname.png)
![](gitian-building/debian_install_8_set_up_username.png)
-- Choose a user password and enter it twice (and remember it for later)
+- Choose a user password and enter it twice (remember it for later)
![](gitian-building/debian_install_9_user_password.png)
@@ -235,7 +233,7 @@ adduser debian sudo
When you get a colorful screen with a question about the 'LXC directory', just
go with the default (`/var/lib/lxc`).
-Then set up LXC and the rest with the following is a complex jumble of settings and workarounds:
+Then set up LXC and the rest with the following, which is a complex jumble of settings and workarounds:
```bash
# the version of lxc-start in Debian 7.4 needs to run as root, so make sure
@@ -279,11 +277,14 @@ cd ..
**Note**: When sudo asks for a password, enter the password for the user *debian* not for *root*.
-Clone the git repositories for bitcoin and gitian,
+Clone the git repositories for bitcoin and gitian and then checkout the bitcoin version that you want to build.
```bash
git clone https://github.com/devrandom/gitian-builder.git
git clone https://github.com/bitcoin/bitcoin
+cd bitcoin
+git checkout v${VERSION}
+cd ..
```
Setting up gitian images
@@ -315,10 +316,10 @@ you will find a list of `wget` commands that can be executed to get the dependen
I needed to add `--no-check-certificate` to the OpenSSL wget line to make it work.
Likely this is because the ca-certificates in Debian 7.4 is fairly old. This does not create a
-security issue as the gitian descriptors check integrity of the input archives and refuse to work
+security issue as the gitian descriptors check the integrity of the input archives and refuse to work
if any one is corrupted.
-After downloading the archives, execute the `gbuild` commends to build the dependencies.
+After downloading the archives, execute the `gbuild` commands to build the dependencies.
This can take a long time, but only has to be done when the dependencies change, for example
to upgrade the used version.
@@ -335,7 +336,7 @@ tail -f var/build.log
Building Bitcoin
----------------
-To build Bitcoin (for Linux and/or Windows) just follow the steps under 'perform
+To build Bitcoin (for Linux, OSX and Windows) just follow the steps under 'perform
gitian builds' in [doc/release-process.md](release-process.md) in the bitcoin repository.
Output from `gbuild` will look something like
@@ -368,7 +369,7 @@ can be inspected in `var/install.log` and `var/build.log`.
Building an alternative repository
-----------------------------------
-If you want to do a test build of a pull on github it can be useful to point
+If you want to do a test build of a pull on GitHub it can be useful to point
the gitian builder at an alternative repository, using the same descriptors
and inputs.
@@ -378,13 +379,14 @@ URL=https://github.com/laanwj/bitcoin.git
COMMIT=2014_03_windows_unicode_path
./bin/gbuild --commit bitcoin=${COMMIT} --url bitcoin=${URL} ../bitcoin/contrib/gitian-descriptors/gitian-linux.yml
./bin/gbuild --commit bitcoin=${COMMIT} --url bitcoin=${URL} ../bitcoin/contrib/gitian-descriptors/gitian-win.yml
+./bin/gbuild --commit bitcoin=${COMMIT} --url bitcoin=${URL} ../bitcoin/contrib/gitian-descriptors/gitian-osx.yml
```
Signing externally
-------------------
-If you want to do the PGP signing on another device that's possible too; just define `SIGNER` as mentioned
-and follow the steps in the build process as normally.
+If you want to do the PGP signing on another device that's also possible; just define `SIGNER` as mentioned
+and follow the steps in the build process as normal.
gpg: skipped "laanwj": secret key not available
@@ -392,8 +394,9 @@ When you execute `gsign` you will get an error from GPG, which can be ignored. C
in `gitian.sigs` to your signing machine and do
```bash
- gpg --detach-sign ${VERSION}/${SIGNER}/bitcoin-build.assert
+ gpg --detach-sign ${VERSION}-linux/${SIGNER}/bitcoin-build.assert
gpg --detach-sign ${VERSION}-win/${SIGNER}/bitcoin-build.assert
+ gpg --detach-sign ${VERSION}-osx/${SIGNER}/bitcoin-build.assert
```
This will create the `.sig` files that can be committed together with the `.assert` files to assert your
@@ -402,9 +405,6 @@ gitian build.
Uploading signatures
---------------------
-After building and signing you can push your signatures (both the `.assert` and
-`.assert.sig` files) to the
-[bitcoin/gitian.sigs](https://github.com/bitcoin/gitian.sigs/) repository, or
-if not possible create a pull request. You can also mail the files to me
-(laanwj@gmail.com) and I'll commit them.
-
+After building and signing you can push your signatures (both the `.assert` and `.assert.sig` files) to the
+[bitcoin/gitian.sigs](https://github.com/bitcoin/gitian.sigs/) repository, or if that's not possible create a pull
+request. You can also mail the files to me (laanwj@gmail.com) and I'll commit them.
diff --git a/doc/release-notes.md b/doc/release-notes.md
index f16eec32a2..66059800b6 100644
--- a/doc/release-notes.md
+++ b/doc/release-notes.md
@@ -1,2 +1,87 @@
(note: this is a temporary file, to be added-to by anybody, and moved to
release-notes at release time)
+
+Transaction fee changes
+=======================
+
+This release automatically estimates how high a transaction fee (or how
+high a priority) transactions require to be confirmed quickly. The default
+settings will create transactions that confirm quickly; see the new
+'txconfirmtarget' setting to control the tradeoff between fees and
+confirmation times.
+
+Prior releases used hard-coded fees (and priorities), and would
+sometimes create transactions that took a very long time to confirm.
+
+
+New Command Line Options
+========================
+
+-txconfirmtarget=n : create transactions that have enough fees (or priority)
+so they are likely to confirm within n blocks (default: 1). This setting
+is over-ridden by the -paytxfee option.
+
+New RPC methods
+===============
+
+Fee/Priority estimation
+-----------------------
+
+estimatefee nblocks : Returns approximate fee-per-1,000-bytes needed for
+a transaction to be confirmed within nblocks. Returns -1 if not enough
+transactions have been observed to compute a good estimate.
+
+estimatepriority nblocks : Returns approximate priority needed for
+a zero-fee transaction to confirm within nblocks. Returns -1 if not
+enough free transactions have been observed to compute a good
+estimate.
+
+Statistics used to estimate fees and priorities are saved in the
+data directory in the 'fee_estimates.dat' file just before
+program shutdown, and are read in at startup.
+
+Double-Spend Relay and Alerts
+=============================
+VERY IMPORTANT: *It has never been safe, and remains unsafe, to rely*
+*on unconfirmed transactions.*
+
+Relay
+-----
+When an attempt is seen on the network to spend the same unspent funds
+more than once, it is no longer ignored. Instead, it is broadcast, to
+serve as an alert. This broadcast is subject to protections against
+denial-of-service attacks.
+
+Wallets and other bitcoin services should alert their users to
+double-spends that affect them. Merchants and other users may have
+enough time to withhold goods or services when payment becomes
+uncertain, until confirmation.
+
+Bitcoin Core Wallet Alerts
+--------------------------
+The Bitcoin Core wallet now makes respend attempts visible in several
+ways.
+
+If you are online, and a respend affecting one of your wallet
+transactions is seen, a notification is immediately issued to the
+command registered with `-respendnotify=<cmd>`. Additionally, if
+using the GUI:
+ - An alert box is immediately displayed.
+ - The affected wallet transaction is highlighted in red until it is
+ confirmed (and it may never be confirmed).
+
+A `respendsobserved` array is added to `gettransaction`, `listtransactions`,
+and `listsinceblock` RPC results.
+
+Warning
+-------
+*If you rely on an unconfirmed transaction, these change do VERY*
+*LITTLE to protect you from a malicious double-spend, because:*
+
+ - You may learn about the respend too late to avoid doing whatever
+ you were being paid for
+ - Using other relay rules, a double-spender can craft his crime to
+ resist broadcast
+ - Miners can choose which conflicting spend to confirm, and some
+ miners may not confirm the first acceptable spend they see
+
diff --git a/doc/release-notes/release-notes-0.9.1.md b/doc/release-notes/release-notes-0.9.1.md
new file mode 100644
index 0000000000..0552053d27
--- /dev/null
+++ b/doc/release-notes/release-notes-0.9.1.md
@@ -0,0 +1,53 @@
+Bitcoin Core version 0.9.1 is now available from:
+
+ https://bitcoin.org/bin/0.9.1/
+
+This is a security update. It is recommended to upgrade to this release
+as soon as possible.
+
+It is especially important to upgrade if you currently have version
+0.9.0 installed and are using the graphical interface OR you are using
+bitcoind from any pre-0.9.1 version, and have enabled SSL for RPC and
+have configured allowip to allow rpc connections from potentially
+hostile hosts.
+
+Please report bugs using the issue tracker at github:
+
+ https://github.com/bitcoin/bitcoin/issues
+
+How to Upgrade
+--------------
+
+If you are running an older version, shut it down. Wait until it has completely
+shut down (which might take a few minutes for older versions), then run the
+installer (on Windows) or just copy over /Applications/Bitcoin-Qt (on Mac) or
+bitcoind/bitcoin-qt (on Linux).
+
+If you are upgrading from version 0.7.2 or earlier, the first time you run
+0.9.1 your blockchain files will be re-indexed, which will take anywhere from
+30 minutes to several hours, depending on the speed of your machine.
+
+0.9.1 Release notes
+=======================
+
+No code changes were made between 0.9.0 and 0.9.1. Only the dependencies were changed.
+
+- Upgrade OpenSSL to 1.0.1g. This release fixes the following vulnerabilities which can
+ affect the Bitcoin Core software:
+
+ - CVE-2014-0160 ("heartbleed")
+ A missing bounds check in the handling of the TLS heartbeat extension can
+ be used to reveal up to 64k of memory to a connected client or server.
+
+ - CVE-2014-0076
+ The Montgomery ladder implementation in OpenSSL does not ensure that
+ certain swap operations have a constant-time behavior, which makes it
+ easier for local users to obtain ECDSA nonces via a FLUSH+RELOAD cache
+ side-channel attack.
+
+- Add statically built executables to Linux build
+
+Credits
+--------
+
+Credits go to the OpenSSL team for fixing the vulnerabilities quickly.
diff --git a/doc/release-notes/release-notes-0.9.2.1.md b/doc/release-notes/release-notes-0.9.2.1.md
new file mode 100644
index 0000000000..3168ad1a5a
--- /dev/null
+++ b/doc/release-notes/release-notes-0.9.2.1.md
@@ -0,0 +1,207 @@
+Bitcoin Core version 0.9.2.1 is now available from:
+
+ https://bitcoin.org/bin/0.9.2.1/
+
+This is a new minor version release, bringing mostly bug fixes and some minor
+improvements. OpenSSL has been updated because of a security issue (CVE-2014-0224).
+Upgrading to this release is recommended.
+
+Please report bugs using the issue tracker at github:
+
+ https://github.com/bitcoin/bitcoin/issues
+
+How to Upgrade
+--------------
+
+If you are running an older version, shut it down. Wait until it has completely
+shut down (which might take a few minutes for older versions), then run the
+installer (on Windows) or just copy over /Applications/Bitcoin-Qt (on Mac) or
+bitcoind/bitcoin-qt (on Linux).
+
+If you are upgrading from version 0.7.2 or earlier, the first time you run
+0.9.2.1 your blockchain files will be re-indexed, which will take anywhere from
+30 minutes to several hours, depending on the speed of your machine.
+
+Downgrading warnings
+--------------------
+
+The 'chainstate' for this release is not always compatible with previous
+releases, so if you run 0.9.x and then decide to switch back to a
+0.8.x release you might get a blockchain validation error when starting the
+old release (due to 'pruned outputs' being omitted from the index of
+unspent transaction outputs).
+
+Running the old release with the -reindex option will rebuild the chainstate
+data structures and correct the problem.
+
+Also, the first time you run a 0.8.x release on a 0.9 wallet it will rescan
+the blockchain for missing spent coins, which will take a long time (tens
+of minutes on a typical machine).
+
+Important changes
+==================
+
+Gitian OSX build
+-----------------
+
+The deterministic build system that was already used for Windows and Linux
+builds is now used for OSX as well. Although the resulting executables have
+been tested quite a bit, there could be possible regressions. Be sure to report
+these on the Github bug tracker mentioned above.
+
+Compatibility of Linux build
+-----------------------------
+
+For Linux we now build against Qt 4.6, and filter the symbols for libstdc++ and glibc.
+This brings back compatibility with
+
+- Debian 6+ / Tails
+- Ubuntu 10.04
+- CentOS 6.5
+
+0.9.2 - 0.9.2.1 Release notes
+=======================
+
+The OpenSSL dependency in the gitian builds has been upgraded to 1.0.1h because of CVE-2014-0224.
+
+RPC:
+
+- Add `getwalletinfo`, `getblockchaininfo` and `getnetworkinfo` calls (will replace hodge-podge `getinfo` at some point)
+- Add a `relayfee` field to `getnetworkinfo`
+- Fix RPC related shutdown hangs and leaks
+- Always show syncnode in `getpeerinfo`
+- `sendrawtransaction`: report the reject code and reason, and make it possible to re-send transactions that are already in the mempool
+- `getmininginfo` show right genproclimit
+
+Command-line options:
+
+- Fix `-printblocktree` output
+- Show error message if ReadConfigFile fails
+
+Block-chain handling and storage:
+
+- Fix for GetBlockValue() after block 13,440,000 (BIP42)
+- Upgrade leveldb to 1.17
+
+Protocol and network code:
+
+- Per-peer block download tracking and stalled download detection
+- Add new DNS seed from bitnodes.io
+- Prevent socket leak in ThreadSocketHandler and correct some proxy related socket leaks
+- Use pnode->nLastRecv as sync score (was the wrong way around)
+
+Wallet:
+
+- Make GetAvailableCredit run GetHash() only once per transaction (performance improvement)
+- Lower paytxfee warning threshold from 0.25 BTC to 0.01 BTC
+- Fix importwallet nTimeFirstKey (trigger necessary rescans)
+- Log BerkeleyDB version at startup
+- CWallet init fix
+
+Build system:
+
+- Add OSX build descriptors to gitian
+- Fix explicit --disable-qt-dbus
+- Don't require db_cxx.h when compiling with wallet disabled and GUI enabled
+- Improve missing boost error reporting
+- Upgrade miniupnpc version to 1.9
+- gitian-linux: --enable-glibc-back-compat for binary compatibility with old distributions
+- gitian: don't export any symbols from executable
+- gitian: build against Qt 4.6
+- devtools: add script to check symbols from Linux gitian executables
+- Remove build-time no-IPv6 setting
+
+GUI:
+
+- Fix various coin control visual issues
+- Show number of in/out connections in debug console
+- Show weeks as well as years behind for long timespans behind
+- Enable and disable the Show and Remove buttons for requested payments history based on whether any entry is selected.
+- Show also value for options overridden on command line in options dialog
+- Fill in label from address book also for URIs
+- Fixes feel when resizing the last column on tables (issue #2862)
+- Fix ESC in disablewallet mode
+- Add expert section to wallet tab in optionsdialog
+- Do proper boost::path conversion (fixes unicode in datadir)
+- Only override -datadir if different from the default (fixes -datadir in config file)
+- Show rescan progress at start-up
+- Show importwallet progress
+- Get required locks upfront in polling functions (avoids hanging on locks)
+- Catch Windows shutdown events while client is running
+- Optionally add third party links to transaction context menu
+- Check for !pixmap() before trying to export QR code (avoids crashes when no QR code could be generated)
+- Fix "Start bitcoin on system login"
+
+Miscellaneous:
+
+- Replace non-threadsafe C functions (gmtime, strerror and setlocale)
+- Add missing cs_main and wallet locks
+- Avoid exception at startup when system locale not recognized
+- Changed bitrpc.py's raw_input to getpass for passwords to conceal characters during command line input
+- devtools: add a script to fetch and postprocess translations
+
+Credits
+--------
+
+Thanks to everyone who contributed to this release:
+
+- Addy Yeow
+- Altoidnerd
+- Andrea D'Amore
+- Andreas Schildbach
+- Bardi Harborow
+- Brandon Dahler
+- Bryan Bishop
+- Chris Beams
+- Christian von Roques
+- Cory Fields
+- Cozz Lovan
+- daniel
+- Daniel Newton
+- David A. Harding
+- ditto-b
+- duanemoody
+- Eric S. Bullington
+- Fabian Raetz
+- Gavin Andresen
+- Gregory Maxwell
+- gubatron
+- Haakon Nilsen
+- harry
+- Hector Jusforgues
+- Isidoro Ghezzi
+- Jeff Garzik
+- Johnathan Corgan
+- jtimon
+- Kamil Domanski
+- langerhans
+- Luke Dashjr
+- Manuel Araoz
+- Mark Friedenbach
+- Matt Corallo
+- Matthew Bogosian
+- Meeh
+- Michael Ford
+- Michagogo
+- Mikael Wikman
+- Mike Hearn
+- olalonde
+- paveljanik
+- peryaudo
+- Philip Kaufmann
+- philsong
+- Pieter Wuille
+- R E Broadley
+- richierichrawr
+- Rune K. Svendsen
+- rxl
+- shshshsh
+- Simon de la Rouviere
+- Stuart Cardall
+- super3
+- Telepatheic
+- Thomas Zander
+- Torstein Husebø
+- Warren Togami
+- Wladimir J. van der Laan
+- Yoichi Hirai
diff --git a/doc/release-notes/release-notes-0.9.2.md b/doc/release-notes/release-notes-0.9.2.md
new file mode 100644
index 0000000000..a2749e549f
--- /dev/null
+++ b/doc/release-notes/release-notes-0.9.2.md
@@ -0,0 +1,207 @@
+Bitcoin Core version 0.9.2 is now available from:
+
+ https://bitcoin.org/bin/0.9.2/
+
+This is a new minor version release, bringing mostly bug fixes and some minor
+improvements. OpenSSL has been updated because of a security issue (CVE-2014-0224).
+Upgrading to this release is recommended.
+
+Please report bugs using the issue tracker at github:
+
+ https://github.com/bitcoin/bitcoin/issues
+
+How to Upgrade
+--------------
+
+If you are running an older version, shut it down. Wait until it has completely
+shut down (which might take a few minutes for older versions), then run the
+installer (on Windows) or just copy over /Applications/Bitcoin-Qt (on Mac) or
+bitcoind/bitcoin-qt (on Linux).
+
+If you are upgrading from version 0.7.2 or earlier, the first time you run
+0.9.2 your blockchain files will be re-indexed, which will take anywhere from
+30 minutes to several hours, depending on the speed of your machine.
+
+Downgrading warnings
+--------------------
+
+The 'chainstate' for this release is not always compatible with previous
+releases, so if you run 0.9.x and then decide to switch back to a
+0.8.x release you might get a blockchain validation error when starting the
+old release (due to 'pruned outputs' being omitted from the index of
+unspent transaction outputs).
+
+Running the old release with the -reindex option will rebuild the chainstate
+data structures and correct the problem.
+
+Also, the first time you run a 0.8.x release on a 0.9 wallet it will rescan
+the blockchain for missing spent coins, which will take a long time (tens
+of minutes on a typical machine).
+
+Important changes
+==================
+
+Gitian OSX build
+-----------------
+
+The deterministic build system that was already used for Windows and Linux
+builds is now used for OSX as well. Although the resulting executables have
+been tested quite a bit, there could be possible regressions. Be sure to report
+these on the Github bug tracker mentioned above.
+
+Compatibility of Linux build
+-----------------------------
+
+For Linux we now build against Qt 4.6, and filter the symbols for libstdc++ and glibc.
+This brings back compatibility with
+
+- Debian 6+ / Tails
+- Ubuntu 10.04
+- CentOS 6.5
+
+0.9.2 Release notes
+=======================
+
+The OpenSSL dependency in the gitian builds has been upgraded to 1.0.1h because of CVE-2014-0224.
+
+RPC:
+
+- Add `getwalletinfo`, `getblockchaininfo` and `getnetworkinfo` calls (will replace hodge-podge `getinfo` at some point)
+- Add a `relayfee` field to `getnetworkinfo`
+- Fix RPC related shutdown hangs and leaks
+- Always show syncnode in `getpeerinfo`
+- `sendrawtransaction`: report the reject code and reason, and make it possible to re-send transactions that are already in the mempool
+- `getmininginfo` show right genproclimit
+
+Command-line options:
+
+- Fix `-printblocktree` output
+- Show error message if ReadConfigFile fails
+
+Block-chain handling and storage:
+
+- Fix for GetBlockValue() after block 13,440,000 (BIP42)
+- Upgrade leveldb to 1.17
+
+Protocol and network code:
+
+- Per-peer block download tracking and stalled download detection
+- Add new DNS seed from bitnodes.io
+- Prevent socket leak in ThreadSocketHandler and correct some proxy related socket leaks
+- Use pnode->nLastRecv as sync score (was the wrong way around)
+
+Wallet:
+
+- Make GetAvailableCredit run GetHash() only once per transaction (performance improvement)
+- Lower paytxfee warning threshold from 0.25 BTC to 0.01 BTC
+- Fix importwallet nTimeFirstKey (trigger necessary rescans)
+- Log BerkeleyDB version at startup
+- CWallet init fix
+
+Build system:
+
+- Add OSX build descriptors to gitian
+- Fix explicit --disable-qt-dbus
+- Don't require db_cxx.h when compiling with wallet disabled and GUI enabled
+- Improve missing boost error reporting
+- Upgrade miniupnpc version to 1.9
+- gitian-linux: --enable-glibc-back-compat for binary compatibility with old distributions
+- gitian: don't export any symbols from executable
+- gitian: build against Qt 4.6
+- devtools: add script to check symbols from Linux gitian executables
+- Remove build-time no-IPv6 setting
+
+GUI:
+
+- Fix various coin control visual issues
+- Show number of in/out connections in debug console
+- Show weeks as well as years behind for long timespans behind
+- Enable and disable the Show and Remove buttons for requested payments history based on whether any entry is selected.
+- Show also value for options overridden on command line in options dialog
+- Fill in label from address book also for URIs
+- Fixes feel when resizing the last column on tables (issue #2862)
+- Fix ESC in disablewallet mode
+- Add expert section to wallet tab in optionsdialog
+- Do proper boost::path conversion (fixes unicode in datadir)
+- Only override -datadir if different from the default (fixes -datadir in config file)
+- Show rescan progress at start-up
+- Show importwallet progress
+- Get required locks upfront in polling functions (avoids hanging on locks)
+- Catch Windows shutdown events while client is running
+- Optionally add third party links to transaction context menu
+- Check for !pixmap() before trying to export QR code (avoids crashes when no QR code could be generated)
+- Fix "Start bitcoin on system login"
+
+Miscellaneous:
+
+- Replace non-threadsafe C functions (gmtime, strerror and setlocale)
+- Add missing cs_main and wallet locks
+- Avoid exception at startup when system locale not recognized
+- Changed bitrpc.py's raw_input to getpass for passwords to conceal characters during command line input
+- devtools: add a script to fetch and postprocess translations
+
+Credits
+--------
+
+Thanks to everyone who contributed to this release:
+
+- Addy Yeow
+- Altoidnerd
+- Andrea D'Amore
+- Andreas Schildbach
+- Bardi Harborow
+- Brandon Dahler
+- Bryan Bishop
+- Chris Beams
+- Christian von Roques
+- Cory Fields
+- Cozz Lovan
+- daniel
+- Daniel Newton
+- David A. Harding
+- ditto-b
+- duanemoody
+- Eric S. Bullington
+- Fabian Raetz
+- Gavin Andresen
+- Gregory Maxwell
+- gubatron
+- Haakon Nilsen
+- harry
+- Hector Jusforgues
+- Isidoro Ghezzi
+- Jeff Garzik
+- Johnathan Corgan
+- jtimon
+- Kamil Domanski
+- langerhans
+- Luke Dashjr
+- Manuel Araoz
+- Mark Friedenbach
+- Matt Corallo
+- Matthew Bogosian
+- Meeh
+- Michael Ford
+- Michagogo
+- Mikael Wikman
+- Mike Hearn
+- olalonde
+- paveljanik
+- peryaudo
+- Philip Kaufmann
+- philsong
+- Pieter Wuille
+- R E Broadley
+- richierichrawr
+- Rune K. Svendsen
+- rxl
+- shshshsh
+- Simon de la Rouviere
+- Stuart Cardall
+- super3
+- Telepatheic
+- Thomas Zander
+- Torstein Husebø
+- Warren Togami
+- Wladimir J. van der Laan
+- Yoichi Hirai
diff --git a/doc/release-process.md b/doc/release-process.md
index be00cb8092..c588381411 100644
--- a/doc/release-process.md
+++ b/doc/release-process.md
@@ -23,7 +23,7 @@ Release Process
* * *
-##perform gitian builds
+###perform gitian builds
From a directory containing the bitcoin source, gitian-builder and gitian.sigs
@@ -33,28 +33,31 @@ Release Process
git checkout v${VERSION}
popd
pushd ./gitian-builder
- mkdir -p inputs; cd inputs/
- Register and download the Apple SDK (see OSX Readme for details)
- visit https://developer.apple.com/devcenter/download.action?path=/Developer_Tools/xcode_3.2.6_and_ios_sdk_4.3__final/xcode_3.2.6_and_ios_sdk_4.3.dmg
+###fetch and build inputs: (first time, or when dependency versions change)
- Extract MacOSX10.6.pkg using 7zip
- 7z e -y xcode_3.2.6_and_ios_sdk_4.3.dmg 5.hfs
- 7z -y e 5.hfs "Xcode and iOS SDK/Packages/MacOSX10.6.pkg"
- rm 5.hfs
+ mkdir -p inputs; cd inputs/
- Fetch and build inputs: (first time, or when dependency versions change)
+ Register and download the Apple SDK: (see OSX Readme for details)
+
+ https://developer.apple.com/downloads/download.action?path=Developer_Tools/xcode_4.6.3/xcode4630916281a.dmg
+
+ Using a Mac, create a tarball for the 10.7 SDK and copy it to the inputs directory:
+
+ tar -C /Volumes/Xcode/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/ -czf MacOSX10.7.sdk.tar.gz MacOSX10.7.sdk
+ Download remaining inputs, and build everything:
+
wget 'http://miniupnp.free.fr/files/download.php?file=miniupnpc-1.9.tar.gz' -O miniupnpc-1.9.tar.gz
- wget 'https://www.openssl.org/source/openssl-1.0.1g.tar.gz'
+ wget 'https://www.openssl.org/source/openssl-1.0.1h.tar.gz'
wget 'http://download.oracle.com/berkeley-db/db-4.8.30.NC.tar.gz'
wget 'http://zlib.net/zlib-1.2.8.tar.gz'
wget 'ftp://ftp.simplesystems.org/pub/png/src/history/libpng16/libpng-1.6.8.tar.gz'
wget 'https://fukuchi.org/works/qrencode/qrencode-3.4.3.tar.bz2'
wget 'https://downloads.sourceforge.net/project/boost/boost/1.55.0/boost_1_55_0.tar.bz2'
- wget 'https://svn.boost.org/trac/boost/raw-attachment/ticket/7262/boost-mingw.patch' -O \
- boost-mingw-gas-cross-compile-2013-03-03.patch
+ wget 'https://svn.boost.org/trac/boost/raw-attachment/ticket/7262/boost-mingw.patch' -O boost-mingw-gas-cross-compile-2013-03-03.patch
wget 'https://download.qt-project.org/official_releases/qt/5.2/5.2.0/single/qt-everywhere-opensource-src-5.2.0.tar.gz'
+ wget 'https://download.qt-project.org/official_releases/qt/5.2/5.2.1/single/qt-everywhere-opensource-src-5.2.1.tar.gz'
wget 'https://download.qt-project.org/archive/qt/4.6/qt-everywhere-opensource-src-4.6.4.tar.gz'
wget 'https://protobuf.googlecode.com/files/protobuf-2.5.0.tar.bz2'
wget 'https://github.com/mingwandroid/toolchain4/archive/10cc648683617cca8bcbeae507888099b41b530c.tar.gz'
@@ -63,10 +66,8 @@ Release Process
wget 'http://www.opensource.apple.com/tarballs/ld64/ld64-127.2.tar.gz'
wget 'http://cdrkit.org/releases/cdrkit-1.1.11.tar.gz'
wget 'https://github.com/theuni/libdmg-hfsplus/archive/libdmg-hfsplus-v0.1.tar.gz'
- wget 'http://llvm.org/releases/3.2/clang+llvm-3.2-x86-linux-ubuntu-12.04.tar.gz' -O \
- clang-llvm-3.2-x86-linux-ubuntu-12.04.tar.gz
- wget 'https://raw.githubusercontent.com/theuni/osx-cross-depends/master/patches/cdrtools/genisoimage.diff' -O \
- cdrkit-deterministic.patch
+ wget 'http://llvm.org/releases/3.2/clang+llvm-3.2-x86-linux-ubuntu-12.04.tar.gz' -O clang-llvm-3.2-x86-linux-ubuntu-12.04.tar.gz
+ wget 'https://raw.githubusercontent.com/theuni/osx-cross-depends/master/patches/cdrtools/genisoimage.diff' -O cdrkit-deterministic.patch
cd ..
./bin/gbuild ../bitcoin/contrib/gitian-descriptors/boost-linux.yml
mv build/out/boost-*.zip inputs/
@@ -91,25 +92,29 @@ Release Process
The expected SHA256 hashes of the intermediate inputs are:
- 35c3dfd8b9362f59e81b51881b295232e3bc9e286f1add193b59d486d9ac4a5c bitcoin-deps-linux32-gitian-r5.zip
- 571789867d172500fa96d63d0ba8c5b1e1a3d6f44f720eddf2f93665affc88b3 bitcoin-deps-linux64-gitian-r5.zip
f29b7d9577417333fb56e023c2977f5726a7c297f320b175a4108cf7cd4c2d29 boost-linux32-1.55.0-gitian-r1.zip
88232451c4104f7eb16e469ac6474fd1231bd485687253f7b2bdf46c0781d535 boost-linux64-1.55.0-gitian-r1.zip
- 74ec2d301cf1a9d03b194153f545102ba45dad02b390485212fe6717de486361 qt-linux32-4.6.4-gitian-r1.tar.gz
- 01d0477e299467f09280f15424781154e2b1ea4072c5edb16e044c234954fd9a qt-linux64-4.6.4-gitian-r1.tar.gz
+ 46710f673467e367738d8806e45b4cb5931aaeea61f4b6b55a68eea56d5006c5 bitcoin-deps-linux32-gitian-r6.zip
+ f03be39fb26670243d3a659e64d18e19d03dec5c11e9912011107768390b5268 bitcoin-deps-linux64-gitian-r6.zip
+ 57e57dbdadc818cd270e7e00500a5e1085b3bcbdef69a885f0fb7573a8d987e1 qt-linux32-4.6.4-gitian-r1.tar.gz
+ 60eb4b9c5779580b7d66529efa5b2836ba1a70edde2a0f3f696d647906a826be qt-linux64-4.6.4-gitian-r1.tar.gz
60dc2d3b61e9c7d5dbe2f90d5955772ad748a47918ff2d8b74e8db9b1b91c909 boost-win32-1.55.0-gitian-r6.zip
f65fcaf346bc7b73bc8db3a8614f4f6bee2f61fcbe495e9881133a7c2612a167 boost-win64-1.55.0-gitian-r6.zip
- 97e62002d338885336bb24e7cbb9471491294bd8857af7a83d18c0961f864ec0 bitcoin-deps-win32-gitian-r11.zip
- ee3ea2d5aac1a67ea6bfbea2c04068a7c0940616ce48ee4f37c264bb9d4438ef bitcoin-deps-win64-gitian-r11.zip
+ 70de248cd0dd7e7476194129e818402e974ca9c5751cbf591644dc9f332d3b59 bitcoin-deps-win32-gitian-r13.zip
+ 9eace4c76f639f4f3580a478eee4f50246e1bbb5ccdcf37a158261a5a3fa3e65 bitcoin-deps-win64-gitian-r13.zip
963e3e5e85879010a91143c90a711a5d1d5aba992e38672cdf7b54e42c56b2f1 qt-win32-5.2.0-gitian-r3.zip
751c579830d173ef3e6f194e83d18b92ebef6df03289db13ab77a52b6bc86ef0 qt-win64-5.2.0-gitian-r3.zip
e2e403e1a08869c7eed4d4293bce13d51ec6a63592918b90ae215a0eceb44cb4 protobuf-win32-2.5.0-gitian-r4.zip
a0999037e8b0ef9ade13efd88fee261ba401f5ca910068b7e0cd3262ba667db0 protobuf-win64-2.5.0-gitian-r4.zip
+ 512bc0622c883e2e0f4cbc3fedfd8c2402d06c004ce6fb32303cc2a6f405b6df osx-native-depends-r3.tar.gz
+ 927e4b222be6d590b4bc2fc185872a5d0ca5c322adb983764d3ed84be6bdbc81 osx-depends-r4.tar.gz
+ ec95abef1df2b096a970359787c01d8c45e2a4475b7ae34e12c022634fbdba8a osx-depends-qt-5.2.1-r4.tar.gz
+
- Build bitcoind and bitcoin-qt on Linux32, Linux64, and Win32:
+ Build Bitcoin Core for Linux, Windows, and OS X:
./bin/gbuild --commit bitcoin=v${VERSION} ../bitcoin/contrib/gitian-descriptors/gitian-linux.yml
- ./bin/gsign --signer $SIGNER --release ${VERSION} --destination ../gitian.sigs/ ../bitcoin/contrib/gitian-descriptors/gitian-linux.yml
+ ./bin/gsign --signer $SIGNER --release ${VERSION}-linux --destination ../gitian.sigs/ ../bitcoin/contrib/gitian-descriptors/gitian-linux.yml
pushd build/out
zip -r bitcoin-${VERSION}-linux-gitian.zip *
mv bitcoin-${VERSION}-linux-gitian.zip ../../../
@@ -132,7 +137,7 @@ Release Process
1. linux 32-bit and 64-bit binaries + source (bitcoin-${VERSION}-linux-gitian.zip)
2. windows 32-bit and 64-bit binaries + installer + source (bitcoin-${VERSION}-win-gitian.zip)
3. OSX installer (Bitcoin-Qt.dmg)
- 4. Gitian signatures (in gitian.sigs/${VERSION}[-win|-osx]/(your gitian key)/
+ 4. Gitian signatures (in gitian.sigs/${VERSION}-<linux|win|osx>/(your gitian key)/
repackage gitian builds for release as stand-alone zip/tar/installer exe
@@ -172,8 +177,9 @@ repackage gitian builds for release as stand-alone zip/tar/installer exe
Commit your signature to gitian.sigs:
pushd gitian.sigs
- git add ${VERSION}/${SIGNER}
+ git add ${VERSION}-linux/${SIGNER}
git add ${VERSION}-win/${SIGNER}
+ git add ${VERSION}-osx/${SIGNER}
git commit -a
git push # Assuming you can push to the gitian.sigs tree
popd
@@ -182,34 +188,6 @@ Commit your signature to gitian.sigs:
### After 3 or more people have gitian-built, repackage gitian-signed zips:
-From a directory containing bitcoin source, gitian.sigs and gitian zips
-
- export VERSION=(new version, e.g. 0.8.0)
- mkdir bitcoin-${VERSION}-linux-gitian
- pushd bitcoin-${VERSION}-linux-gitian
- unzip ../bitcoin-${VERSION}-linux-gitian.zip
- mkdir gitian
- cp ../bitcoin/contrib/gitian-downloader/*.pgp ./gitian/
- for signer in $(ls ../gitian.sigs/${VERSION}/); do
- cp ../gitian.sigs/${VERSION}/${signer}/bitcoin-build.assert ./gitian/${signer}-build.assert
- cp ../gitian.sigs/${VERSION}/${signer}/bitcoin-build.assert.sig ./gitian/${signer}-build.assert.sig
- done
- zip -r bitcoin-${VERSION}-linux-gitian.zip *
- cp bitcoin-${VERSION}-linux-gitian.zip ../
- popd
- mkdir bitcoin-${VERSION}-win-gitian
- pushd bitcoin-${VERSION}-win-gitian
- unzip ../bitcoin-${VERSION}-win-gitian.zip
- mkdir gitian
- cp ../bitcoin/contrib/gitian-downloader/*.pgp ./gitian/
- for signer in $(ls ../gitian.sigs/${VERSION}-win/); do
- cp ../gitian.sigs/${VERSION}-win/${signer}/bitcoin-build.assert ./gitian/${signer}-build.assert
- cp ../gitian.sigs/${VERSION}-win/${signer}/bitcoin-build.assert.sig ./gitian/${signer}-build.assert.sig
- done
- zip -r bitcoin-${VERSION}-win-gitian.zip *
- cp bitcoin-${VERSION}-win-gitian.zip ../
- popd
-
- Upload gitian zips to SourceForge
- Announce the release:
diff --git a/doc/translation_process.md b/doc/translation_process.md
index 2f0845a877..61a0a0ffed 100644
--- a/doc/translation_process.md
+++ b/doc/translation_process.md
@@ -1,7 +1,7 @@
Translations
============
-The Qt GUI can be easily translated into other languages. Here's how we
+The Bitcoin Core GUI can be easily translated into other languages. Here's how we
handle those translations.
Files and Folders
diff --git a/qa/rpc-tests/receivedby.py b/qa/rpc-tests/receivedby.py
new file mode 100755
index 0000000000..7f2d79b3c1
--- /dev/null
+++ b/qa/rpc-tests/receivedby.py
@@ -0,0 +1,225 @@
+#!/usr/bin/env python
+# Copyright (c) 2014 The Bitcoin Core developers
+# Distributed under the MIT/X11 software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+# Exercise the listtransactions API
+
+# Add python-bitcoinrpc to module search path:
+
+import os
+import sys
+sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), "python-bitcoinrpc"))
+
+import json
+import shutil
+import subprocess
+import tempfile
+import traceback
+
+from bitcoinrpc.authproxy import AuthServiceProxy, JSONRPCException
+from util import *
+
+def get_sub_array_from_array(object_array, to_match):
+ '''
+ Finds and returns a sub array from an array of arrays.
+ to_match should be a unique idetifier of a sub array
+ '''
+ num_matched = 0
+ for item in object_array:
+ all_match = True
+ for key,value in to_match.items():
+ if item[key] != value:
+ all_match = False
+ if not all_match:
+ continue
+ return item
+ return []
+
+def check_array_result(object_array, to_match, expected, should_not_find = False):
+ """
+ Pass in array of JSON objects, a dictionary with key/value pairs
+ to match against, and another dictionary with expected key/value
+ pairs.
+ If the should_not_find flag is true, to_match should not be found in object_array
+ """
+ if should_not_find == True:
+ expected = { }
+ num_matched = 0
+ for item in object_array:
+ all_match = True
+ for key,value in to_match.items():
+ if item[key] != value:
+ all_match = False
+ if not all_match:
+ continue
+ for key,value in expected.items():
+ if item[key] != value:
+ raise AssertionError("%s : expected %s=%s"%(str(item), str(key), str(value)))
+ num_matched = num_matched+1
+ if num_matched == 0 and should_not_find != True:
+ raise AssertionError("No objects matched %s"%(str(to_match)))
+ if num_matched > 0 and should_not_find == True:
+ raise AssertionError("Objects was matched %s"%(str(to_match)))
+
+def run_test(nodes):
+ '''
+ listreceivedbyaddress Test
+ '''
+ # Send from node 0 to 1
+ addr = nodes[1].getnewaddress()
+ txid = nodes[0].sendtoaddress(addr, 0.1)
+ sync_mempools(nodes)
+
+ #Check not listed in listreceivedbyaddress because has 0 confirmations
+ check_array_result(nodes[1].listreceivedbyaddress(),
+ {"address":addr},
+ { },
+ True)
+ #Bury Tx under 10 block so it will be returned by listreceivedbyaddress
+ nodes[1].setgenerate(True, 10)
+ sync_blocks(nodes)
+ check_array_result(nodes[1].listreceivedbyaddress(),
+ {"address":addr},
+ {"address":addr, "account":"", "amount":Decimal("0.1"), "confirmations":10, "txids":[txid,]})
+ #With min confidence < 10
+ check_array_result(nodes[1].listreceivedbyaddress(5),
+ {"address":addr},
+ {"address":addr, "account":"", "amount":Decimal("0.1"), "confirmations":10, "txids":[txid,]})
+ #With min confidence > 10, should not find Tx
+ check_array_result(nodes[1].listreceivedbyaddress(11),{"address":addr},{ },True)
+
+ #Empty Tx
+ addr = nodes[1].getnewaddress()
+ check_array_result(nodes[1].listreceivedbyaddress(0,True),
+ {"address":addr},
+ {"address":addr, "account":"", "amount":0, "confirmations":0, "txids":[]})
+
+ '''
+ getreceivedbyaddress Test
+ '''
+ # Send from node 0 to 1
+ addr = nodes[1].getnewaddress()
+ txid = nodes[0].sendtoaddress(addr, 0.1)
+ sync_mempools(nodes)
+
+ #Check balance is 0 because of 0 confirmations
+ balance = nodes[1].getreceivedbyaddress(addr)
+ if balance != Decimal("0.0"):
+ raise AssertionError("Wrong balance returned by getreceivedbyaddress, %0.2f"%(balance))
+
+ #Check balance is 0.1
+ balance = nodes[1].getreceivedbyaddress(addr,0)
+ if balance != Decimal("0.1"):
+ raise AssertionError("Wrong balance returned by getreceivedbyaddress, %0.2f"%(balance))
+
+ #Bury Tx under 10 block so it will be returned by the default getreceivedbyaddress
+ nodes[1].setgenerate(True, 10)
+ sync_blocks(nodes)
+ balance = nodes[1].getreceivedbyaddress(addr)
+ if balance != Decimal("0.1"):
+ raise AssertionError("Wrong balance returned by getreceivedbyaddress, %0.2f"%(balance))
+
+ '''
+ listreceivedbyaccount + getreceivedbyaccount Test
+ '''
+ #set pre-state
+ addrArr = nodes[1].getnewaddress()
+ account = nodes[1].getaccount(addrArr)
+ received_by_account_json = get_sub_array_from_array(nodes[1].listreceivedbyaccount(),{"account":account})
+ if len(received_by_account_json) == 0:
+ raise AssertionError("No accounts found in node")
+ balance_by_account = rec_by_accountArr = nodes[1].getreceivedbyaccount(account)
+
+ txid = nodes[0].sendtoaddress(addr, 0.1)
+
+ # listreceivedbyaccount should return received_by_account_json because of 0 confirmations
+ check_array_result(nodes[1].listreceivedbyaccount(),
+ {"account":account},
+ received_by_account_json)
+
+ # getreceivedbyaddress should return same balance because of 0 confirmations
+ balance = nodes[1].getreceivedbyaccount(account)
+ if balance != balance_by_account:
+ raise AssertionError("Wrong balance returned by getreceivedbyaccount, %0.2f"%(balance))
+
+ nodes[1].setgenerate(True, 10)
+ sync_blocks(nodes)
+ # listreceivedbyaccount should return updated account balance
+ check_array_result(nodes[1].listreceivedbyaccount(),
+ {"account":account},
+ {"account":received_by_account_json["account"], "amount":(received_by_account_json["amount"] + Decimal("0.1"))})
+
+ # getreceivedbyaddress should return updates balance
+ balance = nodes[1].getreceivedbyaccount(account)
+ if balance != balance_by_account + Decimal("0.1"):
+ raise AssertionError("Wrong balance returned by getreceivedbyaccount, %0.2f"%(balance))
+
+ #Create a new account named "mynewaccount" that has a 0 balance
+ nodes[1].getaccountaddress("mynewaccount")
+ received_by_account_json = get_sub_array_from_array(nodes[1].listreceivedbyaccount(0,True),{"account":"mynewaccount"})
+ if len(received_by_account_json) == 0:
+ raise AssertionError("No accounts found in node")
+
+ # Test includeempty of listreceivedbyaccount
+ if received_by_account_json["amount"] != Decimal("0.0"):
+ raise AssertionError("Wrong balance returned by listreceivedbyaccount, %0.2f"%(received_by_account_json["amount"]))
+
+ # Test getreceivedbyaccount for 0 amount accounts
+ balance = nodes[1].getreceivedbyaccount("mynewaccount")
+ if balance != Decimal("0.0"):
+ raise AssertionError("Wrong balance returned by getreceivedbyaccount, %0.2f"%(balance))
+
+def main():
+ import optparse
+
+ parser = optparse.OptionParser(usage="%prog [options]")
+ parser.add_option("--nocleanup", dest="nocleanup", default=False, action="store_true",
+ help="Leave bitcoinds and test.* datadir on exit or error")
+ parser.add_option("--srcdir", dest="srcdir", default="../../src",
+ help="Source directory containing bitcoind/bitcoin-cli (default: %default%)")
+ parser.add_option("--tmpdir", dest="tmpdir", default=tempfile.mkdtemp(prefix="test"),
+ help="Root directory for datadirs")
+ (options, args) = parser.parse_args()
+
+ os.environ['PATH'] = options.srcdir+":"+os.environ['PATH']
+
+ check_json_precision()
+
+ success = False
+ nodes = []
+ try:
+ print("Initializing test directory "+options.tmpdir)
+ if not os.path.isdir(options.tmpdir):
+ os.makedirs(options.tmpdir)
+ initialize_chain(options.tmpdir)
+
+ nodes = start_nodes(2, options.tmpdir)
+ connect_nodes(nodes[1], 0)
+ sync_blocks(nodes)
+
+ run_test(nodes)
+
+ success = True
+
+ except AssertionError as e:
+ print("Assertion failed: "+e.message)
+ except Exception as e:
+ print("Unexpected exception caught during testing: "+str(e))
+ traceback.print_tb(sys.exc_info()[2])
+
+ if not options.nocleanup:
+ print("Cleaning up")
+ stop_nodes(nodes)
+ wait_bitcoinds()
+ shutil.rmtree(options.tmpdir)
+
+ if success:
+ print("Tests successful")
+ sys.exit(0)
+ else:
+ print("Failed")
+ sys.exit(1)
+
+if __name__ == '__main__':
+ main()
diff --git a/qa/rpc-tests/rpcbind_test.py b/qa/rpc-tests/rpcbind_test.py
index a31f8d98ef..a823404e00 100755
--- a/qa/rpc-tests/rpcbind_test.py
+++ b/qa/rpc-tests/rpcbind_test.py
@@ -39,7 +39,7 @@ def run_bind_test(tmpdir, allow_ips, connect_to, addresses, expected):
stop_nodes(nodes)
wait_bitcoinds()
-def run_allowip_test(tmpdir, allow_ips, rpchost):
+def run_allowip_test(tmpdir, allow_ips, rpchost, rpcport):
'''
Start a node with rpcwallow IP, and request getinfo
at a non-localhost IP.
@@ -48,7 +48,7 @@ def run_allowip_test(tmpdir, allow_ips, rpchost):
nodes = start_nodes(1, tmpdir, [base_args])
try:
# connect to node through non-loopback interface
- url = "http://rt:rt@%s:%d" % (rpchost, START_RPC_PORT,)
+ url = "http://rt:rt@%s:%d" % (rpchost, rpcport,)
node = AuthServiceProxy(url)
node.getinfo()
finally:
@@ -69,15 +69,17 @@ def run_test(tmpdir):
assert(not 'This test requires at least one non-loopback IPv4 interface')
print("Using interface %s for testing" % non_loopback_ip)
+ defaultport = rpc_port(0)
+
# check default without rpcallowip (IPv4 and IPv6 localhost)
run_bind_test(tmpdir, None, '127.0.0.1', [],
- [('127.0.0.1', 11100), ('::1', 11100)])
+ [('127.0.0.1', defaultport), ('::1', defaultport)])
# check default with rpcallowip (IPv6 any)
run_bind_test(tmpdir, ['127.0.0.1'], '127.0.0.1', [],
- [('::0', 11100)])
+ [('::0', defaultport)])
# check only IPv4 localhost (explicit)
run_bind_test(tmpdir, ['127.0.0.1'], '127.0.0.1', ['127.0.0.1'],
- [('127.0.0.1', START_RPC_PORT)])
+ [('127.0.0.1', defaultport)])
# check only IPv4 localhost (explicit) with alternative port
run_bind_test(tmpdir, ['127.0.0.1'], '127.0.0.1:32171', ['127.0.0.1:32171'],
[('127.0.0.1', 32171)])
@@ -86,18 +88,18 @@ def run_test(tmpdir):
[('127.0.0.1', 32171), ('127.0.0.1', 32172)])
# check only IPv6 localhost (explicit)
run_bind_test(tmpdir, ['[::1]'], '[::1]', ['[::1]'],
- [('::1', 11100)])
+ [('::1', defaultport)])
# check both IPv4 and IPv6 localhost (explicit)
run_bind_test(tmpdir, ['127.0.0.1'], '127.0.0.1', ['127.0.0.1', '[::1]'],
- [('127.0.0.1', START_RPC_PORT), ('::1', START_RPC_PORT)])
+ [('127.0.0.1', defaultport), ('::1', defaultport)])
# check only non-loopback interface
run_bind_test(tmpdir, [non_loopback_ip], non_loopback_ip, [non_loopback_ip],
- [(non_loopback_ip, START_RPC_PORT)])
+ [(non_loopback_ip, defaultport)])
# Check that with invalid rpcallowip, we are denied
- run_allowip_test(tmpdir, [non_loopback_ip], non_loopback_ip)
+ run_allowip_test(tmpdir, [non_loopback_ip], non_loopback_ip, defaultport)
try:
- run_allowip_test(tmpdir, ['1.1.1.1'], non_loopback_ip)
+ run_allowip_test(tmpdir, ['1.1.1.1'], non_loopback_ip, defaultport)
assert(not 'Connection not denied by rpcallowip as expected')
except ValueError:
pass
diff --git a/qa/rpc-tests/smartfees.py b/qa/rpc-tests/smartfees.py
new file mode 100755
index 0000000000..e8abbfba19
--- /dev/null
+++ b/qa/rpc-tests/smartfees.py
@@ -0,0 +1,142 @@
+#!/usr/bin/env python
+
+#
+# Test fee estimation code
+#
+
+# Add python-bitcoinrpc to module search path:
+import os
+import sys
+sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), "python-bitcoinrpc"))
+
+import json
+import random
+import shutil
+import subprocess
+import tempfile
+import traceback
+
+from bitcoinrpc.authproxy import AuthServiceProxy, JSONRPCException
+from util import *
+
+
+def run_test(nodes, test_dir):
+ nodes.append(start_node(0, test_dir,
+ ["-debug=mempool", "-debug=estimatefee"]))
+ # Node1 mines small-but-not-tiny blocks, and allows free transactions.
+ # NOTE: the CreateNewBlock code starts counting block size at 1,000 bytes,
+ # so blockmaxsize of 2,000 is really just 1,000 bytes (room enough for
+ # 6 or 7 transactions)
+ nodes.append(start_node(1, test_dir,
+ ["-blockprioritysize=1500", "-blockmaxsize=2000",
+ "-debug=mempool", "-debug=estimatefee"]))
+ connect_nodes(nodes[1], 0)
+
+ # Node2 is a stingy miner, that
+ # produces very small blocks (room for only 3 or so transactions)
+ node2args = [ "-blockprioritysize=0", "-blockmaxsize=1500",
+ "-debug=mempool", "-debug=estimatefee"]
+ nodes.append(start_node(2, test_dir, node2args))
+ connect_nodes(nodes[2], 0)
+
+ sync_blocks(nodes)
+
+ # Prime the memory pool with pairs of transactions
+ # (high-priority, random fee and zero-priority, random fee)
+ min_fee = Decimal("0.001")
+ fees_per_kb = [];
+ for i in range(12):
+ (txid, txhex, fee) = random_zeropri_transaction(nodes, Decimal("1.1"),
+ min_fee, min_fee, 20)
+ tx_kbytes = (len(txhex)/2)/1000.0
+ fees_per_kb.append(float(fee)/tx_kbytes)
+
+ # Mine blocks with node2 until the memory pool clears:
+ count_start = nodes[2].getblockcount()
+ while len(nodes[2].getrawmempool()) > 0:
+ nodes[2].setgenerate(True, 1)
+ sync_blocks(nodes)
+
+ all_estimates = [ nodes[0].estimatefee(i) for i in range(1,20) ]
+ print("Fee estimates, super-stingy miner: "+str([str(e) for e in all_estimates]))
+
+ # Estimates should be within the bounds of what transactions fees actually were:
+ delta = 1.0e-6 # account for rounding error
+ for e in filter(lambda x: x >= 0, all_estimates):
+ if float(e)+delta < min(fees_per_kb) or float(e)-delta > max(fees_per_kb):
+ raise AssertionError("Estimated fee (%f) out of range (%f,%f)"%(float(e), min_fee_kb, max_fee_kb))
+
+ # Generate transactions while mining 30 more blocks, this time with node1:
+ for i in range(30):
+ for j in range(random.randrange(6-4,6+4)):
+ (txid, txhex, fee) = random_transaction(nodes, Decimal("1.1"),
+ Decimal("0.0"), min_fee, 20)
+ tx_kbytes = (len(txhex)/2)/1000.0
+ fees_per_kb.append(float(fee)/tx_kbytes)
+ nodes[1].setgenerate(True, 1)
+ sync_blocks(nodes)
+
+ all_estimates = [ nodes[0].estimatefee(i) for i in range(1,20) ]
+ print("Fee estimates, more generous miner: "+str([ str(e) for e in all_estimates]))
+ for e in filter(lambda x: x >= 0, all_estimates):
+ if float(e)+delta < min(fees_per_kb) or float(e)-delta > max(fees_per_kb):
+ raise AssertionError("Estimated fee (%f) out of range (%f,%f)"%(float(e), min_fee_kb, max_fee_kb))
+
+ # Finish by mining a normal-sized block:
+ while len(nodes[0].getrawmempool()) > 0:
+ nodes[0].setgenerate(True, 1)
+ sync_blocks(nodes)
+
+ final_estimates = [ nodes[0].estimatefee(i) for i in range(1,20) ]
+ print("Final fee estimates: "+str([ str(e) for e in final_estimates]))
+
+def main():
+ import optparse
+
+ parser = optparse.OptionParser(usage="%prog [options]")
+ parser.add_option("--nocleanup", dest="nocleanup", default=False, action="store_true",
+ help="Leave bitcoinds and test.* datadir on exit or error")
+ parser.add_option("--srcdir", dest="srcdir", default="../../src",
+ help="Source directory containing bitcoind/bitcoin-cli (default: %default%)")
+ parser.add_option("--tmpdir", dest="tmpdir", default=tempfile.mkdtemp(prefix="test"),
+ help="Root directory for datadirs")
+ (options, args) = parser.parse_args()
+
+ os.environ['PATH'] = options.srcdir+":"+os.environ['PATH']
+
+ check_json_precision()
+
+ success = False
+ nodes = []
+ try:
+ print("Initializing test directory "+options.tmpdir)
+ print(" node0 running at: 127.0.0.1:%d"%(p2p_port(0)))
+ if not os.path.isdir(options.tmpdir):
+ os.makedirs(options.tmpdir)
+ initialize_chain(options.tmpdir)
+
+ run_test(nodes, options.tmpdir)
+
+ success = True
+
+ except AssertionError as e:
+ print("Assertion failed: "+e.message)
+ except Exception as e:
+ print("Unexpected exception caught during testing: "+str(e))
+ traceback.print_tb(sys.exc_info()[2])
+
+ if not options.nocleanup:
+ print("Cleaning up")
+ stop_nodes(nodes)
+ wait_bitcoinds()
+ shutil.rmtree(options.tmpdir)
+
+ if success:
+ print("Tests successful")
+ sys.exit(0)
+ else:
+ print("Failed")
+ sys.exit(1)
+
+if __name__ == '__main__':
+ main()
diff --git a/qa/rpc-tests/util.py b/qa/rpc-tests/util.py
index 40f4a1458f..27c9f778f6 100644
--- a/qa/rpc-tests/util.py
+++ b/qa/rpc-tests/util.py
@@ -12,6 +12,7 @@ sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), "python
from decimal import Decimal
import json
+import random
import shutil
import subprocess
import time
@@ -20,8 +21,10 @@ import re
from bitcoinrpc.authproxy import AuthServiceProxy, JSONRPCException
from util import *
-START_P2P_PORT=11000
-START_RPC_PORT=11100
+def p2p_port(n):
+ return 11000 + n + os.getpid()%999
+def rpc_port(n):
+ return 12000 + n + os.getpid()%999
def check_json_precision():
"""Make sure json library being used does not lose precision converting BTC values"""
@@ -58,6 +61,18 @@ def sync_mempools(rpc_connections):
bitcoind_processes = []
+def initialize_datadir(dir, n):
+ datadir = os.path.join(dir, "node"+str(n))
+ if not os.path.isdir(datadir):
+ os.makedirs(datadir)
+ with open(os.path.join(datadir, "bitcoin.conf"), 'w') as f:
+ f.write("regtest=1\n");
+ f.write("rpcuser=rt\n");
+ f.write("rpcpassword=rt\n");
+ f.write("port="+str(p2p_port(n))+"\n");
+ f.write("rpcport="+str(rpc_port(n))+"\n");
+ return datadir
+
def initialize_chain(test_dir):
"""
Create (or copy from cache) a 200-block-long chain and
@@ -69,17 +84,10 @@ def initialize_chain(test_dir):
devnull = open("/dev/null", "w+")
# Create cache directories, run bitcoinds:
for i in range(4):
- datadir = os.path.join("cache", "node"+str(i))
- os.makedirs(datadir)
- with open(os.path.join(datadir, "bitcoin.conf"), 'w') as f:
- f.write("regtest=1\n");
- f.write("rpcuser=rt\n");
- f.write("rpcpassword=rt\n");
- f.write("port="+str(START_P2P_PORT+i)+"\n");
- f.write("rpcport="+str(START_RPC_PORT+i)+"\n");
+ datadir=initialize_datadir("cache", i)
args = [ "bitcoind", "-keypool=1", "-datadir="+datadir ]
if i > 0:
- args.append("-connect=127.0.0.1:"+str(START_P2P_PORT))
+ args.append("-connect=127.0.0.1:"+str(p2p_port(0)))
bitcoind_processes.append(subprocess.Popen(args))
subprocess.check_call([ "bitcoin-cli", "-datadir="+datadir,
"-rpcwait", "getblockcount"], stdout=devnull)
@@ -87,7 +95,7 @@ def initialize_chain(test_dir):
rpcs = []
for i in range(4):
try:
- url = "http://rt:rt@127.0.0.1:%d"%(START_RPC_PORT+i,)
+ url = "http://rt:rt@127.0.0.1:%d"%(rpc_port(i),)
rpcs.append(AuthServiceProxy(url))
except:
sys.stderr.write("Error connecting to "+url+"\n")
@@ -112,6 +120,7 @@ def initialize_chain(test_dir):
from_dir = os.path.join("cache", "node"+str(i))
to_dir = os.path.join(test_dir, "node"+str(i))
shutil.copytree(from_dir, to_dir)
+ initialize_datadir(test_dir, i) # Overwrite port/rpcport in bitcoin.conf
def _rpchost_to_args(rpchost):
'''Convert optional IP:port spec to rpcconnect/rpcport args'''
@@ -133,25 +142,28 @@ def _rpchost_to_args(rpchost):
rv += ['-rpcport=' + rpcport]
return rv
-def start_nodes(num_nodes, dir, extra_args=None, rpchost=None):
- # Start bitcoinds, and wait for RPC interface to be up and running:
+def start_node(i, dir, extra_args=None, rpchost=None):
+ """
+ Start a bitcoind and return RPC connection to it
+ """
+ datadir = os.path.join(dir, "node"+str(i))
+ args = [ "bitcoind", "-datadir="+datadir, "-keypool=1" ]
+ if extra_args is not None: args.extend(extra_args)
+ bitcoind_processes.append(subprocess.Popen(args))
devnull = open("/dev/null", "w+")
- for i in range(num_nodes):
- datadir = os.path.join(dir, "node"+str(i))
- args = [ "bitcoind", "-datadir="+datadir ]
- if extra_args is not None:
- args += extra_args[i]
- bitcoind_processes.append(subprocess.Popen(args))
- subprocess.check_call([ "bitcoin-cli", "-datadir="+datadir] +
- _rpchost_to_args(rpchost) +
- ["-rpcwait", "getblockcount"], stdout=devnull)
+ subprocess.check_call([ "bitcoin-cli", "-datadir="+datadir] +
+ _rpchost_to_args(rpchost) +
+ ["-rpcwait", "getblockcount"], stdout=devnull)
devnull.close()
- # Create&return JSON-RPC connections
- rpc_connections = []
- for i in range(num_nodes):
- url = "http://rt:rt@%s:%d" % (rpchost or '127.0.0.1', START_RPC_PORT+i,)
- rpc_connections.append(AuthServiceProxy(url))
- return rpc_connections
+ url = "http://rt:rt@%s:%d" % (rpchost or '127.0.0.1', rpc_port(i))
+ return AuthServiceProxy(url)
+
+def start_nodes(num_nodes, dir, extra_args=None, rpchost=None):
+ """
+ Start multiple bitcoinds, return RPC connections to them
+ """
+ if extra_args is None: extra_args = [ None for i in range(num_nodes) ]
+ return [ start_node(i, dir, extra_args[i], rpchost) for i in range(num_nodes) ]
def debug_log(dir, n_node):
return os.path.join(dir, "node"+str(n_node), "regtest", "debug.log")
@@ -168,8 +180,114 @@ def wait_bitcoinds():
del bitcoind_processes[:]
def connect_nodes(from_connection, node_num):
- ip_port = "127.0.0.1:"+str(START_P2P_PORT+node_num)
+ ip_port = "127.0.0.1:"+str(p2p_port(node_num))
from_connection.addnode(ip_port, "onetry")
+ # poll until version handshake complete to avoid race conditions
+ # with transaction relaying
+ while any(peer['version'] == 0 for peer in from_connection.getpeerinfo()):
+ time.sleep(0.1)
+
+def find_output(node, txid, amount):
+ """
+ Return index to output of txid with value amount
+ Raises exception if there is none.
+ """
+ txdata = node.getrawtransaction(txid, 1)
+ for i in range(len(txdata["vout"])):
+ if txdata["vout"][i]["value"] == amount:
+ return i
+ raise RuntimeError("find_output txid %s : %s not found"%(txid,str(amount)))
+
+def gather_inputs(from_node, amount_needed):
+ """
+ Return a random set of unspent txouts that are enough to pay amount_needed
+ """
+ utxo = from_node.listunspent(1)
+ random.shuffle(utxo)
+ inputs = []
+ total_in = Decimal("0.00000000")
+ while total_in < amount_needed and len(utxo) > 0:
+ t = utxo.pop()
+ total_in += t["amount"]
+ inputs.append({ "txid" : t["txid"], "vout" : t["vout"], "address" : t["address"] } )
+ if total_in < amount_needed:
+ raise RuntimeError("Insufficient funds: need %d, have %d"%(amount+fee*2, total_in))
+ return (total_in, inputs)
+
+def make_change(from_node, amount_in, amount_out, fee):
+ """
+ Create change output(s), return them
+ """
+ outputs = {}
+ amount = amount_out+fee
+ change = amount_in - amount
+ if change > amount*2:
+ # Create an extra change output to break up big inputs
+ outputs[from_node.getnewaddress()] = float(change/2)
+ change = change/2
+ if change > 0:
+ outputs[from_node.getnewaddress()] = float(change)
+ return outputs
+
+def send_zeropri_transaction(from_node, to_node, amount, fee):
+ """
+ Create&broadcast a zero-priority transaction.
+ Returns (txid, hex-encoded-txdata)
+ Ensures transaction is zero-priority by first creating a send-to-self,
+ then using it's output
+ """
+
+ # Create a send-to-self with confirmed inputs:
+ self_address = from_node.getnewaddress()
+ (total_in, inputs) = gather_inputs(from_node, amount+fee*2)
+ outputs = make_change(from_node, total_in, amount+fee, fee)
+ outputs[self_address] = float(amount+fee)
+
+ self_rawtx = from_node.createrawtransaction(inputs, outputs)
+ self_signresult = from_node.signrawtransaction(self_rawtx)
+ self_txid = from_node.sendrawtransaction(self_signresult["hex"], True)
+
+ vout = find_output(from_node, self_txid, amount+fee)
+ # Now immediately spend the output to create a 1-input, 1-output
+ # zero-priority transaction:
+ inputs = [ { "txid" : self_txid, "vout" : vout } ]
+ outputs = { to_node.getnewaddress() : float(amount) }
+
+ rawtx = from_node.createrawtransaction(inputs, outputs)
+ signresult = from_node.signrawtransaction(rawtx)
+ txid = from_node.sendrawtransaction(signresult["hex"], True)
+
+ return (txid, signresult["hex"])
+
+def random_zeropri_transaction(nodes, amount, min_fee, fee_increment, fee_variants):
+ """
+ Create a random zero-priority transaction.
+ Returns (txid, hex-encoded-transaction-data, fee)
+ """
+ from_node = random.choice(nodes)
+ to_node = random.choice(nodes)
+ fee = min_fee + fee_increment*random.randint(0,fee_variants)
+ (txid, txhex) = send_zeropri_transaction(from_node, to_node, amount, fee)
+ return (txid, txhex, fee)
+
+def random_transaction(nodes, amount, min_fee, fee_increment, fee_variants):
+ """
+ Create a random transaction.
+ Returns (txid, hex-encoded-transaction-data, fee)
+ """
+ from_node = random.choice(nodes)
+ to_node = random.choice(nodes)
+ fee = min_fee + fee_increment*random.randint(0,fee_variants)
+
+ (total_in, inputs) = gather_inputs(from_node, amount+fee)
+ outputs = make_change(from_node, total_in, amount, fee)
+ outputs[to_node.getnewaddress()] = float(amount)
+
+ rawtx = from_node.createrawtransaction(inputs, outputs)
+ signresult = from_node.signrawtransaction(rawtx)
+ txid = from_node.sendrawtransaction(signresult["hex"], True)
+
+ return (txid, signresult["hex"], fee)
def assert_equal(thing1, thing2):
if thing1 != thing2:
diff --git a/qa/rpc-tests/util.sh b/qa/rpc-tests/util.sh
index 1e7bd6a7ee..b726ef627f 100644
--- a/qa/rpc-tests/util.sh
+++ b/qa/rpc-tests/util.sh
@@ -38,6 +38,10 @@ function AssertEqual {
if (( $( echo "$1 == $2" | bc ) == 0 ))
then
echoerr "AssertEqual: $1 != $2"
+ declare -f CleanUp > /dev/null 2>&1
+ if [[ $? -eq 0 ]] ; then
+ CleanUp
+ fi
exit 1
fi
}
@@ -49,6 +53,10 @@ function CheckBalance {
if (( $( echo "$B == $EXPECT" | bc ) == 0 ))
then
echoerr "bad balance: $B (expected $2)"
+ declare -f CleanUp > /dev/null 2>&1
+ if [[ $? -eq 0 ]] ; then
+ CleanUp
+ fi
exit 1
fi
}
diff --git a/qa/rpc-tests/zapwallettxes.sh b/qa/rpc-tests/zapwallettxes.sh
new file mode 100755
index 0000000000..bc52a7dacd
--- /dev/null
+++ b/qa/rpc-tests/zapwallettxes.sh
@@ -0,0 +1,161 @@
+#!/usr/bin/env bash
+
+# Test -zapwallettxes=<mode>
+
+if [ $# -lt 1 ]; then
+ echo "Usage: $0 path_to_binaries"
+ echo "e.g. $0 ../../src"
+ exit 1
+fi
+
+set -f
+
+BITCOIND=${1}/bitcoind
+CLI=${1}/bitcoin-cli
+
+DIR="${BASH_SOURCE%/*}"
+SENDANDWAIT="${DIR}/send.sh"
+if [[ ! -d "$DIR" ]]; then DIR="$PWD"; fi
+. "$DIR/util.sh"
+
+D=$(mktemp -d test.XXXXX)
+
+D1=${D}/node1
+CreateDataDir "$D1" port=11000 rpcport=11001
+B1ARGS="-datadir=$D1"
+$BITCOIND $B1ARGS &
+B1PID=$!
+
+D2=${D}/node2
+CreateDataDir "$D2" port=11010 rpcport=11011
+B2ARGS="-datadir=$D2"
+$BITCOIND $B2ARGS &
+B2PID=$!
+
+function CleanUp {
+$CLI $B2ARGS stop > /dev/null 2>&1
+wait $B2PID
+$CLI $B1ARGS stop > /dev/null 2>&1
+wait $B1PID
+
+rm -rf $D
+}
+
+# 110 blocks, 10 mature == 500 XBT
+$CLI $B1ARGS setgenerate true 110
+$CLI $B2ARGS setgenerate true 110
+
+CheckBalance "$B1ARGS" 500
+CheckBalance "$B2ARGS" 500
+
+# Send 10 XBT
+TXID1_DEFAULT=$($CLI $B1ARGS sendtoaddress "mrhz5ZgSF3C1BSdyCKt3gEdhKoRL5BNfJV" 10)
+TXID2_DEFAULT=$($CLI $B2ARGS sendtoaddress "mrhz5ZgSF3C1BSdyCKt3gEdhKoRL5BNfJV" 10)
+
+CheckBalance $B1ARGS 490
+CheckBalance $B2ARGS 490
+
+# Move 10 XBT to testaccount
+TMP=$($CLI $B1ARGS move "" "testaccount" 10)
+TMP=$($CLI $B2ARGS move "" "testaccount" 10)
+
+CheckBalance $B1ARGS 10 "testaccount"
+CheckBalance $B2ARGS 10 "testaccount"
+
+# Send 1 XBT from testaccount
+TXID1_TESTACCOUNT=$($CLI $B1ARGS sendfrom "testaccount" "mrhz5ZgSF3C1BSdyCKt3gEdhKoRL5BNfJV" 1)
+TXID2_TESTACCOUNT=$($CLI $B2ARGS sendfrom "testaccount" "mrhz5ZgSF3C1BSdyCKt3gEdhKoRL5BNfJV" 1)
+
+CheckBalance $B1ARGS 9 "testaccount"
+CheckBalance $B2ARGS 9 "testaccount"
+
+CheckBalance $B1ARGS 489
+CheckBalance $B2ARGS 489
+
+# Confirm transactions
+$CLI $B1ARGS setgenerate true 1
+$CLI $B2ARGS setgenerate true 1
+
+# Create unconfirmed transaction
+TXID1_UNCONFIRMED=$($CLI $B1ARGS sendtoaddress "mrhz5ZgSF3C1BSdyCKt3gEdhKoRL5BNfJV" 1)
+TXID2_UNCONFIRMED=$($CLI $B2ARGS sendtoaddress "mrhz5ZgSF3C1BSdyCKt3gEdhKoRL5BNfJV" 1)
+
+# check balance (we created another 50 and spent 1 in the meantime)
+CheckBalance $B1ARGS 538
+CheckBalance $B2ARGS 538
+
+# Safety check, if unconfirmed transactions are there
+$CLI $B1ARGS gettransaction $TXID1_UNCONFIRMED > /dev/null 2>&1
+if [[ $? -ne 0 ]] ; then
+ echoerr "gettransaction1_1: $TXID1_UNCONFIRMED failed"
+ CleanUp
+ exit 1
+fi
+$CLI $B2ARGS gettransaction $TXID2_UNCONFIRMED > /dev/null 2>&1
+if [[ $? -ne 0 ]] ; then
+ echoerr "gettransaction2_1: $TXID2_UNCONFIRMED failed"
+ CleanUp
+ exit 1
+fi
+
+# stop nodes
+$CLI $B2ARGS stop > /dev/null 2>&1
+wait $B2PID
+$CLI $B1ARGS stop > /dev/null 2>&1
+wait $B1PID
+
+# restart nodes with -zapwallettxes
+$BITCOIND -zapwallettxes=1 $B1ARGS &
+B1PID=$!
+$BITCOIND -zapwallettxes=2 $B2ARGS &
+B2PID=$!
+
+# check if confirmed transactions are there
+$CLI $B1ARGS gettransaction $TXID1_DEFAULT > /dev/null 2>&1
+if [[ $? -ne 0 ]] ; then
+ echoerr "check confirmed transaction 1: $TXID1_DEFAULT failed"
+ CleanUp
+ exit 1
+fi
+$CLI $B2ARGS gettransaction $TXID2_DEFAULT > /dev/null 2>&1
+if [[ $? -ne 0 ]] ; then
+ echoerr "check confirmed transaction 2: $TXID2_DEFAULT failed"
+ CleanUp
+ exit 1
+fi
+$CLI $B1ARGS gettransaction $TXID1_TESTACCOUNT > /dev/null 2>&1
+if [[ $? -ne 0 ]] ; then
+ echoerr "check confirmed transaction 3: $TXID1_TESTACCOUNT failed"
+ CleanUp
+ exit 1
+fi
+$CLI $B2ARGS gettransaction $TXID2_TESTACCOUNT > /dev/null 2>&1
+if [[ $? -ne 0 ]] ; then
+ echoerr "check confirmed transaction 4: $TXID2_TESTACCOUNT failed"
+ CleanUp
+ exit 1
+fi
+
+# check if unconfirmed transaction is gone
+$CLI $B1ARGS gettransaction $TXID1_UNCONFIRMED > /dev/null 2>&1
+if [[ $? -eq 0 ]] ; then
+ echoerr "check unconfirmed transaction 1: $TXID1_UNCONFIRMED failed"
+ CleanUp
+ exit 1
+fi
+$CLI $B2ARGS gettransaction $TXID2_UNCONFIRMED > /dev/null 2>&1
+if [[ $? -eq 0 ]] ; then
+ echoerr "check unconfirmed transaction 2: $TXID2_UNCONFIRMED failed"
+ CleanUp
+ exit 1
+fi
+
+# check zapwallet mode 1, testaccount balance must be 9 (keeping transaction metadata)
+CheckBalance $B1ARGS 9 "testaccount"
+
+# check zapwallet mode 2, testaccount balance must be 10 (dropping transaction metadata)
+CheckBalance $B2ARGS 10 "testaccount"
+
+echo "Tests successful, cleaning up"
+CleanUp
+exit 0
diff --git a/share/qt/extract_strings_qt.py b/share/qt/extract_strings_qt.py
index e6afe3b48b..d4bd585138 100755
--- a/share/qt/extract_strings_qt.py
+++ b/share/qt/extract_strings_qt.py
@@ -7,8 +7,9 @@ from subprocess import Popen, PIPE
import glob
import operator
import os
+import sys
-OUT_CPP="src/qt/bitcoinstrings.cpp"
+OUT_CPP="qt/bitcoinstrings.cpp"
EMPTY=['""']
def parse_po(text):
@@ -47,7 +48,7 @@ def parse_po(text):
return messages
-files = glob.glob('src/*.cpp') + glob.glob('src/*.h')
+files = sys.argv[1:]
# xgettext -n --keyword=_ $FILES
XGETTEXT=os.getenv('XGETTEXT', 'xgettext')
diff --git a/src/Makefile.am b/src/Makefile.am
index a49ad58716..e2a62c9699 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,16 +1,54 @@
-include Makefile.include
+AM_CPPFLAGS = $(INCLUDES)
+AM_LDFLAGS = $(PTHREAD_CFLAGS)
-AM_CPPFLAGS += -I$(builddir)
+if USE_LIBSECP256K1
+secp256k1/libsecp256k1.la: $(wildcard secp256k1/src/*) $(wildcard secp256k1/include/*)
+ @$(MAKE) $(AM_MAKEFLAGS) -C $(@D) $(@F)
+endif
+
+if EMBEDDED_LEVELDB
+LEVELDB_CPPFLAGS += -I$(srcdir)/leveldb/include
+LEVELDB_CPPFLAGS += -I$(srcdir)/leveldb/helpers/memenv
+LIBLEVELDB += $(builddir)/leveldb/libleveldb.a
+LIBMEMENV += $(builddir)/leveldb/libmemenv.a
+
+# NOTE: This dependency is not strictly necessary, but without it make may try to build both in parallel, which breaks the LevelDB build system in a race
+$(LIBLEVELDB): $(LIBMEMENV)
+
+$(LIBLEVELDB) $(LIBMEMENV):
+ @echo "Building LevelDB ..." && $(MAKE) -C $(@D) $(@F) CXX="$(CXX)" \
+ CC="$(CC)" PLATFORM=$(TARGET_OS) AR="$(AR)" $(LEVELDB_TARGET_FLAGS) \
+ OPT="$(CXXFLAGS) $(CPPFLAGS)"
+endif
+
+BITCOIN_CONFIG_INCLUDES=-I$(builddir)/config
+BITCOIN_INCLUDES=-I$(builddir) -I$(builddir)/obj $(BOOST_CPPFLAGS) $(LEVELDB_CPPFLAGS)
+
+if USE_LIBSECP256K1
+BITCOIN_INCLUDES += -I$(srcdir)/secp256k1/include
+endif
+
+LIBBITCOIN_SERVER=libbitcoin_server.a
+LIBBITCOIN_WALLET=libbitcoin_wallet.a
+LIBBITCOIN_COMMON=libbitcoin_common.a
+LIBBITCOIN_CLI=libbitcoin_cli.a
+LIBBITCOIN_UTIL=libbitcoin_util.a
+LIBBITCOIN_CRYPTO=crypto/libbitcoin_crypto.a
+LIBBITCOINQT=qt/libbitcoinqt.a
noinst_LIBRARIES = \
libbitcoin_server.a \
libbitcoin_common.a \
- libbitcoin_cli.a
+ libbitcoin_cli.a \
+ libbitcoin_util.a \
+ crypto/libbitcoin_crypto.a
if ENABLE_WALLET
+BITCOIN_INCLUDES += $(BDB_CPPFLAGS)
noinst_LIBRARIES += libbitcoin_wallet.a
endif
bin_PROGRAMS =
+TESTS =
if BUILD_BITCOIND
bin_PROGRAMS += bitcoind
@@ -20,8 +58,6 @@ if BUILD_BITCOIN_CLI
bin_PROGRAMS += bitcoin-cli
endif
-SUBDIRS = . $(BUILD_QT) $(BUILD_TEST)
-DIST_SUBDIRS = . qt test
.PHONY: FORCE
# bitcoin core #
BITCOIN_CORE_H = \
@@ -31,6 +67,7 @@ BITCOIN_CORE_H = \
base58.h \
bloom.h \
chainparams.h \
+ chainparamsbase.h \
checkpoints.h \
checkqueue.h \
clientversion.h \
@@ -52,6 +89,7 @@ BITCOIN_CORE_H = \
netbase.h \
net.h \
noui.h \
+ pow.h \
protocol.h \
rpcclient.h \
rpcprotocol.h \
@@ -60,6 +98,7 @@ BITCOIN_CORE_H = \
serialize.h \
sync.h \
threadsafety.h \
+ timedata.h \
tinyformat.h \
txdb.h \
txmempool.h \
@@ -68,7 +107,8 @@ BITCOIN_CORE_H = \
util.h \
version.h \
walletdb.h \
- wallet.h
+ wallet.h \
+ compat/sanity.h
JSON_H = \
json/json_spirit.h \
@@ -82,35 +122,40 @@ JSON_H = \
json/json_spirit_writer_template.h
obj/build.h: FORCE
- @$(MKDIR_P) $(abs_top_builddir)/src/obj
+ @$(MKDIR_P) $(builddir)/obj
@$(top_srcdir)/share/genbuild.sh $(abs_top_builddir)/src/obj/build.h \
$(abs_top_srcdir)
-version.o: obj/build.h
+libbitcoin_util_a-version.$(OBJEXT): obj/build.h
+# server: shared between bitcoind and bitcoin-qt
+libbitcoin_server_a_CPPFLAGS = $(BITCOIN_INCLUDES)
libbitcoin_server_a_SOURCES = \
addrman.cpp \
alert.cpp \
bloom.cpp \
checkpoints.cpp \
- coins.cpp \
init.cpp \
- keystore.cpp \
leveldbwrapper.cpp \
main.cpp \
miner.cpp \
net.cpp \
noui.cpp \
+ pow.cpp \
rpcblockchain.cpp \
rpcmining.cpp \
rpcmisc.cpp \
rpcnet.cpp \
rpcrawtransaction.cpp \
rpcserver.cpp \
+ timedata.cpp \
txdb.cpp \
txmempool.cpp \
$(JSON_H) \
$(BITCOIN_CORE_H)
+# wallet: shared between bitcoind and bitcoin-qt, but only linked
+# when wallet enabled
+libbitcoin_wallet_a_CPPFLAGS = $(BITCOIN_INCLUDES)
libbitcoin_wallet_a_SOURCES = \
db.cpp \
crypter.cpp \
@@ -120,41 +165,74 @@ libbitcoin_wallet_a_SOURCES = \
walletdb.cpp \
$(BITCOIN_CORE_H)
+# crypto primitives library
+crypto_libbitcoin_crypto_a_CPPFLAGS = $(BITCOIN_CONFIG_INCLUDES)
+crypto_libbitcoin_crypto_a_SOURCES = \
+ crypto/sha1.cpp \
+ crypto/sha2.cpp \
+ crypto/ripemd160.cpp \
+ crypto/common.h \
+ crypto/sha2.h \
+ crypto/sha1.h \
+ crypto/ripemd160.h
+
+# common: shared between bitcoind, and bitcoin-qt and non-server tools
+libbitcoin_common_a_CPPFLAGS = $(BITCOIN_INCLUDES)
libbitcoin_common_a_SOURCES = \
- base58.cpp \
allocators.cpp \
+ base58.cpp \
chainparams.cpp \
+ coins.cpp \
core.cpp \
hash.cpp \
key.cpp \
+ keystore.cpp \
netbase.cpp \
protocol.cpp \
- rpcprotocol.cpp \
script.cpp \
+ $(BITCOIN_CORE_H)
+
+# util: shared between all executables.
+# This library *must* be included to make sure that the glibc
+# backward-compatibility objects and their sanity checks are linked.
+libbitcoin_util_a_CPPFLAGS = $(BITCOIN_INCLUDES)
+libbitcoin_util_a_SOURCES = \
+ chainparamsbase.cpp \
+ rpcprotocol.cpp \
sync.cpp \
+ uint256.cpp \
util.cpp \
version.cpp \
+ compat/glibc_sanity.cpp \
+ compat/glibcxx_sanity.cpp \
$(BITCOIN_CORE_H)
if GLIBC_BACK_COMPAT
-libbitcoin_common_a_SOURCES += compat/glibc_compat.cpp
-libbitcoin_common_a_SOURCES += compat/glibcxx_compat.cpp
+libbitcoin_util_a_SOURCES += compat/glibc_compat.cpp
+libbitcoin_util_a_SOURCES += compat/glibcxx_compat.cpp
endif
+# cli: shared between bitcoin-cli and bitcoin-qt
libbitcoin_cli_a_SOURCES = \
rpcclient.cpp \
$(BITCOIN_CORE_H)
-nodist_libbitcoin_common_a_SOURCES = $(top_srcdir)/src/obj/build.h
+nodist_libbitcoin_util_a_SOURCES = $(srcdir)/obj/build.h
#
# bitcoind binary #
bitcoind_LDADD = \
- libbitcoin_server.a \
- libbitcoin_cli.a \
- libbitcoin_common.a \
+ $(LIBBITCOIN_SERVER) \
+ $(LIBBITCOIN_COMMON) \
+ $(LIBBITCOIN_UTIL) \
+ $(LIBBITCOIN_CRYPTO) \
$(LIBLEVELDB) \
$(LIBMEMENV)
+
+if USE_LIBSECP256K1
+ bitcoind_LDADD += secp256k1/libsecp256k1.la
+endif
+
if ENABLE_WALLET
bitcoind_LDADD += libbitcoin_wallet.a
endif
@@ -165,39 +243,61 @@ if TARGET_WINDOWS
bitcoind_SOURCES += bitcoind-res.rc
endif
-AM_CPPFLAGS += $(BDB_CPPFLAGS)
bitcoind_LDADD += $(BOOST_LIBS) $(BDB_LIBS)
+bitcoind_CPPFLAGS = $(BITCOIN_INCLUDES)
# bitcoin-cli binary #
bitcoin_cli_LDADD = \
- libbitcoin_cli.a \
- libbitcoin_common.a \
+ $(LIBBITCOIN_CLI) \
+ $(LIBBITCOIN_COMMON) \
+ $(LIBBITCOIN_UTIL) \
+ $(LIBBITCOIN_CRYPTO) \
$(BOOST_LIBS)
-bitcoin_cli_SOURCES = bitcoin-cli.cpp
+bitcoin_cli_SOURCES = \
+ bitcoin-cli.cpp
+
+if USE_LIBSECP256K1
+ bitcoin_cli_LDADD += secp256k1/libsecp256k1.la
+endif
+bitcoin_cli_CPPFLAGS = $(BITCOIN_INCLUDES)
#
if TARGET_WINDOWS
bitcoin_cli_SOURCES += bitcoin-cli-res.rc
endif
-# NOTE: This dependency is not strictly necessary, but without it make may try to build both in parallel, which breaks the LevelDB build system in a race
-leveldb/libleveldb.a: leveldb/libmemenv.a
-
-leveldb/%.a:
- @echo "Building LevelDB ..." && $(MAKE) -C $(@D) $(@F) CXX="$(CXX)" \
- CC="$(CC)" PLATFORM=$(TARGET_OS) AR="$(AR)" $(LEVELDB_TARGET_FLAGS) \
- OPT="$(CXXFLAGS) $(CPPFLAGS)"
-
-qt/bitcoinstrings.cpp: $(libbitcoin_server_a_SOURCES) $(libbitcoin_common_a_SOURCES) $(libbitcoin_cli_a_SOURCES)
- @test -n $(XGETTEXT) || echo "xgettext is required for updating translations"
- @cd $(top_srcdir); XGETTEXT=$(XGETTEXT) share/qt/extract_strings_qt.py
-
CLEANFILES = leveldb/libleveldb.a leveldb/libmemenv.a *.gcda *.gcno
DISTCLEANFILES = obj/build.h
-EXTRA_DIST = leveldb Makefile.include
+EXTRA_DIST = leveldb secp256k1
clean-local:
-$(MAKE) -C leveldb clean
+ -$(MAKE) -C secp256k1 clean
rm -f leveldb/*/*.gcno leveldb/helpers/memenv/*.gcno
+ -rm -f config.h
+
+.rc.o:
+ @test -f $(WINDRES)
+ $(AM_V_GEN) $(WINDRES) -i $< -o $@
+
+.mm.o:
+ $(AM_V_CXX) $(OBJCXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CXXFLAGS) $(QT_INCLUDES) $(CXXFLAGS) -c -o $@ $<
+
+%.pb.cc %.pb.h: %.proto
+ @test -f $(PROTOC)
+ $(AM_V_GEN) $(PROTOC) --cpp_out=$(@D) --proto_path=$(abspath $(<D) $<)
+
+if ENABLE_TESTS
+include Makefile.test.include
+endif
+
+if ENABLE_QT
+include Makefile.qt.include
+endif
+
+if ENABLE_QT_TESTS
+include Makefile.qttest.include
+endif
diff --git a/src/Makefile.include b/src/Makefile.include
deleted file mode 100644
index 2fc6cd7775..0000000000
--- a/src/Makefile.include
+++ /dev/null
@@ -1,79 +0,0 @@
-if EMBEDDED_LEVELDB
-LEVELDB_CPPFLAGS += -I$(top_srcdir)/src/leveldb/include
-LEVELDB_CPPFLAGS += -I$(top_srcdir)/src/leveldb/helpers/memenv
-LIBLEVELDB += $(top_builddir)/src/leveldb/libleveldb.a
-LIBMEMENV += $(top_builddir)/src/leveldb/libmemenv.a
-endif
-
-AM_CPPFLAGS = $(INCLUDES) \
- -I$(top_builddir)/src/obj \
- $(BDB_CPPFLAGS) \
- $(BOOST_CPPFLAGS) $(BOOST_INCLUDES)
-AM_CPPFLAGS += $(LEVELDB_CPPFLAGS)
-AM_LDFLAGS = $(PTHREAD_CFLAGS)
-
-LIBBITCOIN_SERVER=$(top_builddir)/src/libbitcoin_server.a
-LIBBITCOIN_WALLET=$(top_builddir)/src/libbitcoin_wallet.a
-LIBBITCOIN_COMMON=$(top_builddir)/src/libbitcoin_common.a
-LIBBITCOIN_CLI=$(top_builddir)/src/libbitcoin_cli.a
-LIBBITCOINQT=$(top_builddir)/src/qt/libbitcoinqt.a
-
-$(LIBBITCOIN):
- $(MAKE) -C $(top_builddir)/src $(@F)
-
-if EMBEDDED_LEVELDB
-$(LIBLEVELDB) $(LIBMEMENV):
- $(MAKE) -C $(top_builddir)/src leveldb/$(@F)
-endif
-
-$(LIBBITCOINQT):
- $(MAKE) -C $(top_builddir)/src/qt $(@F)
-
-.mm.o:
- $(OBJC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
- $(CPPFLAGS) $(AM_CXXFLAGS) $(QT_INCLUDES) $(CXXFLAGS) -c -o $@ $<
-
-.rc.o:
- @test -f $(WINDRES) && $(WINDRES) -i $< -o $@ || \
- echo error: could not build $@
-
-ui_%.h: %.ui
- @test -d $(abs_builddir)/$(@D) || $(MKDIR_P) $(abs_builddir)/$(@D)
- @test -f $(UIC) && QT_SELECT=$(QT_SELECT) $(UIC) -o $(abs_builddir)/$@ $(abs_srcdir)/$< || echo error: could not build $(abs_builddir)/$@
- $(SED) -e '/^\*\*.*Created:/d' $(abs_builddir)/$@ > $(abs_builddir)/$@.n && mv $(abs_builddir)/$@{.n,}
- $(SED) -e '/^\*\*.*by:/d' $(abs_builddir)/$@ > $(abs_builddir)/$@.n && mv $(abs_builddir)/$@{.n,}
-
-%.moc: %.cpp
- QT_SELECT=$(QT_SELECT) $(MOC) $(QT_INCLUDES) $(MOC_DEFS) -o $@ $<
- $(SED) -e '/^\*\*.*Created:/d' $@ > $@.n && mv $@{.n,}
- $(SED) -e '/^\*\*.*by:/d' $@ > $@.n && mv $@{.n,}
-
-moc_%.cpp: %.h
- QT_SELECT=$(QT_SELECT) $(MOC) $(QT_INCLUDES) $(MOC_DEFS) -o $@ $<
- $(SED) -e '/^\*\*.*Created:/d' $@ > $@.n && mv $@{.n,}
- $(SED) -e '/^\*\*.*by:/d' $@ > $@.n && mv $@{.n,}
-
-%.qm: %.ts
- @test -d $(abs_builddir)/$(@D) || $(MKDIR_P) $(abs_builddir)/$(@D)
- @test -f $(LRELEASE) && QT_SELECT=$(QT_SELECT) $(LRELEASE) $(abs_srcdir)/$< -qm $(abs_builddir)/$@ || \
- echo error: could not build $(abs_builddir)/$@
-
-%.pb.cc %.pb.h: %.proto
- test -f $(PROTOC) && $(PROTOC) --cpp_out=$(@D) --proto_path=$(abspath $(<D) $<) || \
- echo error: could not build $@
-
-%.json.h: %.json
- @$(MKDIR_P) $(@D)
- @echo "namespace json_tests{" > $@
- @echo "static unsigned const char $(*F)[] = {" >> $@
- @$(HEXDUMP) -v -e '8/1 "0x%02x, "' -e '"\n"' $< | $(SED) -e 's/0x ,//g' >> $@
- @echo "};};" >> $@
- @echo "Generated $@"
-
-%.raw.h: %.raw
- @$(MKDIR_P) $(@D)
- @echo "namespace alert_tests{" > $@
- @echo "static unsigned const char $(*F)[] = {" >> $@
- @$(HEXDUMP) -v -e '8/1 "0x%02x, "' -e '"\n"' $< | $(SED) -e 's/0x ,//g' >> $@
- @echo "};};" >> $@
- @echo "Generated $@"
diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include
new file mode 100644
index 0000000000..d97c2d064a
--- /dev/null
+++ b/src/Makefile.qt.include
@@ -0,0 +1,417 @@
+bin_PROGRAMS += qt/bitcoin-qt
+noinst_LIBRARIES += qt/libbitcoinqt.a
+
+# bitcoin qt core #
+QT_TS = \
+ qt/locale/bitcoin_ach.ts \
+ qt/locale/bitcoin_af_ZA.ts \
+ qt/locale/bitcoin_ar.ts \
+ qt/locale/bitcoin_be_BY.ts \
+ qt/locale/bitcoin_bg.ts \
+ qt/locale/bitcoin_bs.ts \
+ qt/locale/bitcoin_ca_ES.ts \
+ qt/locale/bitcoin_ca.ts \
+ qt/locale/bitcoin_ca@valencia.ts \
+ qt/locale/bitcoin_cmn.ts \
+ qt/locale/bitcoin_cs.ts \
+ qt/locale/bitcoin_cy.ts \
+ qt/locale/bitcoin_da.ts \
+ qt/locale/bitcoin_de.ts \
+ qt/locale/bitcoin_el_GR.ts \
+ qt/locale/bitcoin_en.ts \
+ qt/locale/bitcoin_eo.ts \
+ qt/locale/bitcoin_es_CL.ts \
+ qt/locale/bitcoin_es_DO.ts \
+ qt/locale/bitcoin_es_MX.ts \
+ qt/locale/bitcoin_es.ts \
+ qt/locale/bitcoin_es_UY.ts \
+ qt/locale/bitcoin_et.ts \
+ qt/locale/bitcoin_eu_ES.ts \
+ qt/locale/bitcoin_fa_IR.ts \
+ qt/locale/bitcoin_fa.ts \
+ qt/locale/bitcoin_fi.ts \
+ qt/locale/bitcoin_fr_CA.ts \
+ qt/locale/bitcoin_fr.ts \
+ qt/locale/bitcoin_gl.ts \
+ qt/locale/bitcoin_gu_IN.ts \
+ qt/locale/bitcoin_he.ts \
+ qt/locale/bitcoin_hi_IN.ts \
+ qt/locale/bitcoin_hr.ts \
+ qt/locale/bitcoin_hu.ts \
+ qt/locale/bitcoin_id_ID.ts \
+ qt/locale/bitcoin_it.ts \
+ qt/locale/bitcoin_ja.ts \
+ qt/locale/bitcoin_ka.ts \
+ qt/locale/bitcoin_kk_KZ.ts \
+ qt/locale/bitcoin_ko_KR.ts \
+ qt/locale/bitcoin_ky.ts \
+ qt/locale/bitcoin_la.ts \
+ qt/locale/bitcoin_lt.ts \
+ qt/locale/bitcoin_lv_LV.ts \
+ qt/locale/bitcoin_mn.ts \
+ qt/locale/bitcoin_ms_MY.ts \
+ qt/locale/bitcoin_nb.ts \
+ qt/locale/bitcoin_nl.ts \
+ qt/locale/bitcoin_pam.ts \
+ qt/locale/bitcoin_pl.ts \
+ qt/locale/bitcoin_pt_BR.ts \
+ qt/locale/bitcoin_pt_PT.ts \
+ qt/locale/bitcoin_ro_RO.ts \
+ qt/locale/bitcoin_ru.ts \
+ qt/locale/bitcoin_sah.ts \
+ qt/locale/bitcoin_sk.ts \
+ qt/locale/bitcoin_sl_SI.ts \
+ qt/locale/bitcoin_sq.ts \
+ qt/locale/bitcoin_sr.ts \
+ qt/locale/bitcoin_sv.ts \
+ qt/locale/bitcoin_th_TH.ts \
+ qt/locale/bitcoin_tr.ts \
+ qt/locale/bitcoin_uk.ts \
+ qt/locale/bitcoin_ur_PK.ts \
+ qt/locale/bitcoin_uz@Cyrl.ts \
+ qt/locale/bitcoin_vi.ts \
+ qt/locale/bitcoin_vi_VN.ts \
+ qt/locale/bitcoin_zh_CN.ts \
+ qt/locale/bitcoin_zh_HK.ts \
+ qt/locale/bitcoin_zh_TW.ts
+
+QT_FORMS_UI = \
+ qt/forms/addressbookpage.ui \
+ qt/forms/askpassphrasedialog.ui \
+ qt/forms/coincontroldialog.ui \
+ qt/forms/editaddressdialog.ui \
+ qt/forms/helpmessagedialog.ui \
+ qt/forms/intro.ui \
+ qt/forms/openuridialog.ui \
+ qt/forms/optionsdialog.ui \
+ qt/forms/overviewpage.ui \
+ qt/forms/receivecoinsdialog.ui \
+ qt/forms/receiverequestdialog.ui \
+ qt/forms/rpcconsole.ui \
+ qt/forms/sendcoinsdialog.ui \
+ qt/forms/sendcoinsentry.ui \
+ qt/forms/signverifymessagedialog.ui \
+ qt/forms/transactiondescdialog.ui
+
+QT_MOC_CPP = \
+ qt/moc_addressbookpage.cpp \
+ qt/moc_addresstablemodel.cpp \
+ qt/moc_askpassphrasedialog.cpp \
+ qt/moc_bitcoinaddressvalidator.cpp \
+ qt/moc_bitcoinamountfield.cpp \
+ qt/moc_bitcoingui.cpp \
+ qt/moc_bitcoinunits.cpp \
+ qt/moc_clientmodel.cpp \
+ qt/moc_coincontroldialog.cpp \
+ qt/moc_coincontroltreewidget.cpp \
+ qt/moc_csvmodelwriter.cpp \
+ qt/moc_editaddressdialog.cpp \
+ qt/moc_guiutil.cpp \
+ qt/moc_intro.cpp \
+ qt/moc_macdockiconhandler.cpp \
+ qt/moc_macnotificationhandler.cpp \
+ qt/moc_monitoreddatamapper.cpp \
+ qt/moc_notificator.cpp \
+ qt/moc_openuridialog.cpp \
+ qt/moc_optionsdialog.cpp \
+ qt/moc_optionsmodel.cpp \
+ qt/moc_overviewpage.cpp \
+ qt/moc_peertablemodel.cpp \
+ qt/moc_paymentserver.cpp \
+ qt/moc_qvalidatedlineedit.cpp \
+ qt/moc_qvaluecombobox.cpp \
+ qt/moc_receivecoinsdialog.cpp \
+ qt/moc_receiverequestdialog.cpp \
+ qt/moc_recentrequeststablemodel.cpp \
+ qt/moc_rpcconsole.cpp \
+ qt/moc_sendcoinsdialog.cpp \
+ qt/moc_sendcoinsentry.cpp \
+ qt/moc_signverifymessagedialog.cpp \
+ qt/moc_splashscreen.cpp \
+ qt/moc_trafficgraphwidget.cpp \
+ qt/moc_transactiondesc.cpp \
+ qt/moc_transactiondescdialog.cpp \
+ qt/moc_transactionfilterproxy.cpp \
+ qt/moc_transactiontablemodel.cpp \
+ qt/moc_transactionview.cpp \
+ qt/moc_utilitydialog.cpp \
+ qt/moc_walletframe.cpp \
+ qt/moc_walletmodel.cpp \
+ qt/moc_walletview.cpp
+
+BITCOIN_MM = \
+ qt/macdockiconhandler.mm \
+ qt/macnotificationhandler.mm
+
+QT_MOC = \
+ qt/bitcoin.moc \
+ qt/intro.moc \
+ qt/overviewpage.moc \
+ qt/rpcconsole.moc
+
+QT_QRC_CPP = qt/qrc_bitcoin.cpp
+QT_QRC = qt/bitcoin.qrc
+QT_QRC_LOCALE_CPP = qt/qrc_bitcoin_locale.cpp
+QT_QRC_LOCALE = qt/bitcoin_locale.qrc
+
+PROTOBUF_CC = qt/paymentrequest.pb.cc
+PROTOBUF_H = qt/paymentrequest.pb.h
+PROTOBUF_PROTO = qt/paymentrequest.proto
+
+BITCOIN_QT_H = \
+ qt/addressbookpage.h \
+ qt/addresstablemodel.h \
+ qt/askpassphrasedialog.h \
+ qt/bitcoinaddressvalidator.h \
+ qt/bitcoinamountfield.h \
+ qt/bitcoingui.h \
+ qt/bitcoinunits.h \
+ qt/clientmodel.h \
+ qt/coincontroldialog.h \
+ qt/coincontroltreewidget.h \
+ qt/csvmodelwriter.h \
+ qt/editaddressdialog.h \
+ qt/guiconstants.h \
+ qt/guiutil.h \
+ qt/intro.h \
+ qt/macdockiconhandler.h \
+ qt/macnotificationhandler.h \
+ qt/monitoreddatamapper.h \
+ qt/notificator.h \
+ qt/openuridialog.h \
+ qt/optionsdialog.h \
+ qt/optionsmodel.h \
+ qt/overviewpage.h \
+ qt/paymentrequestplus.h \
+ qt/paymentserver.h \
+ qt/peertablemodel.h \
+ qt/qvalidatedlineedit.h \
+ qt/qvaluecombobox.h \
+ qt/receivecoinsdialog.h \
+ qt/receiverequestdialog.h \
+ qt/recentrequeststablemodel.h \
+ qt/rpcconsole.h \
+ qt/sendcoinsdialog.h \
+ qt/sendcoinsentry.h \
+ qt/signverifymessagedialog.h \
+ qt/splashscreen.h \
+ qt/trafficgraphwidget.h \
+ qt/transactiondesc.h \
+ qt/transactiondescdialog.h \
+ qt/transactionfilterproxy.h \
+ qt/transactionrecord.h \
+ qt/transactiontablemodel.h \
+ qt/transactionview.h \
+ qt/utilitydialog.h \
+ qt/walletframe.h \
+ qt/walletmodel.h \
+ qt/walletmodeltransaction.h \
+ qt/walletview.h \
+ qt/winshutdownmonitor.h
+
+RES_ICONS = \
+ qt/res/icons/add.png \
+ qt/res/icons/address-book.png \
+ qt/res/icons/bitcoin.ico \
+ qt/res/icons/bitcoin.png \
+ qt/res/icons/bitcoin_testnet.ico \
+ qt/res/icons/bitcoin_testnet.png \
+ qt/res/icons/clock1.png \
+ qt/res/icons/clock2.png \
+ qt/res/icons/clock3.png \
+ qt/res/icons/clock4.png \
+ qt/res/icons/clock5.png \
+ qt/res/icons/configure.png \
+ qt/res/icons/connect0_16.png \
+ qt/res/icons/connect1_16.png \
+ qt/res/icons/connect2_16.png \
+ qt/res/icons/connect3_16.png \
+ qt/res/icons/connect4_16.png \
+ qt/res/icons/debugwindow.png \
+ qt/res/icons/edit.png \
+ qt/res/icons/editcopy.png \
+ qt/res/icons/editpaste.png \
+ qt/res/icons/export.png \
+ qt/res/icons/filesave.png \
+ qt/res/icons/history.png \
+ qt/res/icons/key.png \
+ qt/res/icons/lock_closed.png \
+ qt/res/icons/lock_open.png \
+ qt/res/icons/overview.png \
+ qt/res/icons/qrcode.png \
+ qt/res/icons/quit.png \
+ qt/res/icons/receive.png \
+ qt/res/icons/remove.png \
+ qt/res/icons/send.png \
+ qt/res/icons/synced.png \
+ qt/res/icons/toolbar.png \
+ qt/res/icons/toolbar_testnet.png \
+ qt/res/icons/transaction0.png \
+ qt/res/icons/transaction2.png \
+ qt/res/icons/transaction_conflicted.png \
+ qt/res/icons/tx_inout.png \
+ qt/res/icons/tx_input.png \
+ qt/res/icons/tx_output.png \
+ qt/res/icons/tx_mined.png \
+ qt/res/icons/unit_btc.png \
+ qt/res/icons/unit_mbtc.png \
+ qt/res/icons/unit_ubtc.png
+
+BITCOIN_QT_CPP = \
+ qt/bitcoinaddressvalidator.cpp \
+ qt/bitcoinamountfield.cpp \
+ qt/bitcoingui.cpp \
+ qt/bitcoinunits.cpp \
+ qt/clientmodel.cpp \
+ qt/csvmodelwriter.cpp \
+ qt/guiutil.cpp \
+ qt/intro.cpp \
+ qt/monitoreddatamapper.cpp \
+ qt/notificator.cpp \
+ qt/optionsdialog.cpp \
+ qt/optionsmodel.cpp \
+ qt/peertablemodel.cpp \
+ qt/qvalidatedlineedit.cpp \
+ qt/qvaluecombobox.cpp \
+ qt/rpcconsole.cpp \
+ qt/splashscreen.cpp \
+ qt/trafficgraphwidget.cpp \
+ qt/utilitydialog.cpp \
+ qt/winshutdownmonitor.cpp
+
+if ENABLE_WALLET
+BITCOIN_QT_CPP += \
+ qt/addressbookpage.cpp \
+ qt/addresstablemodel.cpp \
+ qt/askpassphrasedialog.cpp \
+ qt/coincontroldialog.cpp \
+ qt/coincontroltreewidget.cpp \
+ qt/editaddressdialog.cpp \
+ qt/openuridialog.cpp \
+ qt/overviewpage.cpp \
+ qt/paymentrequestplus.cpp \
+ qt/paymentserver.cpp \
+ qt/receivecoinsdialog.cpp \
+ qt/receiverequestdialog.cpp \
+ qt/recentrequeststablemodel.cpp \
+ qt/sendcoinsdialog.cpp \
+ qt/sendcoinsentry.cpp \
+ qt/signverifymessagedialog.cpp \
+ qt/transactiondesc.cpp \
+ qt/transactiondescdialog.cpp \
+ qt/transactionfilterproxy.cpp \
+ qt/transactionrecord.cpp \
+ qt/transactiontablemodel.cpp \
+ qt/transactionview.cpp \
+ qt/walletframe.cpp \
+ qt/walletmodel.cpp \
+ qt/walletmodeltransaction.cpp \
+ qt/walletview.cpp
+endif
+
+RES_IMAGES = \
+ qt/res/images/about.png \
+ qt/res/images/splash.png \
+ qt/res/images/splash_testnet.png
+
+RES_MOVIES = $(wildcard qt/res/movies/spinner-*.png)
+
+BITCOIN_RC = qt/res/bitcoin-qt-res.rc
+
+BITCOIN_QT_INCLUDES = -I$(builddir)/qt -I$(srcdir)/qt -I$(srcdir)/qt/forms \
+ -I$(builddir)/qt/forms
+
+qt_libbitcoinqt_a_CPPFLAGS = $(BITCOIN_INCLUDES) $(BITCOIN_QT_INCLUDES) \
+ $(QT_INCLUDES) $(QT_DBUS_INCLUDES) $(PROTOBUF_CFLAGS) $(QR_CFLAGS)
+
+qt_libbitcoinqt_a_SOURCES = $(BITCOIN_QT_CPP) $(BITCOIN_QT_H) $(QT_FORMS_UI) \
+ $(QT_QRC) $(QT_QRC_LOCALE) $(QT_TS) $(PROTOBUF_PROTO) $(RES_ICONS) $(RES_IMAGES) $(RES_MOVIES)
+
+nodist_qt_libbitcoinqt_a_SOURCES = $(QT_MOC_CPP) $(QT_MOC) $(PROTOBUF_CC) \
+ $(PROTOBUF_H) $(QT_QRC_CPP) $(QT_QRC_LOCALE_CPP)
+
+# forms/foo.h -> forms/ui_foo.h
+QT_FORMS_H=$(join $(dir $(QT_FORMS_UI)),$(addprefix ui_, $(notdir $(QT_FORMS_UI:.ui=.h))))
+
+# Most files will depend on the forms and moc files as includes. Generate them
+# before anything else.
+$(QT_MOC): $(QT_FORMS_H)
+$(qt_libbitcoinqt_a_OBJECTS) $(qt_bitcoin_qt_OBJECTS) : | $(QT_MOC)
+
+#Generating these with a half-written protobuf header leads to wacky results.
+#This makes sure it's done.
+$(QT_MOC): $(PROTOBUF_H)
+$(QT_MOC_CPP): $(PROTOBUF_H)
+
+# bitcoin-qt binary #
+qt_bitcoin_qt_CPPFLAGS = $(BITCOIN_INCLUDES) $(BITCOIN_QT_INCLUDES) \
+ $(QT_INCLUDES) $(PROTOBUF_CFLAGS) $(QR_CFLAGS)
+
+qt_bitcoin_qt_SOURCES = qt/bitcoin.cpp
+if TARGET_DARWIN
+ qt_bitcoin_qt_SOURCES += $(BITCOIN_MM)
+endif
+if TARGET_WINDOWS
+ qt_bitcoin_qt_SOURCES += $(BITCOIN_RC)
+endif
+qt_bitcoin_qt_LDADD = qt/libbitcoinqt.a $(LIBBITCOIN_SERVER)
+if ENABLE_WALLET
+qt_bitcoin_qt_LDADD += $(LIBBITCOIN_WALLET)
+endif
+qt_bitcoin_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBLEVELDB) $(LIBMEMENV) \
+ $(BOOST_LIBS) $(QT_LIBS) $(QT_DBUS_LIBS) $(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS)
+if USE_LIBSECP256K1
+ qt_bitcoin_qt_LDADD += secp256k1/libsecp256k1.la
+endif
+qt_bitcoin_qt_LDFLAGS = $(QT_LDFLAGS)
+
+#locale/foo.ts -> locale/foo.qm
+QT_QM=$(QT_TS:.ts=.qm)
+
+.SECONDARY: $(QT_QM)
+
+qt/bitcoinstrings.cpp: $(libbitcoin_server_a_SOURCES) $(libbitcoin_wallet_a_SOURCES)
+ @test -n $(XGETTEXT) || echo "xgettext is required for updating translations"
+ $(AM_V_GEN) cd $(srcdir); XGETTEXT=$(XGETTEXT) ../share/qt/extract_strings_qt.py $^
+
+translate: qt/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"
+ $(AM_V_GEN) QT_SELECT=$(QT_SELECT) $(LUPDATE) $^ -locations relative -no-obsolete -ts qt/locale/bitcoin_en.ts
+
+$(QT_QRC_LOCALE_CPP): $(QT_QRC_LOCALE) $(QT_QM)
+ @test -f $(RCC)
+ @test -f $(@D)/$(<F) || cp -f $< $(@D)
+ $(AM_V_GEN) QT_SELECT=$(QT_SELECT) $(RCC) -name bitcoin_locale $(@D)/$(<F) | \
+ $(SED) -e '/^\*\*.*Created:/d' -e '/^\*\*.*by:/d' > $@
+
+$(QT_QRC_CPP): $(QT_QRC) $(QT_FORMS_H) $(RES_ICONS) $(RES_IMAGES) $(RES_MOVIES) $(PROTOBUF_H)
+ @test -f $(RCC)
+ $(AM_V_GEN) QT_SELECT=$(QT_SELECT) $(RCC) -name bitcoin $< | \
+ $(SED) -e '/^\*\*.*Created:/d' -e '/^\*\*.*by:/d' > $@
+
+CLEAN_QT = $(nodist_qt_libbitcoinqt_a_SOURCES) $(QT_QM) $(QT_FORMS_H) qt/*.gcda qt/*.gcno
+
+CLEANFILES += $(CLEAN_QT)
+
+bitcoin_qt_clean: FORCE
+ rm -f $(CLEAN_QT) $(qt_libbitcoinqt_a_OBJECTS) $(qt_bitcoin_qt_OBJECTS) qt/bitcoin-qt$(EXEEXT) $(LIBBITCOINQT)
+
+bitcoin_qt : qt/bitcoin-qt$(EXEEXT)
+
+ui_%.h: %.ui
+ @test -f $(UIC)
+ @$(MKDIR_P) $(@D)
+ $(AM_V_GEN) QT_SELECT=$(QT_SELECT) $(UIC) -o $@ $< || (echo "Error creating $@"; false)
+
+%.moc: %.cpp
+ $(AM_V_GEN) QT_SELECT=$(QT_SELECT) $(MOC) $(QT_INCLUDES) $(MOC_DEFS) $< | \
+ $(SED) -e '/^\*\*.*Created:/d' -e '/^\*\*.*by:/d' > $@
+
+moc_%.cpp: %.h
+ $(AM_V_GEN) QT_SELECT=$(QT_SELECT) $(MOC) $(QT_INCLUDES) $(MOC_DEFS) $< | \
+ $(SED) -e '/^\*\*.*Created:/d' -e '/^\*\*.*by:/d' > $@
+
+%.qm: %.ts
+ @test -f $(LRELEASE)
+ @$(MKDIR_P) $(@D)
+ $(AM_V_GEN) QT_SELECT=$(QT_SELECT) $(LRELEASE) -silent $< -qm $@
diff --git a/src/Makefile.qttest.include b/src/Makefile.qttest.include
new file mode 100644
index 0000000000..7e10ce5a96
--- /dev/null
+++ b/src/Makefile.qttest.include
@@ -0,0 +1,51 @@
+bin_PROGRAMS += qt/test/test_bitcoin-qt
+TESTS += qt/test/test_bitcoin-qt
+
+TEST_QT_MOC_CPP = qt/test/moc_uritests.cpp
+
+if ENABLE_WALLET
+TEST_QT_MOC_CPP += qt/test/moc_paymentservertests.cpp
+endif
+
+TEST_QT_H = \
+ qt/test/uritests.h \
+ qt/test/paymentrequestdata.h \
+ qt/test/paymentservertests.h
+
+qt_test_test_bitcoin_qt_CPPFLAGS = $(BITCOIN_INCLUDES) $(BITCOIN_QT_INCLUDES) \
+ $(QT_INCLUDES) $(QT_TEST_INCLUDES)
+
+qt_test_test_bitcoin_qt_SOURCES = \
+ qt/test/test_main.cpp \
+ qt/test/uritests.cpp \
+ $(TEST_QT_H)
+if ENABLE_WALLET
+qt_test_test_bitcoin_qt_SOURCES += \
+ qt/test/paymentservertests.cpp
+endif
+
+nodist_qt_test_test_bitcoin_qt_SOURCES = $(TEST_QT_MOC_CPP)
+
+qt_test_test_bitcoin_qt_LDADD = $(LIBBITCOINQT) $(LIBBITCOIN_SERVER)
+if ENABLE_WALLET
+qt_test_test_bitcoin_qt_LDADD += $(LIBBITCOIN_WALLET)
+endif
+qt_test_test_bitcoin_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBLEVELDB) \
+ $(LIBMEMENV) $(BOOST_LIBS) $(QT_DBUS_LIBS) $(QT_TEST_LIBS) $(QT_LIBS) \
+ $(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS)
+if USE_LIBSECP256K1
+ qt_test_test_bitcoin_qt_LDADD += secp256k1/libsecp256k1.la
+endif
+qt_test_test_bitcoin_qt_LDFLAGS = $(QT_LDFLAGS)
+
+CLEAN_BITCOIN_QT_TEST = $(TEST_QT_MOC_CPP) qt/test/*.gcda qt/test/*.gcno
+
+CLEANFILES += $(CLEAN_BITCOIN_QT_TEST)
+
+test_bitcoin_qt : qt/test/test_bitcoin-qt$(EXEEXT)
+
+test_bitcoin_qt_check : qt/test/test_bitcoin-qt$(EXEEXT) FORCE
+ $(MAKE) check-TESTS TESTS=$^
+
+test_bitcoin_qt_clean: FORCE
+ rm -f $(CLEAN_BITCOIN_QT_TEST) $(qt_test_test_bitcoin_qt_OBJECTS)
diff --git a/src/Makefile.test.include b/src/Makefile.test.include
new file mode 100644
index 0000000000..12b90adca3
--- /dev/null
+++ b/src/Makefile.test.include
@@ -0,0 +1,109 @@
+TESTS += test/test_bitcoin
+bin_PROGRAMS += test/test_bitcoin
+TEST_SRCDIR = test
+TEST_BINARY=test/test_bitcoin$(EXEEXT)
+
+JSON_TEST_FILES = \
+ test/data/script_valid.json \
+ test/data/base58_keys_valid.json \
+ test/data/sig_canonical.json \
+ test/data/sig_noncanonical.json \
+ test/data/base58_encode_decode.json \
+ test/data/base58_keys_invalid.json \
+ test/data/script_invalid.json \
+ test/data/tx_invalid.json \
+ test/data/tx_valid.json \
+ test/data/sighash.json
+
+RAW_TEST_FILES = test/data/alertTests.raw
+
+GENERATED_TEST_FILES = $(JSON_TEST_FILES:.json=.json.h) $(RAW_TEST_FILES:.raw=.raw.h)
+
+BITCOIN_TESTS =\
+ test/bignum.h \
+ test/alert_tests.cpp \
+ test/allocator_tests.cpp \
+ test/base32_tests.cpp \
+ test/base58_tests.cpp \
+ test/base64_tests.cpp \
+ test/bloom_tests.cpp \
+ test/canonical_tests.cpp \
+ test/checkblock_tests.cpp \
+ test/Checkpoints_tests.cpp \
+ test/compress_tests.cpp \
+ test/crypto_tests.cpp \
+ test/DoS_tests.cpp \
+ test/getarg_tests.cpp \
+ test/hash_tests.cpp \
+ test/key_tests.cpp \
+ test/main_tests.cpp \
+ test/miner_tests.cpp \
+ test/mruset_tests.cpp \
+ test/multisig_tests.cpp \
+ test/netbase_tests.cpp \
+ test/pmt_tests.cpp \
+ test/rpc_tests.cpp \
+ test/script_P2SH_tests.cpp \
+ test/script_tests.cpp \
+ test/serialize_tests.cpp \
+ test/sigopcount_tests.cpp \
+ test/skiplist_tests.cpp \
+ test/test_bitcoin.cpp \
+ test/transaction_tests.cpp \
+ test/uint256_tests.cpp \
+ test/util_tests.cpp \
+ test/scriptnum_tests.cpp \
+ test/sighash_tests.cpp
+
+if ENABLE_WALLET
+BITCOIN_TESTS += \
+ test/accounting_tests.cpp \
+ test/wallet_tests.cpp \
+ test/rpc_wallet_tests.cpp
+endif
+
+test_test_bitcoin_SOURCES = $(BITCOIN_TESTS) $(JSON_TEST_FILES) $(RAW_TEST_FILES)
+test_test_bitcoin_CPPFLAGS = $(BITCOIN_INCLUDES) -I$(builddir)/test/ $(TESTDEFS)
+test_test_bitcoin_LDADD = $(LIBBITCOIN_SERVER) $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBLEVELDB) $(LIBMEMENV) \
+ $(BOOST_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIB)
+if ENABLE_WALLET
+test_test_bitcoin_LDADD += $(LIBBITCOIN_WALLET)
+endif
+
+if USE_LIBSECP256K1
+ test_test_bitcoin_LDADD += secp256k1/libsecp256k1.la
+endif
+
+test_test_bitcoin_LDADD += $(BDB_LIBS)
+
+nodist_test_test_bitcoin_SOURCES = $(GENERATED_TEST_FILES)
+
+$(BITCOIN_TESTS): $(GENERATED_TEST_FILES)
+
+CLEAN_BITCOIN_TEST = test/*.gcda test/*.gcno $(GENERATED_TEST_FILES)
+
+CLEANFILES += $(CLEAN_BITCOIN_TEST)
+
+bitcoin_test: $(TEST_BINARY)
+
+bitcoin_test_check: $(TEST_BINARY) FORCE
+ $(MAKE) check-TESTS TESTS=$^
+
+bitcoin_test_clean : FORCE
+ rm -f $(CLEAN_BITCOIN_TEST) $(test_test_bitcoin_OBJECTS) $(TEST_BINARY)
+
+%.json.h: %.json
+ @$(MKDIR_P) $(@D)
+ @echo "namespace json_tests{" > $@
+ @echo "static unsigned const char $(*F)[] = {" >> $@
+ @$(HEXDUMP) -v -e '8/1 "0x%02x, "' -e '"\n"' $< | $(SED) -e 's/0x ,//g' >> $@
+ @echo "};};" >> $@
+ @echo "Generated $@"
+
+%.raw.h: %.raw
+ @$(MKDIR_P) $(@D)
+ @echo "namespace alert_tests{" > $@
+ @echo "static unsigned const char $(*F)[] = {" >> $@
+ @$(HEXDUMP) -v -e '8/1 "0x%02x, "' -e '"\n"' $< | $(SED) -e 's/0x ,//g' >> $@
+ @echo "};};" >> $@
+ @echo "Generated $@"
diff --git a/src/addrman.h b/src/addrman.h
index e2b0cb1093..c4c296560e 100644
--- a/src/addrman.h
+++ b/src/addrman.h
@@ -8,6 +8,7 @@
#include "netbase.h"
#include "protocol.h"
#include "sync.h"
+#include "timedata.h"
#include "util.h"
#include <map>
@@ -420,7 +421,7 @@ public:
Check();
}
if (fRet)
- LogPrint("addrman", "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(), nTried, nNew);
return fRet;
}
@@ -436,7 +437,7 @@ public:
Check();
}
if (nAdd)
- LogPrint("addrman", "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(), nTried, nNew);
return nAdd > 0;
}
diff --git a/src/alert.cpp b/src/alert.cpp
index 99164d63e5..258a2b52c4 100644
--- a/src/alert.cpp
+++ b/src/alert.cpp
@@ -5,8 +5,10 @@
#include "alert.h"
+#include "chainparams.h"
#include "key.h"
#include "net.h"
+#include "timedata.h"
#include "ui_interface.h"
#include "util.h"
diff --git a/src/base58.cpp b/src/base58.cpp
index 5975703887..c9e91beef1 100644
--- a/src/base58.cpp
+++ b/src/base58.cpp
@@ -114,9 +114,8 @@ std::string EncodeBase58Check(const std::vector<unsigned char>& vchIn) {
}
bool DecodeBase58Check(const char* psz, std::vector<unsigned char>& vchRet) {
- if (!DecodeBase58(psz, vchRet))
- return false;
- if (vchRet.size() < 4)
+ if (!DecodeBase58(psz, vchRet) ||
+ (vchRet.size() < 4))
{
vchRet.clear();
return false;
@@ -154,8 +153,8 @@ void CBase58Data::SetData(const std::vector<unsigned char> &vchVersionIn, const
bool CBase58Data::SetString(const char* psz, unsigned int nVersionBytes) {
std::vector<unsigned char> vchTemp;
- DecodeBase58Check(psz, vchTemp);
- if (vchTemp.size() < nVersionBytes) {
+ bool rc58 = DecodeBase58Check(psz, vchTemp);
+ if ((!rc58) || (vchTemp.size() < nVersionBytes)) {
vchData.clear();
vchVersion.clear();
return false;
@@ -187,6 +186,7 @@ int CBase58Data::CompareTo(const CBase58Data& b58) const {
}
namespace {
+
class CBitcoinAddressVisitor : public boost::static_visitor<bool> {
private:
CBitcoinAddress *addr;
@@ -197,7 +197,8 @@ namespace {
bool operator()(const CScriptID &id) const { return addr->Set(id); }
bool operator()(const CNoDestination &no) const { return false; }
};
-};
+
+} // anon namespace
bool CBitcoinAddress::Set(const CKeyID &id) {
SetData(Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS), &id, 20);
diff --git a/src/bitcoin-cli-res.rc b/src/bitcoin-cli-res.rc
index f8bfb3a881..b1aa1b0e16 100644
--- a/src/bitcoin-cli-res.rc
+++ b/src/bitcoin-cli-res.rc
@@ -5,7 +5,6 @@
#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 Core developers"
VS_VERSION_INFO VERSIONINFO
FILEVERSION VER_FILEVERSION
diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp
index ce9e7a4027..016b2f50f5 100644
--- a/src/bitcoin-cli.cpp
+++ b/src/bitcoin-cli.cpp
@@ -7,11 +7,39 @@
#include "init.h"
#include "rpcclient.h"
#include "rpcprotocol.h"
-#include "ui_interface.h" /* for _(...) */
-#include "chainparams.h"
+#include "chainparamsbase.h"
#include <boost/filesystem/operations.hpp>
+#define _(x) std::string(x) /* Keep the _() around in case gettext or such will be used later to translate non-UI */
+
+using namespace std;
+using namespace boost;
+using namespace boost::asio;
+using namespace json_spirit;
+
+std::string HelpMessageCli()
+{
+ string strUsage;
+ strUsage += _("Options:") + "\n";
+ strUsage += " -? " + _("This help message") + "\n";
+ strUsage += " -conf=<file> " + _("Specify configuration file (default: bitcoin.conf)") + "\n";
+ strUsage += " -datadir=<dir> " + _("Specify data directory") + "\n";
+ strUsage += " -testnet " + _("Use the test network") + "\n";
+ strUsage += " -regtest " + _("Enter regression test mode, which uses a special chain in which blocks can be "
+ "solved instantly. This is intended for regression testing tools and app development.") + "\n";
+ strUsage += " -rpcconnect=<ip> " + _("Send commands to node running on <ip> (default: 127.0.0.1)") + "\n";
+ strUsage += " -rpcport=<port> " + _("Connect to JSON-RPC on <port> (default: 8332 or testnet: 18332)") + "\n";
+ strUsage += " -rpcwait " + _("Wait for RPC server to start") + "\n";
+ strUsage += " -rpcuser=<user> " + _("Username for JSON-RPC connections") + "\n";
+ strUsage += " -rpcpassword=<pw> " + _("Password for JSON-RPC connections") + "\n";
+
+ strUsage += "\n" + _("SSL options: (see the Bitcoin Wiki for SSL setup instructions)") + "\n";
+ strUsage += " -rpcssl " + _("Use OpenSSL (https) for JSON-RPC connections") + "\n";
+
+ return strUsage;
+}
+
//////////////////////////////////////////////////////////////////////////////
//
// Start
@@ -33,22 +61,23 @@ static bool AppInitRPC(int argc, char* argv[])
fprintf(stderr,"Error reading configuration file: %s\n", e.what());
return false;
}
- // Check for -testnet or -regtest parameter (TestNet() calls are only valid after this clause)
- if (!SelectParamsFromCommandLine()) {
+ // Check for -testnet or -regtest parameter (BaseParams() calls are only valid after this clause)
+ if (!SelectBaseParamsFromCommandLine()) {
fprintf(stderr, "Error: Invalid combination of -regtest and -testnet.\n");
return false;
}
-
- if (argc<2 || mapArgs.count("-?") || mapArgs.count("--help"))
+ if (argc<2 || mapArgs.count("-?") || mapArgs.count("-help") || mapArgs.count("-version"))
{
- // First part of help message is specific to RPC client
- std::string strUsage = _("Bitcoin Core RPC client version") + " " + FormatFullVersion() + "\n\n" +
- _("Usage:") + "\n" +
- " bitcoin-cli [options] <command> [params] " + _("Send command to Bitcoin Core") + "\n" +
- " bitcoin-cli [options] help " + _("List commands") + "\n" +
- " bitcoin-cli [options] help <command> " + _("Get help for a command") + "\n";
+ std::string strUsage = _("Bitcoin Core RPC client version") + " " + FormatFullVersion() + "\n";
+ if (!mapArgs.count("-version"))
+ {
+ strUsage += "\n" + _("Usage:") + "\n" +
+ " bitcoin-cli [options] <command> [params] " + _("Send command to Bitcoin Core") + "\n" +
+ " bitcoin-cli [options] help " + _("List commands") + "\n" +
+ " bitcoin-cli [options] help <command> " + _("Get help for a command") + "\n";
- strUsage += "\n" + HelpMessageCli(true);
+ strUsage += "\n" + HelpMessageCli();
+ }
fprintf(stdout, "%s", strUsage.c_str());
return false;
@@ -56,6 +85,136 @@ static bool AppInitRPC(int argc, char* argv[])
return true;
}
+Object CallRPC(const string& strMethod, const Array& params)
+{
+ if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
+ throw runtime_error(strprintf(
+ _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
+ "If the file does not exist, create it with owner-readable-only file permissions."),
+ GetConfigFile().string().c_str()));
+
+ // Connect to localhost
+ bool fUseSSL = GetBoolArg("-rpcssl", false);
+ asio::io_service io_service;
+ ssl::context context(io_service, ssl::context::sslv23);
+ context.set_options(ssl::context::no_sslv2);
+ asio::ssl::stream<asio::ip::tcp::socket> sslStream(io_service, context);
+ SSLIOStreamDevice<asio::ip::tcp> d(sslStream, fUseSSL);
+ iostreams::stream< SSLIOStreamDevice<asio::ip::tcp> > stream(d);
+
+ bool fWait = GetBoolArg("-rpcwait", false); // -rpcwait means try until server has started
+ do {
+ bool fConnected = d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", itostr(BaseParams().RPCPort())));
+ if (fConnected) break;
+ if (fWait)
+ MilliSleep(1000);
+ else
+ throw runtime_error("couldn't connect to server");
+ } while (fWait);
+
+ // HTTP basic authentication
+ string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
+ map<string, string> mapRequestHeaders;
+ mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
+
+ // Send request
+ string strRequest = JSONRPCRequest(strMethod, params, 1);
+ string strPost = HTTPPost(strRequest, mapRequestHeaders);
+ stream << strPost << std::flush;
+
+ // Receive HTTP reply status
+ int nProto = 0;
+ int nStatus = ReadHTTPStatus(stream, nProto);
+
+ // Receive HTTP reply message headers and body
+ map<string, string> mapHeaders;
+ string strReply;
+ ReadHTTPMessage(stream, mapHeaders, strReply, nProto);
+
+ if (nStatus == HTTP_UNAUTHORIZED)
+ throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
+ else if (nStatus >= 400 && nStatus != HTTP_BAD_REQUEST && nStatus != HTTP_NOT_FOUND && nStatus != HTTP_INTERNAL_SERVER_ERROR)
+ throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
+ else if (strReply.empty())
+ throw runtime_error("no response from server");
+
+ // Parse reply
+ Value valReply;
+ if (!read_string(strReply, valReply))
+ throw runtime_error("couldn't parse reply from server");
+ const Object& reply = valReply.get_obj();
+ if (reply.empty())
+ throw runtime_error("expected reply to have result, error and id properties");
+
+ return reply;
+}
+
+int CommandLineRPC(int argc, char *argv[])
+{
+ string strPrint;
+ int nRet = 0;
+ try
+ {
+ // Skip switches
+ while (argc > 1 && IsSwitchChar(argv[1][0]))
+ {
+ argc--;
+ argv++;
+ }
+
+ // Method
+ if (argc < 2)
+ throw runtime_error("too few parameters");
+ string strMethod = argv[1];
+
+ // Parameters default to strings
+ std::vector<std::string> strParams(&argv[2], &argv[argc]);
+ Array params = RPCConvertValues(strMethod, strParams);
+
+ // Execute
+ Object reply = CallRPC(strMethod, params);
+
+ // Parse reply
+ const Value& result = find_value(reply, "result");
+ const Value& error = find_value(reply, "error");
+
+ if (error.type() != null_type)
+ {
+ // Error
+ strPrint = "error: " + write_string(error, false);
+ int code = find_value(error.get_obj(), "code").get_int();
+ nRet = abs(code);
+ }
+ else
+ {
+ // Result
+ if (result.type() == null_type)
+ strPrint = "";
+ else if (result.type() == str_type)
+ strPrint = result.get_str();
+ else
+ strPrint = write_string(result, true);
+ }
+ }
+ catch (boost::thread_interrupted) {
+ throw;
+ }
+ catch (std::exception& e) {
+ strPrint = string("error: ") + e.what();
+ nRet = EXIT_FAILURE;
+ }
+ catch (...) {
+ PrintExceptionContinue(NULL, "CommandLineRPC()");
+ throw;
+ }
+
+ if (strPrint != "")
+ {
+ fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
+ }
+ return nRet;
+}
+
int main(int argc, char* argv[])
{
SetupEnvironment();
@@ -63,17 +222,17 @@ int main(int argc, char* argv[])
try
{
if(!AppInitRPC(argc, argv))
- return abs(RPC_MISC_ERROR);
+ return EXIT_FAILURE;
}
catch (std::exception& e) {
PrintExceptionContinue(&e, "AppInitRPC()");
- return abs(RPC_MISC_ERROR);
+ return EXIT_FAILURE;
} catch (...) {
PrintExceptionContinue(NULL, "AppInitRPC()");
- return abs(RPC_MISC_ERROR);
+ return EXIT_FAILURE;
}
- int ret = abs(RPC_MISC_ERROR);
+ int ret = EXIT_FAILURE;
try
{
ret = CommandLineRPC(argc, argv);
diff --git a/src/bitcoind-res.rc b/src/bitcoind-res.rc
index dc5c56b797..2e6d754495 100644
--- a/src/bitcoind-res.rc
+++ b/src/bitcoind-res.rc
@@ -5,7 +5,6 @@
#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 Core developers"
VS_VERSION_INFO VERSIONINFO
FILEVERSION VER_FILEVERSION
diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp
index 9b535c2e6b..880955481b 100644
--- a/src/bitcoind.cpp
+++ b/src/bitcoind.cpp
@@ -4,7 +4,6 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "rpcserver.h"
-#include "rpcclient.h"
#include "init.h"
#include "main.h"
#include "noui.h"
@@ -77,25 +76,27 @@ bool AppInit(int argc, char* argv[])
fprintf(stderr,"Error reading configuration file: %s\n", e.what());
return false;
}
- // Check for -testnet or -regtest parameter (TestNet() calls are only valid after this clause)
+ // Check for -testnet or -regtest parameter (Params() calls are only valid after this clause)
if (!SelectParamsFromCommandLine()) {
fprintf(stderr, "Error: Invalid combination of -regtest and -testnet.\n");
return false;
}
- if (mapArgs.count("-?") || mapArgs.count("--help"))
+ if (mapArgs.count("-?") || mapArgs.count("-help") || mapArgs.count("-version"))
{
- // First part of help message is specific to bitcoind / RPC client
- std::string strUsage = _("Bitcoin Core Daemon") + " " + _("version") + " " + FormatFullVersion() + "\n\n" +
- _("Usage:") + "\n" +
- " bitcoind [options] " + _("Start Bitcoin Core Daemon") + "\n" +
- _("Usage (deprecated, use bitcoin-cli):") + "\n" +
- " bitcoind [options] <command> [params] " + _("Send command to Bitcoin Core") + "\n" +
- " bitcoind [options] help " + _("List commands") + "\n" +
- " bitcoind [options] help <command> " + _("Get help for a command") + "\n";
-
- strUsage += "\n" + HelpMessage(HMM_BITCOIND);
- strUsage += "\n" + HelpMessageCli(false);
+ std::string strUsage = _("Bitcoin Core Daemon") + " " + _("version") + " " + FormatFullVersion() + "\n";
+
+ if (mapArgs.count("-version"))
+ {
+ strUsage += LicenseInfo();
+ }
+ else
+ {
+ strUsage += "\n" + _("Usage:") + "\n" +
+ " bitcoind [options] " + _("Start Bitcoin Core Daemon") + "\n";
+
+ strUsage += "\n" + HelpMessage(HMM_BITCOIND);
+ }
fprintf(stdout, "%s", strUsage.c_str());
return false;
@@ -109,8 +110,8 @@ bool AppInit(int argc, char* argv[])
if (fCommandLine)
{
- int ret = CommandLineRPC(argc, argv);
- exit(ret);
+ fprintf(stderr, "Error: There is no RPC client functionality in bitcoind anymore. Use the bitcoin-cli utility instead.\n");
+ exit(1);
}
#ifndef WIN32
fDaemon = GetBoolArg("-daemon", false);
diff --git a/src/bloom.cpp b/src/bloom.cpp
index 1bfcbd406f..85a2ddc189 100644
--- a/src/bloom.cpp
+++ b/src/bloom.cpp
@@ -94,12 +94,19 @@ bool CBloomFilter::contains(const uint256& hash) const
return contains(data);
}
+void CBloomFilter::clear()
+{
+ vData.assign(vData.size(),0);
+ isFull = false;
+ isEmpty = true;
+}
+
bool CBloomFilter::IsWithinSizeConstraints() const
{
return vData.size() <= MAX_BLOOM_FILTER_SIZE && nHashFuncs <= MAX_HASH_FUNCS;
}
-bool CBloomFilter::IsRelevantAndUpdate(const CTransaction& tx, const uint256& hash)
+bool CBloomFilter::IsRelevantAndUpdate(const CTransaction& tx)
{
bool fFound = false;
// Match if the filter contains the hash of tx
@@ -108,6 +115,7 @@ bool CBloomFilter::IsRelevantAndUpdate(const CTransaction& tx, const uint256& ha
return true;
if (isEmpty)
return false;
+ const uint256& hash = tx.GetHash();
if (contains(hash))
fFound = true;
diff --git a/src/bloom.h b/src/bloom.h
index 75e3f38c55..d0caf9e9fa 100644
--- a/src/bloom.h
+++ b/src/bloom.h
@@ -78,12 +78,14 @@ public:
bool contains(const COutPoint& outpoint) const;
bool contains(const uint256& hash) const;
+ void clear();
+
// True if the size is <= MAX_BLOOM_FILTER_SIZE and the number of hash functions is <= MAX_HASH_FUNCS
// (catch a filter which was just deserialized which was too big)
bool IsWithinSizeConstraints() const;
// Also adds any outputs which match the filter to the filter (to match their spending txes)
- bool IsRelevantAndUpdate(const CTransaction& tx, const uint256& hash);
+ bool IsRelevantAndUpdate(const CTransaction& tx);
// Checks for empty and full filters to avoid wasting cpu
void UpdateEmptyFull();
diff --git a/src/chainparams.cpp b/src/chainparams.cpp
index f5cf846a01..63067a153d 100644
--- a/src/chainparams.cpp
+++ b/src/chainparams.cpp
@@ -6,12 +6,11 @@
#include "chainparams.h"
#include "assert.h"
-#include "core.h"
-#include "protocol.h"
#include "util.h"
#include <boost/assign/list_of.hpp>
+using namespace std;
using namespace boost::assign;
//
@@ -100,6 +99,8 @@ unsigned int pnSeed[] =
class CMainParams : public CChainParams {
public:
CMainParams() {
+ networkID = CBaseChainParams::MAIN;
+ strNetworkID = "main";
// The message start string is designed to be unlikely to occur in normal data.
// The characters are rarely used upper ASCII, not valid as UTF-8, and produce
// a large 4-byte int at any alignment.
@@ -109,9 +110,14 @@ public:
pchMessageStart[3] = 0xd9;
vAlertPubKey = ParseHex("04fc9702847840aaf195de8442ebecedf5b095cdbb9bc716bda9110971b28a49e0ead8564ff0db22209e0374782c093bb899692d524e9d6a6956e7c5ecbcd68284");
nDefaultPort = 8333;
- nRPCPort = 8332;
bnProofOfWorkLimit = ~uint256(0) >> 32;
nSubsidyHalvingInterval = 210000;
+ nEnforceBlockUpgradeMajority = 750;
+ nRejectBlockOutdatedMajority = 950;
+ nToCheckBlockUpgradeMajority = 1000;
+ nMinerThreads = 0;
+ nTargetTimespan = 14 * 24 * 60 * 60; // two weeks
+ nTargetSpacing = 10 * 60;
// Build the genesis block. Note that the output of the genesis coinbase cannot
// be spent as it did not originally exist in the database.
@@ -122,7 +128,7 @@ public:
// CTxOut(nValue=50.00000000, scriptPubKey=0x5F1DF16B2B704C8A578D0B)
// vMerkleTree: 4a5e1e
const char* pszTimestamp = "The Times 03/Jan/2009 Chancellor on brink of second bailout for banks";
- CTransaction txNew;
+ CMutableTransaction txNew;
txNew.vin.resize(1);
txNew.vout.resize(1);
txNew.vin[0].scriptSig = CScript() << 486604799 << CScriptNum(4) << vector<unsigned char>((const unsigned char*)pszTimestamp, (const unsigned char*)pszTimestamp + strlen(pszTimestamp));
@@ -167,27 +173,25 @@ public:
addr.nTime = GetTime() - GetRand(nOneWeek) - nOneWeek;
vFixedSeeds.push_back(addr);
}
- }
-
- virtual const CBlock& GenesisBlock() const { return genesis; }
- virtual Network NetworkID() const { return CChainParams::MAIN; }
- virtual const vector<CAddress>& FixedSeeds() const {
- return vFixedSeeds;
+ fRequireRPCPassword = true;
+ fMiningRequiresPeers = true;
+ fDefaultCheckMemPool = false;
+ fAllowMinDifficultyBlocks = false;
+ fRequireStandard = true;
+ fMineBlocksOnDemand = false;
}
-protected:
- CBlock genesis;
- vector<CAddress> vFixedSeeds;
};
static CMainParams mainParams;
-
//
// Testnet (v3)
//
class CTestNetParams : public CMainParams {
public:
CTestNetParams() {
+ networkID = CBaseChainParams::TESTNET;
+ strNetworkID = "test";
// The message start string is designed to be unlikely to occur in normal data.
// The characters are rarely used upper ASCII, not valid as UTF-8, and produce
// a large 4-byte int at any alignment.
@@ -197,8 +201,12 @@ public:
pchMessageStart[3] = 0x07;
vAlertPubKey = ParseHex("04302390343f91cc401d56d68b123028bf52e5fca1939df127f63c6467cdf9c8e2c14b61104cf817d0b780da337893ecc4aaff1309e536162dabbdb45200ca2b0a");
nDefaultPort = 18333;
- nRPCPort = 18332;
- strDataDir = "testnet3";
+ nEnforceBlockUpgradeMajority = 51;
+ nRejectBlockOutdatedMajority = 75;
+ nToCheckBlockUpgradeMajority = 100;
+ nMinerThreads = 0;
+ nTargetTimespan = 14 * 24 * 60 * 60; // two weeks
+ nTargetSpacing = 10 * 60;
// Modify the testnet genesis block so the timestamp is valid for a later start.
genesis.nTime = 1296688602;
@@ -208,6 +216,7 @@ public:
vFixedSeeds.clear();
vSeeds.clear();
+ vSeeds.push_back(CDNSSeedData("alexykot.me", "testnet-seed.alexykot.me"));
vSeeds.push_back(CDNSSeedData("bitcoin.petertodd.org", "testnet-seed.bitcoin.petertodd.org"));
vSeeds.push_back(CDNSSeedData("bluematt.me", "testnet-seed.bluematt.me"));
@@ -216,55 +225,73 @@ public:
base58Prefixes[SECRET_KEY] = list_of(239);
base58Prefixes[EXT_PUBLIC_KEY] = list_of(0x04)(0x35)(0x87)(0xCF);
base58Prefixes[EXT_SECRET_KEY] = list_of(0x04)(0x35)(0x83)(0x94);
+
+ fRequireRPCPassword = true;
+ fMiningRequiresPeers = true;
+ fDefaultCheckMemPool = false;
+ fAllowMinDifficultyBlocks = true;
+ fRequireStandard = false;
+ fMineBlocksOnDemand = false;
}
- virtual Network NetworkID() const { return CChainParams::TESTNET; }
};
static CTestNetParams testNetParams;
-
//
// Regression test
//
class CRegTestParams : public CTestNetParams {
public:
CRegTestParams() {
+ networkID = CBaseChainParams::REGTEST;
+ strNetworkID = "regtest";
pchMessageStart[0] = 0xfa;
pchMessageStart[1] = 0xbf;
pchMessageStart[2] = 0xb5;
pchMessageStart[3] = 0xda;
nSubsidyHalvingInterval = 150;
+ nEnforceBlockUpgradeMajority = 750;
+ nRejectBlockOutdatedMajority = 950;
+ nToCheckBlockUpgradeMajority = 1000;
+ nMinerThreads = 1;
+ nTargetTimespan = 14 * 24 * 60 * 60; // two weeks
+ nTargetSpacing = 10 * 60;
bnProofOfWorkLimit = ~uint256(0) >> 1;
genesis.nTime = 1296688602;
genesis.nBits = 0x207fffff;
genesis.nNonce = 2;
hashGenesisBlock = genesis.GetHash();
nDefaultPort = 18444;
- strDataDir = "regtest";
assert(hashGenesisBlock == uint256("0x0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206"));
vSeeds.clear(); // Regtest mode doesn't have any DNS seeds.
- }
- virtual bool RequireRPCPassword() const { return false; }
- virtual Network NetworkID() const { return CChainParams::REGTEST; }
+ fRequireRPCPassword = false;
+ fMiningRequiresPeers = false;
+ fDefaultCheckMemPool = true;
+ fAllowMinDifficultyBlocks = true;
+ fRequireStandard = false;
+ fMineBlocksOnDemand = true;
+ }
};
static CRegTestParams regTestParams;
-static CChainParams *pCurrentParams = &mainParams;
+static CChainParams *pCurrentParams = 0;
const CChainParams &Params() {
+ assert(pCurrentParams);
return *pCurrentParams;
}
-void SelectParams(CChainParams::Network network) {
+void SelectParams(CBaseChainParams::Network network) {
+ SelectBaseParams(network);
switch (network) {
- case CChainParams::MAIN:
+ case CBaseChainParams::MAIN:
pCurrentParams = &mainParams;
break;
- case CChainParams::TESTNET:
+ case CBaseChainParams::TESTNET:
pCurrentParams = &testNetParams;
break;
- case CChainParams::REGTEST:
+ case CBaseChainParams::REGTEST:
pCurrentParams = &regTestParams;
break;
default:
@@ -274,19 +301,9 @@ void SelectParams(CChainParams::Network network) {
}
bool SelectParamsFromCommandLine() {
- bool fRegTest = GetBoolArg("-regtest", false);
- bool fTestNet = GetBoolArg("-testnet", false);
-
- if (fTestNet && fRegTest) {
+ if (!SelectBaseParamsFromCommandLine())
return false;
- }
- if (fRegTest) {
- SelectParams(CChainParams::REGTEST);
- } else if (fTestNet) {
- SelectParams(CChainParams::TESTNET);
- } else {
- SelectParams(CChainParams::MAIN);
- }
+ SelectParams(BaseParams().NetworkID());
return true;
}
diff --git a/src/chainparams.h b/src/chainparams.h
index 5600b904cc..446256ba82 100644
--- a/src/chainparams.h
+++ b/src/chainparams.h
@@ -6,21 +6,18 @@
#ifndef BITCOIN_CHAIN_PARAMS_H
#define BITCOIN_CHAIN_PARAMS_H
+#include "core.h"
+#include "chainparamsbase.h"
+#include "protocol.h"
#include "uint256.h"
#include <vector>
-using namespace std;
-
-#define MESSAGE_START_SIZE 4
typedef unsigned char MessageStartChars[MESSAGE_START_SIZE];
-class CAddress;
-class CBlock;
-
struct CDNSSeedData {
- string name, host;
- CDNSSeedData(const string &strName, const string &strHost) : name(strName), host(strHost) {}
+ std::string name, host;
+ CDNSSeedData(const std::string &strName, const std::string &strHost) : name(strName), host(strHost) {}
};
/**
@@ -33,14 +30,6 @@ struct CDNSSeedData {
class CChainParams
{
public:
- enum Network {
- MAIN,
- TESTNET,
- REGTEST,
-
- MAX_NETWORK_TYPES
- };
-
enum Base58Type {
PUBKEY_ADDRESS,
SCRIPT_ADDRESS,
@@ -53,32 +42,67 @@ public:
const uint256& HashGenesisBlock() const { return hashGenesisBlock; }
const MessageStartChars& MessageStart() const { return pchMessageStart; }
- const vector<unsigned char>& AlertKey() const { return vAlertPubKey; }
+ const std::vector<unsigned char>& AlertKey() const { return vAlertPubKey; }
int GetDefaultPort() const { return nDefaultPort; }
const uint256& ProofOfWorkLimit() const { return bnProofOfWorkLimit; }
int SubsidyHalvingInterval() const { return nSubsidyHalvingInterval; }
- virtual const CBlock& GenesisBlock() const = 0;
- virtual bool RequireRPCPassword() const { return true; }
- const string& DataDir() const { return strDataDir; }
- virtual Network NetworkID() const = 0;
- const vector<CDNSSeedData>& DNSSeeds() const { return vSeeds; }
- const std::vector<unsigned char> &Base58Prefix(Base58Type type) const { return base58Prefixes[type]; }
- virtual const vector<CAddress>& FixedSeeds() const = 0;
- int RPCPort() const { return nRPCPort; }
+ /* Used to check majorities for block version upgrade */
+ int EnforceBlockUpgradeMajority() const { return nEnforceBlockUpgradeMajority; }
+ int RejectBlockOutdatedMajority() const { return nRejectBlockOutdatedMajority; }
+ int ToCheckBlockUpgradeMajority() const { return nToCheckBlockUpgradeMajority; }
+
+ /* Used if GenerateBitcoins is called with a negative number of threads */
+ int DefaultMinerThreads() const { return nMinerThreads; }
+ const CBlock& GenesisBlock() const { return genesis; }
+ bool RequireRPCPassword() const { return fRequireRPCPassword; }
+ /* Make miner wait to have peers to avoid wasting work */
+ bool MiningRequiresPeers() const { return fMiningRequiresPeers; }
+ /* Default value for -checkmempool argument */
+ bool DefaultCheckMemPool() const { return fDefaultCheckMemPool; }
+ /* Allow mining of a min-difficulty block */
+ bool AllowMinDifficultyBlocks() const { return fAllowMinDifficultyBlocks; }
+ /* Make standard checks */
+ bool RequireStandard() const { return fRequireStandard; }
+ int64_t TargetTimespan() const { return nTargetTimespan; }
+ int64_t TargetSpacing() const { return nTargetSpacing; }
+ int64_t Interval() const { return nTargetTimespan / nTargetSpacing; }
+ /* Make miner stop after a block is found. In RPC, don't return
+ * until nGenProcLimit blocks are generated */
+ bool MineBlocksOnDemand() const { return fMineBlocksOnDemand; }
+ CBaseChainParams::Network NetworkID() const { return networkID; }
+ /* Return the BIP70 network string (main, test or regtest) */
+ std::string NetworkIDString() const { return strNetworkID; }
+ const std::vector<CDNSSeedData>& DNSSeeds() const { return vSeeds; }
+ const std::vector<unsigned char>& Base58Prefix(Base58Type type) const { return base58Prefixes[type]; }
+ const std::vector<CAddress>& FixedSeeds() const { return vFixedSeeds; }
protected:
CChainParams() {}
uint256 hashGenesisBlock;
MessageStartChars pchMessageStart;
// Raw pub key bytes for the broadcast alert signing key.
- vector<unsigned char> vAlertPubKey;
+ std::vector<unsigned char> vAlertPubKey;
int nDefaultPort;
- int nRPCPort;
uint256 bnProofOfWorkLimit;
int nSubsidyHalvingInterval;
- string strDataDir;
- vector<CDNSSeedData> vSeeds;
+ int nEnforceBlockUpgradeMajority;
+ int nRejectBlockOutdatedMajority;
+ int nToCheckBlockUpgradeMajority;
+ int64_t nTargetTimespan;
+ int64_t nTargetSpacing;
+ int nMinerThreads;
+ std::vector<CDNSSeedData> vSeeds;
std::vector<unsigned char> base58Prefixes[MAX_BASE58_TYPES];
+ CBaseChainParams::Network networkID;
+ std::string strNetworkID;
+ CBlock genesis;
+ std::vector<CAddress> vFixedSeeds;
+ bool fRequireRPCPassword;
+ bool fMiningRequiresPeers;
+ bool fDefaultCheckMemPool;
+ bool fAllowMinDifficultyBlocks;
+ bool fRequireStandard;
+ bool fMineBlocksOnDemand;
};
/**
@@ -88,7 +112,7 @@ protected:
const CChainParams &Params();
/** Sets the params returned by Params() to those for the given network. */
-void SelectParams(CChainParams::Network network);
+void SelectParams(CBaseChainParams::Network network);
/**
* Looks for -regtest or -testnet and then calls SelectParams as appropriate.
@@ -96,13 +120,4 @@ void SelectParams(CChainParams::Network network);
*/
bool SelectParamsFromCommandLine();
-inline bool TestNet() {
- // Note: it's deliberate that this returns "false" for regression test mode.
- return Params().NetworkID() == CChainParams::TESTNET;
-}
-
-inline bool RegTest() {
- return Params().NetworkID() == CChainParams::REGTEST;
-}
-
#endif
diff --git a/src/chainparamsbase.cpp b/src/chainparamsbase.cpp
new file mode 100644
index 0000000000..19a9e72cc9
--- /dev/null
+++ b/src/chainparamsbase.cpp
@@ -0,0 +1,93 @@
+// Copyright (c) 2010 Satoshi Nakamoto
+// Copyright (c) 2009-2014 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 "chainparamsbase.h"
+
+#include "assert.h"
+#include "util.h"
+
+#include <boost/assign/list_of.hpp>
+
+using namespace boost::assign;
+
+//
+// Main network
+//
+
+class CBaseMainParams : public CBaseChainParams {
+public:
+ CBaseMainParams() {
+ networkID = CBaseChainParams::MAIN;
+ nRPCPort = 8332;
+ }
+};
+static CBaseMainParams mainParams;
+
+//
+// Testnet (v3)
+//
+class CBaseTestNetParams : public CBaseMainParams {
+public:
+ CBaseTestNetParams() {
+ networkID = CBaseChainParams::TESTNET;
+ nRPCPort = 18332;
+ strDataDir = "testnet3";
+ }
+};
+static CBaseTestNetParams testNetParams;
+
+//
+// Regression test
+//
+class CBaseRegTestParams : public CBaseTestNetParams {
+public:
+ CBaseRegTestParams() {
+ networkID = CBaseChainParams::REGTEST;
+ strDataDir = "regtest";
+ }
+};
+static CBaseRegTestParams regTestParams;
+
+static CBaseChainParams *pCurrentBaseParams = 0;
+
+const CBaseChainParams &BaseParams() {
+ assert(pCurrentBaseParams);
+ return *pCurrentBaseParams;
+}
+
+void SelectBaseParams(CBaseChainParams::Network network) {
+ switch (network) {
+ case CBaseChainParams::MAIN:
+ pCurrentBaseParams = &mainParams;
+ break;
+ case CBaseChainParams::TESTNET:
+ pCurrentBaseParams = &testNetParams;
+ break;
+ case CBaseChainParams::REGTEST:
+ pCurrentBaseParams = &regTestParams;
+ break;
+ default:
+ assert(false && "Unimplemented network");
+ return;
+ }
+}
+
+bool SelectBaseParamsFromCommandLine() {
+ bool fRegTest = GetBoolArg("-regtest", false);
+ bool fTestNet = GetBoolArg("-testnet", false);
+
+ if (fTestNet && fRegTest) {
+ return false;
+ }
+
+ if (fRegTest) {
+ SelectBaseParams(CBaseChainParams::REGTEST);
+ } else if (fTestNet) {
+ SelectBaseParams(CBaseChainParams::TESTNET);
+ } else {
+ SelectBaseParams(CBaseChainParams::MAIN);
+ }
+ return true;
+}
diff --git a/src/chainparamsbase.h b/src/chainparamsbase.h
new file mode 100644
index 0000000000..4a3b268909
--- /dev/null
+++ b/src/chainparamsbase.h
@@ -0,0 +1,52 @@
+// Copyright (c) 2014 The Bitcoin developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_CHAIN_PARAMS_BASE_H
+#define BITCOIN_CHAIN_PARAMS_BASE_H
+
+#include <vector>
+#include <string>
+
+/**
+ * CBaseChainParams defines the base parameters (shared between bitcoin-cli and bitcoind)
+ * of a given instance of the Bitcoin system.
+ */
+class CBaseChainParams
+{
+public:
+ enum Network {
+ MAIN,
+ TESTNET,
+ REGTEST,
+
+ MAX_NETWORK_TYPES
+ };
+
+ const std::string& DataDir() const { return strDataDir; }
+ int RPCPort() const { return nRPCPort; }
+ Network NetworkID() const { return networkID; }
+protected:
+ CBaseChainParams() {}
+
+ int nRPCPort;
+ std::string strDataDir;
+ Network networkID;
+};
+
+/**
+ * Return the currently selected parameters. This won't change after app startup
+ * outside of the unit tests.
+ */
+const CBaseChainParams &BaseParams();
+
+/** Sets the params returned by Params() to those for the given network. */
+void SelectBaseParams(CBaseChainParams::Network network);
+
+/**
+ * Looks for -regtest or -testnet and then calls SelectParams as appropriate.
+ * Returns false if an invalid combination is given.
+ */
+bool SelectBaseParamsFromCommandLine();
+
+#endif
diff --git a/src/checkpoints.cpp b/src/checkpoints.cpp
index 9ab8b68443..4cab11db3d 100644
--- a/src/checkpoints.cpp
+++ b/src/checkpoints.cpp
@@ -12,8 +12,8 @@
#include <boost/assign/list_of.hpp> // for 'map_list_of()'
#include <boost/foreach.hpp>
-namespace Checkpoints
-{
+namespace Checkpoints {
+
typedef std::map<int, uint256> MapCheckpoints;
// How many times we expect transactions after the last checkpoint to
@@ -66,8 +66,8 @@ namespace Checkpoints
;
static const CCheckpointData dataTestnet = {
&mapCheckpointsTestnet,
- 1338180505,
- 16341,
+ 1337966069,
+ 1488,
300
};
@@ -83,9 +83,9 @@ namespace Checkpoints
};
const CCheckpointData &Checkpoints() {
- if (Params().NetworkID() == CChainParams::TESTNET)
+ if (Params().NetworkID() == CBaseChainParams::TESTNET)
return dataTestnet;
- else if (Params().NetworkID() == CChainParams::MAIN)
+ else if (Params().NetworkID() == CBaseChainParams::MAIN)
return data;
else
return dataRegtest;
@@ -127,7 +127,7 @@ namespace Checkpoints
} else {
double nCheapBefore = data.nTransactionsLastCheckpoint;
double nExpensiveBefore = pindex->nChainTx - data.nTransactionsLastCheckpoint;
- double nExpensiveAfter = (nNow - pindex->nTime)/86400.0*data.fTransactionsPerDay;
+ double nExpensiveAfter = (nNow - pindex->GetBlockTime())/86400.0*data.fTransactionsPerDay;
fWorkBefore = nCheapBefore + nExpensiveBefore*fSigcheckVerificationFactor;
fWorkAfter = nExpensiveAfter*fSigcheckVerificationFactor;
}
@@ -161,4 +161,5 @@ namespace Checkpoints
}
return NULL;
}
-}
+
+} // namespace Checkpoints
diff --git a/src/checkpoints.h b/src/checkpoints.h
index 1b4aacee20..2cf8d41b9d 100644
--- a/src/checkpoints.h
+++ b/src/checkpoints.h
@@ -13,8 +13,8 @@ class uint256;
/** Block-chain checkpoints are compiled-in sanity checks.
* They are updated every release or three.
*/
-namespace Checkpoints
-{
+namespace Checkpoints {
+
// Returns true if block passes checkpoint checks
bool CheckBlock(int nHeight, const uint256& hash);
@@ -27,6 +27,7 @@ namespace Checkpoints
double GuessVerificationProgress(CBlockIndex *pindex, bool fSigchecks = true);
extern bool fEnabled;
-}
+
+} //namespace Checkpoints
#endif
diff --git a/src/clientversion.h b/src/clientversion.h
index 29b4aa3764..6c718a9f79 100644
--- a/src/clientversion.h
+++ b/src/clientversion.h
@@ -2,13 +2,13 @@
#define CLIENTVERSION_H
#if defined(HAVE_CONFIG_H)
-#include "bitcoin-config.h"
+#include "config/bitcoin-config.h"
#else
//
// client versioning and copyright year
//
-// These need to be macros, as version.cpp's and bitcoin-qt.rc's voodoo requires it
+// These need to be macros, as version.cpp's and bitcoin*-res.rc's voodoo requires it
#define CLIENT_VERSION_MAJOR 0
#define CLIENT_VERSION_MINOR 9
#define CLIENT_VERSION_REVISION 99
@@ -28,4 +28,7 @@
#define STRINGIZE(X) DO_STRINGIZE(X)
#define DO_STRINGIZE(X) #X
+// Copyright string used in Windows .rc files
+#define COPYRIGHT_STR "2009-" STRINGIZE(COPYRIGHT_YEAR) " The Bitcoin Core Developers"
+
#endif // CLIENTVERSION_H
diff --git a/src/coins.cpp b/src/coins.cpp
index 86b2a6ef17..13a4ea95cd 100644
--- a/src/coins.cpp
+++ b/src/coins.cpp
@@ -55,7 +55,7 @@ bool CCoinsView::SetCoins(const uint256 &txid, const CCoins &coins) { return fal
bool CCoinsView::HaveCoins(const uint256 &txid) { return false; }
uint256 CCoinsView::GetBestBlock() { return uint256(0); }
bool CCoinsView::SetBestBlock(const uint256 &hashBlock) { return false; }
-bool CCoinsView::BatchWrite(const std::map<uint256, CCoins> &mapCoins, const uint256 &hashBlock) { return false; }
+bool CCoinsView::BatchWrite(const CCoinsMap &mapCoins, const uint256 &hashBlock) { return false; }
bool CCoinsView::GetStats(CCoinsStats &stats) { return false; }
@@ -66,7 +66,7 @@ bool CCoinsViewBacked::HaveCoins(const uint256 &txid) { return base->HaveCoins(t
uint256 CCoinsViewBacked::GetBestBlock() { return base->GetBestBlock(); }
bool CCoinsViewBacked::SetBestBlock(const uint256 &hashBlock) { return base->SetBestBlock(hashBlock); }
void CCoinsViewBacked::SetBackend(CCoinsView &viewIn) { base = &viewIn; }
-bool CCoinsViewBacked::BatchWrite(const std::map<uint256, CCoins> &mapCoins, const uint256 &hashBlock) { return base->BatchWrite(mapCoins, hashBlock); }
+bool CCoinsViewBacked::BatchWrite(const CCoinsMap &mapCoins, const uint256 &hashBlock) { return base->BatchWrite(mapCoins, hashBlock); }
bool CCoinsViewBacked::GetStats(CCoinsStats &stats) { return base->GetStats(stats); }
CCoinsViewCache::CCoinsViewCache(CCoinsView &baseIn, bool fDummy) : CCoinsViewBacked(baseIn), hashBlock(0) { }
@@ -83,20 +83,20 @@ bool CCoinsViewCache::GetCoins(const uint256 &txid, CCoins &coins) {
return false;
}
-std::map<uint256,CCoins>::iterator CCoinsViewCache::FetchCoins(const uint256 &txid) {
- std::map<uint256,CCoins>::iterator it = cacheCoins.lower_bound(txid);
+CCoinsMap::iterator CCoinsViewCache::FetchCoins(const uint256 &txid) {
+ CCoinsMap::iterator it = cacheCoins.lower_bound(txid);
if (it != cacheCoins.end() && it->first == txid)
return it;
CCoins tmp;
if (!base->GetCoins(txid,tmp))
return cacheCoins.end();
- std::map<uint256,CCoins>::iterator ret = cacheCoins.insert(it, std::make_pair(txid, CCoins()));
+ CCoinsMap::iterator ret = cacheCoins.insert(it, std::make_pair(txid, CCoins()));
tmp.swap(ret->second);
return ret;
}
CCoins &CCoinsViewCache::GetCoins(const uint256 &txid) {
- std::map<uint256,CCoins>::iterator it = FetchCoins(txid);
+ CCoinsMap::iterator it = FetchCoins(txid);
assert(it != cacheCoins.end());
return it->second;
}
@@ -121,8 +121,8 @@ bool CCoinsViewCache::SetBestBlock(const uint256 &hashBlockIn) {
return true;
}
-bool CCoinsViewCache::BatchWrite(const std::map<uint256, CCoins> &mapCoins, const uint256 &hashBlockIn) {
- for (std::map<uint256, CCoins>::const_iterator it = mapCoins.begin(); it != mapCoins.end(); it++)
+bool CCoinsViewCache::BatchWrite(const CCoinsMap &mapCoins, const uint256 &hashBlockIn) {
+ for (CCoinsMap::const_iterator it = mapCoins.begin(); it != mapCoins.end(); it++)
cacheCoins[it->first] = it->second;
hashBlock = hashBlockIn;
return true;
diff --git a/src/coins.h b/src/coins.h
index 0ad28524a1..c57a5ec722 100644
--- a/src/coins.h
+++ b/src/coins.h
@@ -239,6 +239,7 @@ public:
}
};
+typedef std::map<uint256,CCoins> CCoinsMap;
struct CCoinsStats
{
@@ -275,7 +276,7 @@ public:
virtual bool SetBestBlock(const uint256 &hashBlock);
// Do a bulk modification (multiple SetCoins + one SetBestBlock)
- virtual bool BatchWrite(const std::map<uint256, CCoins> &mapCoins, const uint256 &hashBlock);
+ virtual bool BatchWrite(const CCoinsMap &mapCoins, const uint256 &hashBlock);
// Calculate statistics about the unspent transaction output set
virtual bool GetStats(CCoinsStats &stats);
@@ -299,7 +300,7 @@ public:
uint256 GetBestBlock();
bool SetBestBlock(const uint256 &hashBlock);
void SetBackend(CCoinsView &viewIn);
- bool BatchWrite(const std::map<uint256, CCoins> &mapCoins, const uint256 &hashBlock);
+ bool BatchWrite(const CCoinsMap &mapCoins, const uint256 &hashBlock);
bool GetStats(CCoinsStats &stats);
};
@@ -309,7 +310,7 @@ class CCoinsViewCache : public CCoinsViewBacked
{
protected:
uint256 hashBlock;
- std::map<uint256,CCoins> cacheCoins;
+ CCoinsMap cacheCoins;
public:
CCoinsViewCache(CCoinsView &baseIn, bool fDummy = false);
@@ -320,7 +321,7 @@ public:
bool HaveCoins(const uint256 &txid);
uint256 GetBestBlock();
bool SetBestBlock(const uint256 &hashBlock);
- bool BatchWrite(const std::map<uint256, CCoins> &mapCoins, const uint256 &hashBlock);
+ bool BatchWrite(const CCoinsMap &mapCoins, const uint256 &hashBlock);
// Return a modifiable reference to a CCoins. Check HaveCoins first.
// Many methods explicitly require a CCoinsViewCache because of this method, to reduce
@@ -352,7 +353,7 @@ public:
const CTxOut &GetOutputFor(const CTxIn& input);
private:
- std::map<uint256,CCoins>::iterator FetchCoins(const uint256 &txid);
+ CCoinsMap::iterator FetchCoins(const uint256 &txid);
};
#endif
diff --git a/src/compat/glibc_compat.cpp b/src/compat/glibc_compat.cpp
index 5b73e6051a..22f82e4259 100644
--- a/src/compat/glibc_compat.cpp
+++ b/src/compat/glibc_compat.cpp
@@ -1,19 +1,28 @@
-#include "bitcoin-config.h"
+// Copyright (c) 2009-2014 The Bitcoin developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#if defined(HAVE_CONFIG_H)
+#include "config/bitcoin-config.h"
+#endif
+
#include <cstddef>
+#if defined(HAVE_SYS_SELECT_H)
#include <sys/select.h>
+#endif
// Prior to GLIBC_2.14, memcpy was aliased to memmove.
extern "C" void* memmove(void* a, const void* b, size_t c);
extern "C" void* memcpy(void* a, const void* b, size_t c)
{
- return memmove(a, b, c);
+ return memmove(a, b, c);
}
extern "C" void __chk_fail (void) __attribute__((__noreturn__));
extern "C" FDELT_TYPE __fdelt_warn(FDELT_TYPE a)
{
- if (a >= FD_SETSIZE)
- __chk_fail ();
- return a / __NFDBITS;
+ if (a >= FD_SETSIZE)
+ __chk_fail ();
+ return a / __NFDBITS;
}
extern "C" FDELT_TYPE __fdelt_chk(FDELT_TYPE) __attribute__((weak, alias("__fdelt_warn")));
diff --git a/src/compat/glibc_sanity.cpp b/src/compat/glibc_sanity.cpp
new file mode 100644
index 0000000000..d93602e0fe
--- /dev/null
+++ b/src/compat/glibc_sanity.cpp
@@ -0,0 +1,67 @@
+// Copyright (c) 2009-2014 The Bitcoin developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#if defined(HAVE_CONFIG_H)
+#include "config/bitcoin-config.h"
+#endif
+
+#include <cstddef>
+#if defined(HAVE_SYS_SELECT_H)
+#include <sys/select.h>
+#endif
+
+extern "C" void* memcpy(void* a, const void* b, size_t c);
+void* memcpy_int(void* a, const void* b, size_t c)
+{
+ return memcpy(a,b,c);
+}
+
+namespace {
+// trigger: Use the memcpy_int wrapper which calls our internal memcpy.
+// A direct call to memcpy may be optimized away by the compiler.
+// test: Fill an array with a sequence of integers. memcpy to a new empty array.
+// Verify that the arrays are equal. Use an odd size to decrease the odds of
+// the call being optimized away.
+template <unsigned int T>
+bool sanity_test_memcpy()
+{
+ unsigned int memcpy_test[T];
+ unsigned int memcpy_verify[T] = {};
+ for (unsigned int i = 0; i != T; ++i)
+ memcpy_test[i] = i;
+
+ memcpy_int(memcpy_verify,memcpy_test,sizeof(memcpy_test));
+
+ for (unsigned int i = 0; i != T; ++i)
+ {
+ if(memcpy_verify[i] != i)
+ return false;
+ }
+ return true;
+}
+
+#if defined(HAVE_SYS_SELECT_H)
+// trigger: Call FD_SET to trigger __fdelt_chk. FORTIFY_SOURCE must be defined
+// as >0 and optimizations must be set to at least -O2.
+// test: Add a file descriptor to an empty fd_set. Verify that it has been
+// correctly added.
+bool sanity_test_fdelt()
+{
+ fd_set fds;
+ FD_ZERO(&fds);
+ FD_SET(0, &fds);
+ return FD_ISSET(0,&fds);
+}
+#endif
+
+} // anon namespace
+
+bool glibc_sanity_test()
+{
+#if defined(HAVE_SYS_SELECT_H)
+ if (!sanity_test_fdelt())
+ return false;
+#endif
+ return sanity_test_memcpy<1025>();
+}
diff --git a/src/compat/glibcxx_compat.cpp b/src/compat/glibcxx_compat.cpp
index e91376f818..417166aeda 100644
--- a/src/compat/glibcxx_compat.cpp
+++ b/src/compat/glibcxx_compat.cpp
@@ -1,49 +1,55 @@
+// Copyright (c) 2009-2014 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 <cstddef>
#include <istream>
#include <stdexcept>
#include <typeinfo>
#ifndef _GLIBCXX_USE_NOEXCEPT
- #define _GLIBCXX_USE_NOEXCEPT throw()
+#define _GLIBCXX_USE_NOEXCEPT throw()
#endif
namespace std {
const char* bad_exception::what() const throw()
{
- return "std::bad_exception";
+ return "std::bad_exception";
}
const char* bad_cast::what() const throw()
{
- return "std::bad_cast";
+ return "std::bad_cast";
}
const char* bad_alloc::what() const throw()
{
- return "std::bad_alloc";
+ return "std::bad_alloc";
}
namespace __detail
{
struct _List_node_base
{
- void _M_hook(std::__detail::_List_node_base* const __position) throw () __attribute__((used))
- {
- _M_next = __position;
- _M_prev = __position->_M_prev;
- __position->_M_prev->_M_next = this;
- __position->_M_prev = this;
- }
- void _M_unhook() __attribute__((used))
- {
- _List_node_base* const __next_node = _M_next;
- _List_node_base* const __prev_node = _M_prev;
- __prev_node->_M_next = __next_node;
- __next_node->_M_prev = __prev_node;
- }
- _List_node_base* _M_next;
- _List_node_base* _M_prev;
+ void _M_hook(std::__detail::_List_node_base* const __position) throw () __attribute__((used))
+ {
+ _M_next = __position;
+ _M_prev = __position->_M_prev;
+ __position->_M_prev->_M_next = this;
+ __position->_M_prev = this;
+ }
+
+ void _M_unhook() __attribute__((used))
+ {
+ _List_node_base* const __next_node = _M_next;
+ _List_node_base* const __prev_node = _M_prev;
+ __prev_node->_M_next = __next_node;
+ __next_node->_M_prev = __prev_node;
+ }
+
+ _List_node_base* _M_next;
+ _List_node_base* _M_prev;
};
} // namespace detail
@@ -61,8 +67,8 @@ out_of_range::~out_of_range() _GLIBCXX_USE_NOEXCEPT { }
// Used with permission.
// See: https://github.com/madlib/madlib/commit/c3db418c0d34d6813608f2137fef1012ce03043d
-void
-ctype<char>::_M_widen_init() const {
+void ctype<char>::_M_widen_init() const
+{
char __tmp[sizeof(_M_widen)];
for (unsigned __i = 0; __i < sizeof(_M_widen); ++__i)
__tmp[__i] = __i;
diff --git a/src/compat/glibcxx_sanity.cpp b/src/compat/glibcxx_sanity.cpp
new file mode 100644
index 0000000000..cd8da4fd67
--- /dev/null
+++ b/src/compat/glibcxx_sanity.cpp
@@ -0,0 +1,65 @@
+// Copyright (c) 2009-2014 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 <list>
+#include <locale>
+#include <stdexcept>
+
+namespace{
+
+// trigger: use ctype<char>::widen to trigger ctype<char>::_M_widen_init().
+// test: convert a char from narrow to wide and back. Verify that the result
+// matches the original.
+bool sanity_test_widen(char testchar)
+{
+ const std::ctype<char>& test(std::use_facet< std::ctype<char> >(std::locale()));
+ return test.narrow(test.widen(testchar),'b') == testchar;
+}
+
+// trigger: use list::push_back and list::pop_back to trigger _M_hook and
+// _M_unhook.
+// test: Push a sequence of integers into a list. Pop them off and verify that
+// they match the original sequence.
+bool sanity_test_list(unsigned int size)
+{
+ std::list<unsigned int> test;
+ for (unsigned int i = 0; i != size; ++i)
+ test.push_back(i+1);
+
+ if (test.size() != size)
+ return false;
+
+ while (!test.empty())
+ {
+ if(test.back() != test.size())
+ return false;
+ test.pop_back();
+ }
+ return true;
+}
+
+} // anon namespace
+
+// trigger: string::at(x) on an empty string to trigger __throw_out_of_range_fmt.
+// test: force std::string to throw an out_of_range exception. Verify that
+// it's caught correctly.
+bool sanity_test_range_fmt()
+{
+ std::string test;
+ try
+ {
+ test.at(1);
+ }
+ catch (const std::out_of_range&)
+ {
+ return true;
+ }
+ catch (...){}
+ return false;
+}
+
+bool glibcxx_sanity_test()
+{
+ return sanity_test_widen('a') && sanity_test_list(100) && sanity_test_range_fmt();
+}
diff --git a/src/compat/sanity.h b/src/compat/sanity.h
new file mode 100644
index 0000000000..e7df44307a
--- /dev/null
+++ b/src/compat/sanity.h
@@ -0,0 +1,11 @@
+// Copyright (c) 2009-2014 The Bitcoin developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCON_COMPAT_SANITY_H
+#define BITCON_COMPAT_SANITY_H
+
+bool glibc_sanity_test();
+bool glibcxx_sanity_test();
+
+#endif // BITCON_COMPAT_SANITY_H
diff --git a/src/config/.empty b/src/config/.empty
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/src/config/.empty
diff --git a/src/core.cpp b/src/core.cpp
index 7651ce9957..b56994ecf3 100644
--- a/src/core.cpp
+++ b/src/core.cpp
@@ -72,38 +72,72 @@ void CTxOut::print() const
LogPrintf("%s\n", ToString());
}
-uint256 CTransaction::GetHash() const
+CFeeRate::CFeeRate(int64_t nFeePaid, size_t nSize)
+{
+ if (nSize > 0)
+ nSatoshisPerK = nFeePaid*1000/nSize;
+ else
+ nSatoshisPerK = 0;
+}
+
+int64_t CFeeRate::GetFee(size_t nSize) const
+{
+ int64_t nFee = nSatoshisPerK*nSize / 1000;
+
+ if (nFee == 0 && nSatoshisPerK > 0)
+ nFee = nSatoshisPerK;
+
+ return nFee;
+}
+
+std::string CFeeRate::ToString() const
+{
+ std::string result = FormatMoney(nSatoshisPerK) + " BTC/kB";
+ return result;
+}
+
+CMutableTransaction::CMutableTransaction() : nVersion(CTransaction::CURRENT_VERSION), nLockTime(0) {}
+CMutableTransaction::CMutableTransaction(const CTransaction& tx) : nVersion(tx.nVersion), vin(tx.vin), vout(tx.vout), nLockTime(tx.nLockTime) {}
+
+uint256 CMutableTransaction::GetHash() const
{
return SerializeHash(*this);
}
-bool CTransaction::IsNewerThan(const CTransaction& old) const
+void CTransaction::UpdateHash() const
{
- if (vin.size() != old.vin.size())
- return false;
- for (unsigned int i = 0; i < vin.size(); i++)
- if (vin[i].prevout != old.vin[i].prevout)
- return false;
+ *const_cast<uint256*>(&hash) = SerializeHash(*this);
+}
+
+CTransaction::CTransaction() : hash(0), nVersion(CTransaction::CURRENT_VERSION), vin(), vout(), nLockTime(0) { }
- bool fNewer = false;
- unsigned int nLowest = std::numeric_limits<unsigned int>::max();
+CTransaction::CTransaction(const CMutableTransaction &tx) : nVersion(tx.nVersion), vin(tx.vin), vout(tx.vout), nLockTime(tx.nLockTime) {
+ UpdateHash();
+}
+
+CTransaction& CTransaction::operator=(const CTransaction &tx) {
+ *const_cast<int*>(&nVersion) = tx.nVersion;
+ *const_cast<std::vector<CTxIn>*>(&vin) = tx.vin;
+ *const_cast<std::vector<CTxOut>*>(&vout) = tx.vout;
+ *const_cast<unsigned int*>(&nLockTime) = tx.nLockTime;
+ *const_cast<uint256*>(&hash) = tx.hash;
+ return *this;
+}
+
+bool CTransaction::IsEquivalentTo(const CTransaction& tx) const
+{
+ if (nVersion != tx.nVersion ||
+ nLockTime != tx.nLockTime ||
+ vin.size() != tx.vin.size() ||
+ vout != tx.vout)
+ return false;
for (unsigned int i = 0; i < vin.size(); i++)
{
- if (vin[i].nSequence != old.vin[i].nSequence)
- {
- if (vin[i].nSequence <= nLowest)
- {
- fNewer = false;
- nLowest = vin[i].nSequence;
- }
- if (old.vin[i].nSequence < nLowest)
- {
- fNewer = true;
- nLowest = old.vin[i].nSequence;
- }
- }
+ if (vin[i].nSequence != tx.vin[i].nSequence ||
+ vin[i].prevout != tx.vin[i].prevout)
+ return false;
}
- return fNewer;
+ return true;
}
int64_t CTransaction::GetValueOut() const
diff --git a/src/core.h b/src/core.h
index 5eb953610d..0387336c98 100644
--- a/src/core.h
+++ b/src/core.h
@@ -112,6 +112,32 @@ public:
+/** Type-safe wrapper class to for fee rates
+ * (how much to pay based on transaction size)
+ */
+class CFeeRate
+{
+private:
+ int64_t nSatoshisPerK; // unit is satoshis-per-1,000-bytes
+public:
+ CFeeRate() : nSatoshisPerK(0) { }
+ explicit CFeeRate(int64_t _nSatoshisPerK): nSatoshisPerK(_nSatoshisPerK) { }
+ CFeeRate(int64_t nFeePaid, size_t nSize);
+ CFeeRate(const CFeeRate& other) { nSatoshisPerK = other.nSatoshisPerK; }
+
+ int64_t GetFee(size_t size) const; // unit returned is satoshis
+ int64_t GetFeePerK() const { return GetFee(1000); } // satoshis-per-1000-bytes
+
+ friend bool operator<(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK < b.nSatoshisPerK; }
+ friend bool operator>(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK > b.nSatoshisPerK; }
+ friend bool operator==(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK == b.nSatoshisPerK; }
+ friend bool operator<=(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK <= b.nSatoshisPerK; }
+ friend bool operator>=(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK >= b.nSatoshisPerK; }
+ std::string ToString() const;
+
+ IMPLEMENT_SERIALIZE( READWRITE(nSatoshisPerK); )
+};
+
/** An output of a transaction. It contains the public key that the next input
* must be able to sign with to claim it.
@@ -148,17 +174,18 @@ public:
uint256 GetHash() const;
- bool IsDust(int64_t nMinRelayTxFee) const
+ bool IsDust(CFeeRate minRelayTxFee) const
{
- // "Dust" is defined in terms of CTransaction::nMinRelayTxFee,
+ // "Dust" is defined in terms of CTransaction::minRelayTxFee,
// which has units satoshis-per-kilobyte.
// If you'd pay more than 1/3 in fees
// to spend something, then we consider it dust.
// A typical txout is 34 bytes big, and will
- // need a CTxIn of at least 148 bytes to spend,
+ // need a CTxIn of at least 148 bytes to spend:
// so dust is a txout less than 546 satoshis
- // with default nMinRelayTxFee.
- return ((nValue*1000)/(3*((int)GetSerializeSize(SER_DISK,0)+148)) < nMinRelayTxFee);
+ // with default minRelayTxFee.
+ size_t nSize = GetSerializeSize(SER_DISK,0)+148u;
+ return (nValue < 3*minRelayTxFee.GetFee(nSize));
}
friend bool operator==(const CTxOut& a, const CTxOut& b)
@@ -177,49 +204,59 @@ public:
};
+struct CMutableTransaction;
+
/** The basic transaction that is broadcasted on the network and contained in
* blocks. A transaction can contain multiple inputs and outputs.
*/
class CTransaction
{
+private:
+ /** Memory only. */
+ const uint256 hash;
+ void UpdateHash() const;
+
public:
- static int64_t nMinTxFee;
- static int64_t nMinRelayTxFee;
static const int CURRENT_VERSION=1;
- int nVersion;
- std::vector<CTxIn> vin;
- std::vector<CTxOut> vout;
- unsigned int nLockTime;
- CTransaction()
- {
- SetNull();
- }
+ // The local variables are made const to prevent unintended modification
+ // without updating the cached hash value. However, CTransaction is not
+ // actually immutable; deserialization and assignment are implemented,
+ // and bypass the constness. This is safe, as they update the entire
+ // structure, including the hash.
+ const int nVersion;
+ const std::vector<CTxIn> vin;
+ const std::vector<CTxOut> vout;
+ const unsigned int nLockTime;
- IMPLEMENT_SERIALIZE
- (
- READWRITE(this->nVersion);
+ /** Construct a CTransaction that qualifies as IsNull() */
+ CTransaction();
+
+ /** Convert a CMutableTransaction into a CTransaction. */
+ CTransaction(const CMutableTransaction &tx);
+
+ CTransaction& operator=(const CTransaction& tx);
+
+ IMPLEMENT_SERIALIZE(
+ READWRITE(*const_cast<int*>(&this->nVersion));
nVersion = this->nVersion;
- READWRITE(vin);
- READWRITE(vout);
- READWRITE(nLockTime);
+ READWRITE(*const_cast<std::vector<CTxIn>*>(&vin));
+ READWRITE(*const_cast<std::vector<CTxOut>*>(&vout));
+ READWRITE(*const_cast<unsigned int*>(&nLockTime));
+ if (fRead)
+ UpdateHash();
)
- void SetNull()
- {
- nVersion = CTransaction::CURRENT_VERSION;
- vin.clear();
- vout.clear();
- nLockTime = 0;
+ bool IsNull() const {
+ return vin.empty() && vout.empty();
}
- bool IsNull() const
- {
- return (vin.empty() && vout.empty());
+ const uint256& GetHash() const {
+ return hash;
}
- uint256 GetHash() const;
- bool IsNewerThan(const CTransaction& old) const;
+ // True if only scriptSigs are different
+ bool IsEquivalentTo(const CTransaction& tx) const;
// Return sum of txouts.
int64_t GetValueOut() const;
@@ -236,22 +273,43 @@ public:
friend bool operator==(const CTransaction& a, const CTransaction& b)
{
- return (a.nVersion == b.nVersion &&
- a.vin == b.vin &&
- a.vout == b.vout &&
- a.nLockTime == b.nLockTime);
+ return a.hash == b.hash;
}
friend bool operator!=(const CTransaction& a, const CTransaction& b)
{
- return !(a == b);
+ return a.hash != b.hash;
}
-
std::string ToString() const;
void print() const;
};
+/** A mutable version of CTransaction. */
+struct CMutableTransaction
+{
+ int nVersion;
+ std::vector<CTxIn> vin;
+ std::vector<CTxOut> vout;
+ unsigned int nLockTime;
+
+ CMutableTransaction();
+ CMutableTransaction(const CTransaction& tx);
+
+ IMPLEMENT_SERIALIZE(
+ READWRITE(this->nVersion);
+ nVersion = this->nVersion;
+ READWRITE(vin);
+ READWRITE(vout);
+ READWRITE(nLockTime);
+ )
+
+ /** Compute the hash of this CMutableTransaction. This is computed on the
+ * fly, as opposed to GetHash() in CTransaction, which uses a cached result.
+ */
+ uint256 GetHash() const;
+};
+
/** wrapper for CTxOut that provides a more compact serialization */
class CTxOutCompressor
{
@@ -440,12 +498,6 @@ public:
uint256 BuildMerkleTree() const;
- const uint256 &GetTxHash(unsigned int nIndex) const {
- assert(vMerkleTree.size() > 0); // BuildMerkleTree must have been called first
- assert(nIndex < vtx.size());
- return vMerkleTree[nIndex];
- }
-
std::vector<uint256> GetMerkleBranch(int nIndex) const;
static uint256 CheckMerkleBranch(uint256 hash, const std::vector<uint256>& vMerkleBranch, int nIndex);
void print() const;
diff --git a/src/crypto/common.h b/src/crypto/common.h
new file mode 100644
index 0000000000..8f675a16c5
--- /dev/null
+++ b/src/crypto/common.h
@@ -0,0 +1,93 @@
+// Copyright (c) 2014 The Bitcoin developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_CRYPTO_COMMON_H
+#define BITCOIN_CRYPTO_COMMON_H
+
+#if defined(HAVE_CONFIG_H)
+#include "bitcoin-config.h"
+#endif
+#include <stdint.h>
+#if defined(HAVE_ENDIAN_H)
+#include <endian.h>
+#endif
+
+uint32_t static inline ReadLE32(const unsigned char *ptr) {
+#if HAVE_DECL_LE32TOH == 1
+ return le32toh(*((uint32_t*)ptr));
+#elif !defined(WORDS_BIGENDIAN)
+ return *((uint32_t*)ptr);
+#else
+ return ((uint32_t)ptr[3] << 24 | (uint32_t)ptr[2] << 16 | (uint32_t)ptr[1] << 8 | (uint32_t)ptr[0]);
+#endif
+}
+
+uint64_t static inline ReadLE64(const unsigned char *ptr) {
+
+#if HAVE_DECL_LE64TOH == 1
+ return le64toh(*((uint64_t*)ptr));
+#elif !defined(WORDS_BIGENDIAN)
+ return *((uint64_t*)ptr);
+#else
+ return ((uint64_t)ptr[7] << 56 | (uint64_t)ptr[6] << 48 | (uint64_t)ptr[5] << 40 | (uint64_t)ptr[4] << 32 |
+ (uint64_t)ptr[3] << 24 | (uint64_t)ptr[2] << 16 | (uint64_t)ptr[1] << 8 | (uint64_t)ptr[0]);
+#endif
+}
+
+void static inline WriteLE32(unsigned char *ptr, uint32_t x) {
+#if HAVE_DECL_HTOLE32 == 1
+ *((uint32_t*)ptr) = htole32(x);
+#elif !defined(WORDS_BIGENDIAN)
+ *((uint32_t*)ptr) = x;
+#else
+ ptr[3] = x >> 24; ptr[2] = x >> 16; ptr[1] = x >> 8; ptr[0] = x;
+#endif
+}
+
+void static inline WriteLE64(unsigned char *ptr, uint64_t x) {
+#if HAVE_DECL_HTOLE64 == 1
+ *((uint64_t*)ptr) = htole64(x);
+#elif !defined(WORDS_BIGENDIAN)
+ *((uint64_t*)ptr) = x;
+#else
+ ptr[7] = x >> 56; ptr[6] = x >> 48; ptr[5] = x >> 40; ptr[4] = x >> 32;
+ ptr[3] = x >> 24; ptr[2] = x >> 16; ptr[1] = x >> 8; ptr[0] = x;
+#endif
+}
+
+uint32_t static inline ReadBE32(const unsigned char *ptr) {
+#if HAVE_DECL_BE32TOH == 1
+ return be32toh(*((uint32_t*)ptr));
+#else
+ return ((uint32_t)ptr[0] << 24 | (uint32_t)ptr[1] << 16 | (uint32_t)ptr[2] << 8 | (uint32_t)ptr[3]);
+#endif
+}
+
+uint64_t static inline ReadBE64(const unsigned char *ptr) {
+#if HAVE_DECL_BE64TOH == 1
+ return be64toh(*((uint64_t*)ptr));
+#else
+ return ((uint64_t)ptr[0] << 56 | (uint64_t)ptr[1] << 48 | (uint64_t)ptr[2] << 40 | (uint64_t)ptr[3] << 32 |
+ (uint64_t)ptr[4] << 24 | (uint64_t)ptr[5] << 16 | (uint64_t)ptr[6] << 8 | (uint64_t)ptr[7]);
+#endif
+}
+
+void static inline WriteBE32(unsigned char *ptr, uint32_t x) {
+#if HAVE_DECL_HTOBE32 == 1
+ *((uint32_t*)ptr) = htobe32(x);
+#else
+ ptr[0] = x >> 24; ptr[1] = x >> 16; ptr[2] = x >> 8; ptr[3] = x;
+#endif
+}
+
+void static inline WriteBE64(unsigned char *ptr, uint64_t x) {
+#if HAVE_DECL_HTOBE64 == 1
+ *((uint64_t*)ptr) = htobe64(x);
+#else
+ ptr[0] = x >> 56; ptr[1] = x >> 48; ptr[2] = x >> 40; ptr[3] = x >> 32;
+ ptr[4] = x >> 24; ptr[5] = x >> 16; ptr[6] = x >> 8; ptr[7] = x;
+#endif
+}
+
+#endif
diff --git a/src/crypto/ripemd160.cpp b/src/crypto/ripemd160.cpp
new file mode 100644
index 0000000000..24bd318d43
--- /dev/null
+++ b/src/crypto/ripemd160.cpp
@@ -0,0 +1,204 @@
+// Copyright (c) 2014 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 "crypto/ripemd160.h"
+
+#include "crypto/common.h"
+#include <string.h>
+
+// Internal implementation code.
+namespace {
+
+/// Internal RIPEMD-160 implementation.
+namespace ripemd160 {
+
+uint32_t inline f1(uint32_t x, uint32_t y, uint32_t z) { return x ^ y ^ z; }
+uint32_t inline f2(uint32_t x, uint32_t y, uint32_t z) { return (x & y) | (~x & z); }
+uint32_t inline f3(uint32_t x, uint32_t y, uint32_t z) { return (x | ~y) ^ z; }
+uint32_t inline f4(uint32_t x, uint32_t y, uint32_t z) { return (x & z) | (y & ~z); }
+uint32_t inline f5(uint32_t x, uint32_t y, uint32_t z) { return x ^ (y | ~z); }
+
+/** Initialize RIPEMD-160 state. */
+void inline Initialize(uint32_t *s) {
+ s[0] = 0x67452301ul;
+ s[1] = 0xEFCDAB89ul;
+ s[2] = 0x98BADCFEul;
+ s[3] = 0x10325476ul;
+ s[4] = 0xC3D2E1F0ul;
+}
+
+uint32_t inline rol(uint32_t x, int i) { return (x << i) | (x >> (32-i)); }
+
+void inline Round(uint32_t &a, uint32_t b, uint32_t &c, uint32_t d, uint32_t e, uint32_t f, uint32_t x, uint32_t k, int r) {
+ a = rol(a + f + x + k, r) + e;
+ c = rol(c, 10);
+}
+
+void inline R11(uint32_t &a, uint32_t b, uint32_t &c, uint32_t d, uint32_t e, uint32_t x, int r) { Round(a, b, c, d, e, f1(b, c, d), x, 0, r); }
+void inline R21(uint32_t &a, uint32_t b, uint32_t &c, uint32_t d, uint32_t e, uint32_t x, int r) { Round(a, b, c, d, e, f2(b, c, d), x, 0x5A827999ul, r); }
+void inline R31(uint32_t &a, uint32_t b, uint32_t &c, uint32_t d, uint32_t e, uint32_t x, int r) { Round(a, b, c, d, e, f3(b, c, d), x, 0x6ED9EBA1ul, r); }
+void inline R41(uint32_t &a, uint32_t b, uint32_t &c, uint32_t d, uint32_t e, uint32_t x, int r) { Round(a, b, c, d, e, f4(b, c, d), x, 0x8F1BBCDCul, r); }
+void inline R51(uint32_t &a, uint32_t b, uint32_t &c, uint32_t d, uint32_t e, uint32_t x, int r) { Round(a, b, c, d, e, f5(b, c, d), x, 0xA953FD4Eul, r); }
+
+void inline R12(uint32_t &a, uint32_t b, uint32_t &c, uint32_t d, uint32_t e, uint32_t x, int r) { Round(a, b, c, d, e, f5(b, c, d), x, 0x50A28BE6ul, r); }
+void inline R22(uint32_t &a, uint32_t b, uint32_t &c, uint32_t d, uint32_t e, uint32_t x, int r) { Round(a, b, c, d, e, f4(b, c, d), x, 0x5C4DD124ul, r); }
+void inline R32(uint32_t &a, uint32_t b, uint32_t &c, uint32_t d, uint32_t e, uint32_t x, int r) { Round(a, b, c, d, e, f3(b, c, d), x, 0x6D703EF3ul, r); }
+void inline R42(uint32_t &a, uint32_t b, uint32_t &c, uint32_t d, uint32_t e, uint32_t x, int r) { Round(a, b, c, d, e, f2(b, c, d), x, 0x7A6D76E9ul, r); }
+void inline R52(uint32_t &a, uint32_t b, uint32_t &c, uint32_t d, uint32_t e, uint32_t x, int r) { Round(a, b, c, d, e, f1(b, c, d), x, 0, r); }
+
+/** Perform a RIPEMD-160 transformation, processing a 64-byte chunk. */
+void Transform(uint32_t *s, const unsigned char *chunk) {
+ uint32_t a1 = s[0], b1 = s[1], c1 = s[2], d1 = s[3], e1 = s[4];
+ uint32_t a2 = a1 , b2 = b1 , c2 = c1 , d2 = d1 , e2 = e1 ;
+ uint32_t w0 = ReadLE32(chunk + 0), w1 = ReadLE32(chunk + 4), w2 = ReadLE32(chunk + 8), w3 = ReadLE32(chunk + 12);
+ uint32_t w4 = ReadLE32(chunk + 16), w5 = ReadLE32(chunk + 20), w6 = ReadLE32(chunk + 24), w7 = ReadLE32(chunk + 28);
+ uint32_t w8 = ReadLE32(chunk + 32), w9 = ReadLE32(chunk + 36), w10 = ReadLE32(chunk + 40), w11 = ReadLE32(chunk + 44);
+ uint32_t w12 = ReadLE32(chunk + 48), w13 = ReadLE32(chunk + 52), w14 = ReadLE32(chunk + 56), w15 = ReadLE32(chunk + 60);
+
+ R11(a1, b1, c1, d1, e1, w0 , 11); R12(a2, b2, c2, d2, e2, w5 , 8);
+ R11(e1, a1, b1, c1, d1, w1 , 14); R12(e2, a2, b2, c2, d2, w14, 9);
+ R11(d1, e1, a1, b1, c1, w2 , 15); R12(d2, e2, a2, b2, c2, w7 , 9);
+ R11(c1, d1, e1, a1, b1, w3 , 12); R12(c2, d2, e2, a2, b2, w0 , 11);
+ R11(b1, c1, d1, e1, a1, w4 , 5); R12(b2, c2, d2, e2, a2, w9 , 13);
+ R11(a1, b1, c1, d1, e1, w5 , 8); R12(a2, b2, c2, d2, e2, w2 , 15);
+ R11(e1, a1, b1, c1, d1, w6 , 7); R12(e2, a2, b2, c2, d2, w11, 15);
+ R11(d1, e1, a1, b1, c1, w7 , 9); R12(d2, e2, a2, b2, c2, w4 , 5);
+ R11(c1, d1, e1, a1, b1, w8 , 11); R12(c2, d2, e2, a2, b2, w13, 7);
+ R11(b1, c1, d1, e1, a1, w9 , 13); R12(b2, c2, d2, e2, a2, w6 , 7);
+ R11(a1, b1, c1, d1, e1, w10, 14); R12(a2, b2, c2, d2, e2, w15, 8);
+ R11(e1, a1, b1, c1, d1, w11, 15); R12(e2, a2, b2, c2, d2, w8 , 11);
+ R11(d1, e1, a1, b1, c1, w12, 6); R12(d2, e2, a2, b2, c2, w1 , 14);
+ R11(c1, d1, e1, a1, b1, w13, 7); R12(c2, d2, e2, a2, b2, w10, 14);
+ R11(b1, c1, d1, e1, a1, w14, 9); R12(b2, c2, d2, e2, a2, w3 , 12);
+ R11(a1, b1, c1, d1, e1, w15, 8); R12(a2, b2, c2, d2, e2, w12, 6);
+
+ R21(e1, a1, b1, c1, d1, w7 , 7); R22(e2, a2, b2, c2, d2, w6 , 9);
+ R21(d1, e1, a1, b1, c1, w4 , 6); R22(d2, e2, a2, b2, c2, w11, 13);
+ R21(c1, d1, e1, a1, b1, w13, 8); R22(c2, d2, e2, a2, b2, w3 , 15);
+ R21(b1, c1, d1, e1, a1, w1 , 13); R22(b2, c2, d2, e2, a2, w7 , 7);
+ R21(a1, b1, c1, d1, e1, w10, 11); R22(a2, b2, c2, d2, e2, w0 , 12);
+ R21(e1, a1, b1, c1, d1, w6 , 9); R22(e2, a2, b2, c2, d2, w13, 8);
+ R21(d1, e1, a1, b1, c1, w15, 7); R22(d2, e2, a2, b2, c2, w5 , 9);
+ R21(c1, d1, e1, a1, b1, w3 , 15); R22(c2, d2, e2, a2, b2, w10, 11);
+ R21(b1, c1, d1, e1, a1, w12, 7); R22(b2, c2, d2, e2, a2, w14, 7);
+ R21(a1, b1, c1, d1, e1, w0 , 12); R22(a2, b2, c2, d2, e2, w15, 7);
+ R21(e1, a1, b1, c1, d1, w9 , 15); R22(e2, a2, b2, c2, d2, w8 , 12);
+ R21(d1, e1, a1, b1, c1, w5 , 9); R22(d2, e2, a2, b2, c2, w12, 7);
+ R21(c1, d1, e1, a1, b1, w2 , 11); R22(c2, d2, e2, a2, b2, w4 , 6);
+ R21(b1, c1, d1, e1, a1, w14, 7); R22(b2, c2, d2, e2, a2, w9 , 15);
+ R21(a1, b1, c1, d1, e1, w11, 13); R22(a2, b2, c2, d2, e2, w1 , 13);
+ R21(e1, a1, b1, c1, d1, w8 , 12); R22(e2, a2, b2, c2, d2, w2 , 11);
+
+ R31(d1, e1, a1, b1, c1, w3 , 11); R32(d2, e2, a2, b2, c2, w15, 9);
+ R31(c1, d1, e1, a1, b1, w10, 13); R32(c2, d2, e2, a2, b2, w5 , 7);
+ R31(b1, c1, d1, e1, a1, w14, 6); R32(b2, c2, d2, e2, a2, w1 , 15);
+ R31(a1, b1, c1, d1, e1, w4 , 7); R32(a2, b2, c2, d2, e2, w3 , 11);
+ R31(e1, a1, b1, c1, d1, w9 , 14); R32(e2, a2, b2, c2, d2, w7 , 8);
+ R31(d1, e1, a1, b1, c1, w15, 9); R32(d2, e2, a2, b2, c2, w14, 6);
+ R31(c1, d1, e1, a1, b1, w8 , 13); R32(c2, d2, e2, a2, b2, w6 , 6);
+ R31(b1, c1, d1, e1, a1, w1 , 15); R32(b2, c2, d2, e2, a2, w9 , 14);
+ R31(a1, b1, c1, d1, e1, w2 , 14); R32(a2, b2, c2, d2, e2, w11, 12);
+ R31(e1, a1, b1, c1, d1, w7 , 8); R32(e2, a2, b2, c2, d2, w8 , 13);
+ R31(d1, e1, a1, b1, c1, w0 , 13); R32(d2, e2, a2, b2, c2, w12, 5);
+ R31(c1, d1, e1, a1, b1, w6 , 6); R32(c2, d2, e2, a2, b2, w2 , 14);
+ R31(b1, c1, d1, e1, a1, w13, 5); R32(b2, c2, d2, e2, a2, w10, 13);
+ R31(a1, b1, c1, d1, e1, w11, 12); R32(a2, b2, c2, d2, e2, w0 , 13);
+ R31(e1, a1, b1, c1, d1, w5 , 7); R32(e2, a2, b2, c2, d2, w4 , 7);
+ R31(d1, e1, a1, b1, c1, w12, 5); R32(d2, e2, a2, b2, c2, w13, 5);
+
+ R41(c1, d1, e1, a1, b1, w1 , 11); R42(c2, d2, e2, a2, b2, w8 , 15);
+ R41(b1, c1, d1, e1, a1, w9 , 12); R42(b2, c2, d2, e2, a2, w6 , 5);
+ R41(a1, b1, c1, d1, e1, w11, 14); R42(a2, b2, c2, d2, e2, w4 , 8);
+ R41(e1, a1, b1, c1, d1, w10, 15); R42(e2, a2, b2, c2, d2, w1 , 11);
+ R41(d1, e1, a1, b1, c1, w0 , 14); R42(d2, e2, a2, b2, c2, w3 , 14);
+ R41(c1, d1, e1, a1, b1, w8 , 15); R42(c2, d2, e2, a2, b2, w11, 14);
+ R41(b1, c1, d1, e1, a1, w12, 9); R42(b2, c2, d2, e2, a2, w15, 6);
+ R41(a1, b1, c1, d1, e1, w4 , 8); R42(a2, b2, c2, d2, e2, w0 , 14);
+ R41(e1, a1, b1, c1, d1, w13, 9); R42(e2, a2, b2, c2, d2, w5 , 6);
+ R41(d1, e1, a1, b1, c1, w3 , 14); R42(d2, e2, a2, b2, c2, w12, 9);
+ R41(c1, d1, e1, a1, b1, w7 , 5); R42(c2, d2, e2, a2, b2, w2 , 12);
+ R41(b1, c1, d1, e1, a1, w15, 6); R42(b2, c2, d2, e2, a2, w13, 9);
+ R41(a1, b1, c1, d1, e1, w14, 8); R42(a2, b2, c2, d2, e2, w9 , 12);
+ R41(e1, a1, b1, c1, d1, w5 , 6); R42(e2, a2, b2, c2, d2, w7 , 5);
+ R41(d1, e1, a1, b1, c1, w6 , 5); R42(d2, e2, a2, b2, c2, w10, 15);
+ R41(c1, d1, e1, a1, b1, w2 , 12); R42(c2, d2, e2, a2, b2, w14, 8);
+
+ R51(b1, c1, d1, e1, a1, w4 , 9); R52(b2, c2, d2, e2, a2, w12, 8);
+ R51(a1, b1, c1, d1, e1, w0 , 15); R52(a2, b2, c2, d2, e2, w15, 5);
+ R51(e1, a1, b1, c1, d1, w5 , 5); R52(e2, a2, b2, c2, d2, w10, 12);
+ R51(d1, e1, a1, b1, c1, w9 , 11); R52(d2, e2, a2, b2, c2, w4 , 9);
+ R51(c1, d1, e1, a1, b1, w7 , 6); R52(c2, d2, e2, a2, b2, w1 , 12);
+ R51(b1, c1, d1, e1, a1, w12, 8); R52(b2, c2, d2, e2, a2, w5 , 5);
+ R51(a1, b1, c1, d1, e1, w2 , 13); R52(a2, b2, c2, d2, e2, w8 , 14);
+ R51(e1, a1, b1, c1, d1, w10, 12); R52(e2, a2, b2, c2, d2, w7 , 6);
+ R51(d1, e1, a1, b1, c1, w14, 5); R52(d2, e2, a2, b2, c2, w6 , 8);
+ R51(c1, d1, e1, a1, b1, w1 , 12); R52(c2, d2, e2, a2, b2, w2 , 13);
+ R51(b1, c1, d1, e1, a1, w3 , 13); R52(b2, c2, d2, e2, a2, w13, 6);
+ R51(a1, b1, c1, d1, e1, w8 , 14); R52(a2, b2, c2, d2, e2, w14, 5);
+ R51(e1, a1, b1, c1, d1, w11, 11); R52(e2, a2, b2, c2, d2, w0 , 15);
+ R51(d1, e1, a1, b1, c1, w6 , 8); R52(d2, e2, a2, b2, c2, w3 , 13);
+ R51(c1, d1, e1, a1, b1, w15, 5); R52(c2, d2, e2, a2, b2, w9 , 11);
+ R51(b1, c1, d1, e1, a1, w13, 6); R52(b2, c2, d2, e2, a2, w11, 11);
+
+ uint32_t t = s[0];
+ s[0] = s[1] + c1 + d2;
+ s[1] = s[2] + d1 + e2;
+ s[2] = s[3] + e1 + a2;
+ s[3] = s[4] + a1 + b2;
+ s[4] = t + b1 + c2;
+}
+
+} // namespace ripemd160
+
+} // namespace
+
+////// RIPEMD160
+
+CRIPEMD160::CRIPEMD160() : bytes(0) {
+ ripemd160::Initialize(s);
+}
+
+CRIPEMD160& CRIPEMD160::Write(const unsigned char *data, size_t len) {
+ const unsigned char *end = data + len;
+ size_t bufsize = bytes % 64;
+ if (bufsize && bufsize + len >= 64) {
+ // Fill the buffer, and process it.
+ memcpy(buf + bufsize, data, 64 - bufsize);
+ bytes += 64 - bufsize;
+ data += 64 - bufsize;
+ ripemd160::Transform(s, buf);
+ bufsize = 0;
+ }
+ while (end >= data + 64) {
+ // Process full chunks directly from the source.
+ ripemd160::Transform(s, data);
+ bytes += 64;
+ data += 64;
+ }
+ if (end > data) {
+ // Fill the buffer with what remains.
+ memcpy(buf + bufsize, data, end - data);
+ bytes += end - data;
+ }
+ return *this;
+}
+
+void CRIPEMD160::Finalize(unsigned char hash[OUTPUT_SIZE]) {
+ static const unsigned char pad[64] = {0x80};
+ unsigned char sizedesc[8];
+ WriteLE64(sizedesc, bytes << 3);
+ Write(pad, 1 + ((119 - (bytes % 64)) % 64));
+ Write(sizedesc, 8);
+ WriteLE32(hash, s[0]);
+ WriteLE32(hash+4, s[1]);
+ WriteLE32(hash+8, s[2]);
+ WriteLE32(hash+12, s[3]);
+ WriteLE32(hash+16, s[4]);
+}
+
+CRIPEMD160& CRIPEMD160::Reset() {
+ bytes = 0;
+ ripemd160::Initialize(s);
+ return *this;
+}
diff --git a/src/crypto/ripemd160.h b/src/crypto/ripemd160.h
new file mode 100644
index 0000000000..44bd4879a5
--- /dev/null
+++ b/src/crypto/ripemd160.h
@@ -0,0 +1,27 @@
+// Copyright (c) 2014 The Bitcoin developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_RIPEMD160_H
+#define BITCOIN_RIPEMD160_H
+
+#include <stdint.h>
+#include <stdlib.h>
+
+/** A hasher class for RIPEMD-160. */
+class CRIPEMD160 {
+private:
+ uint32_t s[5];
+ unsigned char buf[64];
+ size_t bytes;
+
+public:
+ static const size_t OUTPUT_SIZE = 20;
+
+ CRIPEMD160();
+ CRIPEMD160& Write(const unsigned char *data, size_t len);
+ void Finalize(unsigned char hash[OUTPUT_SIZE]);
+ CRIPEMD160& Reset();
+};
+
+#endif
diff --git a/src/crypto/sha1.cpp b/src/crypto/sha1.cpp
new file mode 100644
index 0000000000..304401a50f
--- /dev/null
+++ b/src/crypto/sha1.cpp
@@ -0,0 +1,192 @@
+// Copyright (c) 2014 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 "crypto/sha1.h"
+
+#include "crypto/common.h"
+#include <string.h>
+
+// Internal implementation code.
+namespace {
+
+/// Internal SHA-1 implementation.
+namespace sha1 {
+
+/** One round of SHA-1. */
+void inline Round(uint32_t a, uint32_t &b, uint32_t c, uint32_t d, uint32_t &e,
+ uint32_t f, uint32_t k, uint32_t w) {
+ e += ((a << 5) | (a >> 27)) + f + k + w;
+ b = (b << 30) | (b >> 2);
+}
+
+uint32_t inline f1(uint32_t b, uint32_t c, uint32_t d) { return d ^ (b & (c ^ d)); }
+uint32_t inline f2(uint32_t b, uint32_t c, uint32_t d) { return b ^ c ^ d; }
+uint32_t inline f3(uint32_t b, uint32_t c, uint32_t d) { return (b & c) | (d & (b | c)); }
+
+uint32_t inline left(uint32_t x) { return (x << 1) | (x >> 31); }
+
+/** Initialize SHA-1 state. */
+void inline Initialize(uint32_t *s) {
+ s[0] = 0x67452301ul;
+ s[1] = 0xEFCDAB89ul;
+ s[2] = 0x98BADCFEul;
+ s[3] = 0x10325476ul;
+ s[4] = 0xC3D2E1F0ul;
+}
+
+const uint32_t k1 = 0x5A827999ul;
+const uint32_t k2 = 0x6ED9EBA1ul;
+const uint32_t k3 = 0x8F1BBCDCul;
+const uint32_t k4 = 0xCA62C1D6ul;
+
+/** Perform a SHA-1 transformation, processing a 64-byte chunk. */
+void Transform(uint32_t *s, const unsigned char *chunk) {
+ uint32_t a = s[0], b = s[1], c = s[2], d = s[3], e = s[4];
+ uint32_t w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13, w14, w15;
+
+ Round(a, b, c, d, e, f1(b, c, d), k1, w0 = ReadBE32(chunk + 0));
+ Round(e, a, b, c, d, f1(a, b, c), k1, w1 = ReadBE32(chunk + 4));
+ Round(d, e, a, b, c, f1(e, a, b), k1, w2 = ReadBE32(chunk + 8));
+ Round(c, d, e, a, b, f1(d, e, a), k1, w3 = ReadBE32(chunk + 12));
+ Round(b, c, d, e, a, f1(c, d, e), k1, w4 = ReadBE32(chunk + 16));
+ Round(a, b, c, d, e, f1(b, c, d), k1, w5 = ReadBE32(chunk + 20));
+ Round(e, a, b, c, d, f1(a, b, c), k1, w6 = ReadBE32(chunk + 24));
+ Round(d, e, a, b, c, f1(e, a, b), k1, w7 = ReadBE32(chunk + 28));
+ Round(c, d, e, a, b, f1(d, e, a), k1, w8 = ReadBE32(chunk + 32));
+ Round(b, c, d, e, a, f1(c, d, e), k1, w9 = ReadBE32(chunk + 36));
+ Round(a, b, c, d, e, f1(b, c, d), k1, w10 = ReadBE32(chunk + 40));
+ Round(e, a, b, c, d, f1(a, b, c), k1, w11 = ReadBE32(chunk + 44));
+ Round(d, e, a, b, c, f1(e, a, b), k1, w12 = ReadBE32(chunk + 48));
+ Round(c, d, e, a, b, f1(d, e, a), k1, w13 = ReadBE32(chunk + 52));
+ Round(b, c, d, e, a, f1(c, d, e), k1, w14 = ReadBE32(chunk + 56));
+ Round(a, b, c, d, e, f1(b, c, d), k1, w15 = ReadBE32(chunk + 60));
+
+ Round(e, a, b, c, d, f1(a, b, c), k1, w0 = left(w0 ^ w13 ^ w8 ^ w2 ));
+ Round(d, e, a, b, c, f1(e, a, b), k1, w1 = left(w1 ^ w14 ^ w9 ^ w3 ));
+ Round(c, d, e, a, b, f1(d, e, a), k1, w2 = left(w2 ^ w15 ^ w10 ^ w4 ));
+ Round(b, c, d, e, a, f1(c, d, e), k1, w3 = left(w3 ^ w0 ^ w11 ^ w5 ));
+ Round(a, b, c, d, e, f2(b, c, d), k2, w4 = left(w4 ^ w1 ^ w12 ^ w6 ));
+ Round(e, a, b, c, d, f2(a, b, c), k2, w5 = left(w5 ^ w2 ^ w13 ^ w7 ));
+ Round(d, e, a, b, c, f2(e, a, b), k2, w6 = left(w6 ^ w3 ^ w14 ^ w8 ));
+ Round(c, d, e, a, b, f2(d, e, a), k2, w7 = left(w7 ^ w4 ^ w15 ^ w9 ));
+ Round(b, c, d, e, a, f2(c, d, e), k2, w8 = left(w8 ^ w5 ^ w0 ^ w10));
+ Round(a, b, c, d, e, f2(b, c, d), k2, w9 = left(w9 ^ w6 ^ w1 ^ w11));
+ Round(e, a, b, c, d, f2(a, b, c), k2, w10 = left(w10 ^ w7 ^ w2 ^ w12));
+ Round(d, e, a, b, c, f2(e, a, b), k2, w11 = left(w11 ^ w8 ^ w3 ^ w13));
+ Round(c, d, e, a, b, f2(d, e, a), k2, w12 = left(w12 ^ w9 ^ w4 ^ w14));
+ Round(b, c, d, e, a, f2(c, d, e), k2, w13 = left(w13 ^ w10 ^ w5 ^ w15));
+ Round(a, b, c, d, e, f2(b, c, d), k2, w14 = left(w14 ^ w11 ^ w6 ^ w0 ));
+ Round(e, a, b, c, d, f2(a, b, c), k2, w15 = left(w15 ^ w12 ^ w7 ^ w1 ));
+
+ Round(d, e, a, b, c, f2(e, a, b), k2, w0 = left(w0 ^ w13 ^ w8 ^ w2 ));
+ Round(c, d, e, a, b, f2(d, e, a), k2, w1 = left(w1 ^ w14 ^ w9 ^ w3 ));
+ Round(b, c, d, e, a, f2(c, d, e), k2, w2 = left(w2 ^ w15 ^ w10 ^ w4 ));
+ Round(a, b, c, d, e, f2(b, c, d), k2, w3 = left(w3 ^ w0 ^ w11 ^ w5 ));
+ Round(e, a, b, c, d, f2(a, b, c), k2, w4 = left(w4 ^ w1 ^ w12 ^ w6 ));
+ Round(d, e, a, b, c, f2(e, a, b), k2, w5 = left(w5 ^ w2 ^ w13 ^ w7 ));
+ Round(c, d, e, a, b, f2(d, e, a), k2, w6 = left(w6 ^ w3 ^ w14 ^ w8 ));
+ Round(b, c, d, e, a, f2(c, d, e), k2, w7 = left(w7 ^ w4 ^ w15 ^ w9 ));
+ Round(a, b, c, d, e, f3(b, c, d), k3, w8 = left(w8 ^ w5 ^ w0 ^ w10));
+ Round(e, a, b, c, d, f3(a, b, c), k3, w9 = left(w9 ^ w6 ^ w1 ^ w11));
+ Round(d, e, a, b, c, f3(e, a, b), k3, w10 = left(w10 ^ w7 ^ w2 ^ w12));
+ Round(c, d, e, a, b, f3(d, e, a), k3, w11 = left(w11 ^ w8 ^ w3 ^ w13));
+ Round(b, c, d, e, a, f3(c, d, e), k3, w12 = left(w12 ^ w9 ^ w4 ^ w14));
+ Round(a, b, c, d, e, f3(b, c, d), k3, w13 = left(w13 ^ w10 ^ w5 ^ w15));
+ Round(e, a, b, c, d, f3(a, b, c), k3, w14 = left(w14 ^ w11 ^ w6 ^ w0 ));
+ Round(d, e, a, b, c, f3(e, a, b), k3, w15 = left(w15 ^ w12 ^ w7 ^ w1 ));
+
+ Round(c, d, e, a, b, f3(d, e, a), k3, w0 = left(w0 ^ w13 ^ w8 ^ w2 ));
+ Round(b, c, d, e, a, f3(c, d, e), k3, w1 = left(w1 ^ w14 ^ w9 ^ w3 ));
+ Round(a, b, c, d, e, f3(b, c, d), k3, w2 = left(w2 ^ w15 ^ w10 ^ w4 ));
+ Round(e, a, b, c, d, f3(a, b, c), k3, w3 = left(w3 ^ w0 ^ w11 ^ w5 ));
+ Round(d, e, a, b, c, f3(e, a, b), k3, w4 = left(w4 ^ w1 ^ w12 ^ w6 ));
+ Round(c, d, e, a, b, f3(d, e, a), k3, w5 = left(w5 ^ w2 ^ w13 ^ w7 ));
+ Round(b, c, d, e, a, f3(c, d, e), k3, w6 = left(w6 ^ w3 ^ w14 ^ w8 ));
+ Round(a, b, c, d, e, f3(b, c, d), k3, w7 = left(w7 ^ w4 ^ w15 ^ w9 ));
+ Round(e, a, b, c, d, f3(a, b, c), k3, w8 = left(w8 ^ w5 ^ w0 ^ w10));
+ Round(d, e, a, b, c, f3(e, a, b), k3, w9 = left(w9 ^ w6 ^ w1 ^ w11));
+ Round(c, d, e, a, b, f3(d, e, a), k3, w10 = left(w10 ^ w7 ^ w2 ^ w12));
+ Round(b, c, d, e, a, f3(c, d, e), k3, w11 = left(w11 ^ w8 ^ w3 ^ w13));
+ Round(a, b, c, d, e, f2(b, c, d), k4, w12 = left(w12 ^ w9 ^ w4 ^ w14));
+ Round(e, a, b, c, d, f2(a, b, c), k4, w13 = left(w13 ^ w10 ^ w5 ^ w15));
+ Round(d, e, a, b, c, f2(e, a, b), k4, w14 = left(w14 ^ w11 ^ w6 ^ w0 ));
+ Round(c, d, e, a, b, f2(d, e, a), k4, w15 = left(w15 ^ w12 ^ w7 ^ w1 ));
+
+ Round(b, c, d, e, a, f2(c, d, e), k4, w0 = left(w0 ^ w13 ^ w8 ^ w2 ));
+ Round(a, b, c, d, e, f2(b, c, d), k4, w1 = left(w1 ^ w14 ^ w9 ^ w3 ));
+ Round(e, a, b, c, d, f2(a, b, c), k4, w2 = left(w2 ^ w15 ^ w10 ^ w4 ));
+ Round(d, e, a, b, c, f2(e, a, b), k4, w3 = left(w3 ^ w0 ^ w11 ^ w5 ));
+ Round(c, d, e, a, b, f2(d, e, a), k4, w4 = left(w4 ^ w1 ^ w12 ^ w6 ));
+ Round(b, c, d, e, a, f2(c, d, e), k4, w5 = left(w5 ^ w2 ^ w13 ^ w7 ));
+ Round(a, b, c, d, e, f2(b, c, d), k4, w6 = left(w6 ^ w3 ^ w14 ^ w8 ));
+ Round(e, a, b, c, d, f2(a, b, c), k4, w7 = left(w7 ^ w4 ^ w15 ^ w9 ));
+ Round(d, e, a, b, c, f2(e, a, b), k4, w8 = left(w8 ^ w5 ^ w0 ^ w10));
+ Round(c, d, e, a, b, f2(d, e, a), k4, w9 = left(w9 ^ w6 ^ w1 ^ w11));
+ Round(b, c, d, e, a, f2(c, d, e), k4, w10 = left(w10 ^ w7 ^ w2 ^ w12));
+ Round(a, b, c, d, e, f2(b, c, d), k4, w11 = left(w11 ^ w8 ^ w3 ^ w13));
+ Round(e, a, b, c, d, f2(a, b, c), k4, w12 = left(w12 ^ w9 ^ w4 ^ w14));
+ Round(d, e, a, b, c, f2(e, a, b), k4, left(w13 ^ w10 ^ w5 ^ w15));
+ Round(c, d, e, a, b, f2(d, e, a), k4, left(w14 ^ w11 ^ w6 ^ w0 ));
+ Round(b, c, d, e, a, f2(c, d, e), k4, left(w15 ^ w12 ^ w7 ^ w1 ));
+
+ s[0] += a;
+ s[1] += b;
+ s[2] += c;
+ s[3] += d;
+ s[4] += e;
+}
+
+} // namespace sha1
+
+} // namespace
+
+////// SHA1
+
+CSHA1::CSHA1() : bytes(0) {
+ sha1::Initialize(s);
+}
+
+CSHA1& CSHA1::Write(const unsigned char *data, size_t len) {
+ const unsigned char *end = data + len;
+ size_t bufsize = bytes % 64;
+ if (bufsize && bufsize + len >= 64) {
+ // Fill the buffer, and process it.
+ memcpy(buf + bufsize, data, 64 - bufsize);
+ bytes += 64 - bufsize;
+ data += 64 - bufsize;
+ sha1::Transform(s, buf);
+ bufsize = 0;
+ }
+ while (end >= data + 64) {
+ // Process full chunks directly from the source.
+ sha1::Transform(s, data);
+ bytes += 64;
+ data += 64;
+ }
+ if (end > data) {
+ // Fill the buffer with what remains.
+ memcpy(buf + bufsize, data, end - data);
+ bytes += end - data;
+ }
+ return *this;
+}
+
+void CSHA1::Finalize(unsigned char hash[OUTPUT_SIZE]) {
+ static const unsigned char pad[64] = {0x80};
+ unsigned char sizedesc[8];
+ WriteBE64(sizedesc, bytes << 3);
+ Write(pad, 1 + ((119 - (bytes % 64)) % 64));
+ Write(sizedesc, 8);
+ WriteBE32(hash, s[0]);
+ WriteBE32(hash+4, s[1]);
+ WriteBE32(hash+8, s[2]);
+ WriteBE32(hash+12, s[3]);
+ WriteBE32(hash+16, s[4]);
+}
+
+CSHA1& CSHA1::Reset() {
+ bytes = 0;
+ sha1::Initialize(s);
+ return *this;
+}
diff --git a/src/crypto/sha1.h b/src/crypto/sha1.h
new file mode 100644
index 0000000000..b16f2c88ce
--- /dev/null
+++ b/src/crypto/sha1.h
@@ -0,0 +1,27 @@
+// Copyright (c) 2014 The Bitcoin developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_SHA1_H
+#define BITCOIN_SHA1_H
+
+#include <stdint.h>
+#include <stdlib.h>
+
+/** A hasher class for SHA1. */
+class CSHA1 {
+private:
+ uint32_t s[5];
+ unsigned char buf[64];
+ size_t bytes;
+
+public:
+ static const size_t OUTPUT_SIZE = 20;
+
+ CSHA1();
+ CSHA1& Write(const unsigned char *data, size_t len);
+ void Finalize(unsigned char hash[OUTPUT_SIZE]);
+ CSHA1& Reset();
+};
+
+#endif
diff --git a/src/crypto/sha2.cpp b/src/crypto/sha2.cpp
new file mode 100644
index 0000000000..99a251cb12
--- /dev/null
+++ b/src/crypto/sha2.cpp
@@ -0,0 +1,398 @@
+// Copyright (c) 2014 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 "crypto/sha2.h"
+
+#include "crypto/common.h"
+#include <string.h>
+
+// Internal implementation code.
+namespace {
+
+/// Internal SHA-256 implementation.
+namespace sha256 {
+
+uint32_t inline Ch(uint32_t x, uint32_t y, uint32_t z) { return z ^ (x & (y ^ z)); }
+uint32_t inline Maj(uint32_t x, uint32_t y, uint32_t z) { return (x & y) | (z & (x | y)); }
+uint32_t inline Sigma0(uint32_t x) { return (x >> 2 | x << 30) ^ (x >> 13 | x << 19) ^ (x >> 22 | x << 10); }
+uint32_t inline Sigma1(uint32_t x) { return (x >> 6 | x << 26) ^ (x >> 11 | x << 21) ^ (x >> 25 | x << 7); }
+uint32_t inline sigma0(uint32_t x) { return (x >> 7 | x << 25) ^ (x >> 18 | x << 14) ^ (x >> 3); }
+uint32_t inline sigma1(uint32_t x) { return (x >> 17 | x << 15) ^ (x >> 19 | x << 13) ^ (x >> 10); }
+
+/** One round of SHA-256. */
+void inline Round(uint32_t a, uint32_t b, uint32_t c, uint32_t &d,
+ uint32_t e, uint32_t f, uint32_t g, uint32_t &h,
+ uint32_t k, uint32_t w) {
+ uint32_t t1 = h + Sigma1(e) + Ch(e, f, g) + k + w;
+ uint32_t t2 = Sigma0(a) + Maj(a, b, c);
+ d += t1;
+ h = t1 + t2;
+}
+
+/** Initialize SHA-256 state. */
+void inline Initialize(uint32_t *s) {
+ s[0] = 0x6a09e667ul;
+ s[1] = 0xbb67ae85ul;
+ s[2] = 0x3c6ef372ul;
+ s[3] = 0xa54ff53aul;
+ s[4] = 0x510e527ful;
+ s[5] = 0x9b05688cul;
+ s[6] = 0x1f83d9abul;
+ s[7] = 0x5be0cd19ul;
+}
+
+/** Perform one SHA-256 transformation, processing a 64-byte chunk. */
+void Transform(uint32_t *s, const unsigned char *chunk) {
+ uint32_t a = s[0], b = s[1], c = s[2], d = s[3], e = s[4], f = s[5], g = s[6], h = s[7];
+ uint32_t w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13, w14, w15;
+
+ Round(a, b, c, d, e, f, g, h, 0x428a2f98, w0 = ReadBE32(chunk + 0));
+ Round(h, a, b, c, d, e, f, g, 0x71374491, w1 = ReadBE32(chunk + 4));
+ Round(g, h, a, b, c, d, e, f, 0xb5c0fbcf, w2 = ReadBE32(chunk + 8));
+ Round(f, g, h, a, b, c, d, e, 0xe9b5dba5, w3 = ReadBE32(chunk + 12));
+ Round(e, f, g, h, a, b, c, d, 0x3956c25b, w4 = ReadBE32(chunk + 16));
+ Round(d, e, f, g, h, a, b, c, 0x59f111f1, w5 = ReadBE32(chunk + 20));
+ Round(c, d, e, f, g, h, a, b, 0x923f82a4, w6 = ReadBE32(chunk + 24));
+ Round(b, c, d, e, f, g, h, a, 0xab1c5ed5, w7 = ReadBE32(chunk + 28));
+ Round(a, b, c, d, e, f, g, h, 0xd807aa98, w8 = ReadBE32(chunk + 32));
+ Round(h, a, b, c, d, e, f, g, 0x12835b01, w9 = ReadBE32(chunk + 36));
+ Round(g, h, a, b, c, d, e, f, 0x243185be, w10 = ReadBE32(chunk + 40));
+ Round(f, g, h, a, b, c, d, e, 0x550c7dc3, w11 = ReadBE32(chunk + 44));
+ Round(e, f, g, h, a, b, c, d, 0x72be5d74, w12 = ReadBE32(chunk + 48));
+ Round(d, e, f, g, h, a, b, c, 0x80deb1fe, w13 = ReadBE32(chunk + 52));
+ Round(c, d, e, f, g, h, a, b, 0x9bdc06a7, w14 = ReadBE32(chunk + 56));
+ Round(b, c, d, e, f, g, h, a, 0xc19bf174, w15 = ReadBE32(chunk + 60));
+
+ Round(a, b, c, d, e, f, g, h, 0xe49b69c1, w0 += sigma1(w14) + w9 + sigma0( w1));
+ Round(h, a, b, c, d, e, f, g, 0xefbe4786, w1 += sigma1(w15) + w10 + sigma0( w2));
+ Round(g, h, a, b, c, d, e, f, 0x0fc19dc6, w2 += sigma1( w0) + w11 + sigma0( w3));
+ Round(f, g, h, a, b, c, d, e, 0x240ca1cc, w3 += sigma1( w1) + w12 + sigma0( w4));
+ Round(e, f, g, h, a, b, c, d, 0x2de92c6f, w4 += sigma1( w2) + w13 + sigma0( w5));
+ Round(d, e, f, g, h, a, b, c, 0x4a7484aa, w5 += sigma1( w3) + w14 + sigma0( w6));
+ Round(c, d, e, f, g, h, a, b, 0x5cb0a9dc, w6 += sigma1( w4) + w15 + sigma0( w7));
+ Round(b, c, d, e, f, g, h, a, 0x76f988da, w7 += sigma1( w5) + w0 + sigma0( w8));
+ Round(a, b, c, d, e, f, g, h, 0x983e5152, w8 += sigma1( w6) + w1 + sigma0( w9));
+ Round(h, a, b, c, d, e, f, g, 0xa831c66d, w9 += sigma1( w7) + w2 + sigma0(w10));
+ Round(g, h, a, b, c, d, e, f, 0xb00327c8, w10 += sigma1( w8) + w3 + sigma0(w11));
+ Round(f, g, h, a, b, c, d, e, 0xbf597fc7, w11 += sigma1( w9) + w4 + sigma0(w12));
+ Round(e, f, g, h, a, b, c, d, 0xc6e00bf3, w12 += sigma1(w10) + w5 + sigma0(w13));
+ Round(d, e, f, g, h, a, b, c, 0xd5a79147, w13 += sigma1(w11) + w6 + sigma0(w14));
+ Round(c, d, e, f, g, h, a, b, 0x06ca6351, w14 += sigma1(w12) + w7 + sigma0(w15));
+ Round(b, c, d, e, f, g, h, a, 0x14292967, w15 += sigma1(w13) + w8 + sigma0( w0));
+
+ Round(a, b, c, d, e, f, g, h, 0x27b70a85, w0 += sigma1(w14) + w9 + sigma0( w1));
+ Round(h, a, b, c, d, e, f, g, 0x2e1b2138, w1 += sigma1(w15) + w10 + sigma0( w2));
+ Round(g, h, a, b, c, d, e, f, 0x4d2c6dfc, w2 += sigma1( w0) + w11 + sigma0( w3));
+ Round(f, g, h, a, b, c, d, e, 0x53380d13, w3 += sigma1( w1) + w12 + sigma0( w4));
+ Round(e, f, g, h, a, b, c, d, 0x650a7354, w4 += sigma1( w2) + w13 + sigma0( w5));
+ Round(d, e, f, g, h, a, b, c, 0x766a0abb, w5 += sigma1( w3) + w14 + sigma0( w6));
+ Round(c, d, e, f, g, h, a, b, 0x81c2c92e, w6 += sigma1( w4) + w15 + sigma0( w7));
+ Round(b, c, d, e, f, g, h, a, 0x92722c85, w7 += sigma1( w5) + w0 + sigma0( w8));
+ Round(a, b, c, d, e, f, g, h, 0xa2bfe8a1, w8 += sigma1( w6) + w1 + sigma0( w9));
+ Round(h, a, b, c, d, e, f, g, 0xa81a664b, w9 += sigma1( w7) + w2 + sigma0(w10));
+ Round(g, h, a, b, c, d, e, f, 0xc24b8b70, w10 += sigma1( w8) + w3 + sigma0(w11));
+ Round(f, g, h, a, b, c, d, e, 0xc76c51a3, w11 += sigma1( w9) + w4 + sigma0(w12));
+ Round(e, f, g, h, a, b, c, d, 0xd192e819, w12 += sigma1(w10) + w5 + sigma0(w13));
+ Round(d, e, f, g, h, a, b, c, 0xd6990624, w13 += sigma1(w11) + w6 + sigma0(w14));
+ Round(c, d, e, f, g, h, a, b, 0xf40e3585, w14 += sigma1(w12) + w7 + sigma0(w15));
+ Round(b, c, d, e, f, g, h, a, 0x106aa070, w15 += sigma1(w13) + w8 + sigma0( w0));
+
+ Round(a, b, c, d, e, f, g, h, 0x19a4c116, w0 += sigma1(w14) + w9 + sigma0( w1));
+ Round(h, a, b, c, d, e, f, g, 0x1e376c08, w1 += sigma1(w15) + w10 + sigma0( w2));
+ Round(g, h, a, b, c, d, e, f, 0x2748774c, w2 += sigma1( w0) + w11 + sigma0( w3));
+ Round(f, g, h, a, b, c, d, e, 0x34b0bcb5, w3 += sigma1( w1) + w12 + sigma0( w4));
+ Round(e, f, g, h, a, b, c, d, 0x391c0cb3, w4 += sigma1( w2) + w13 + sigma0( w5));
+ Round(d, e, f, g, h, a, b, c, 0x4ed8aa4a, w5 += sigma1( w3) + w14 + sigma0( w6));
+ Round(c, d, e, f, g, h, a, b, 0x5b9cca4f, w6 += sigma1( w4) + w15 + sigma0( w7));
+ Round(b, c, d, e, f, g, h, a, 0x682e6ff3, w7 += sigma1( w5) + w0 + sigma0( w8));
+ Round(a, b, c, d, e, f, g, h, 0x748f82ee, w8 += sigma1( w6) + w1 + sigma0( w9));
+ Round(h, a, b, c, d, e, f, g, 0x78a5636f, w9 += sigma1( w7) + w2 + sigma0(w10));
+ Round(g, h, a, b, c, d, e, f, 0x84c87814, w10 += sigma1( w8) + w3 + sigma0(w11));
+ Round(f, g, h, a, b, c, d, e, 0x8cc70208, w11 += sigma1( w9) + w4 + sigma0(w12));
+ Round(e, f, g, h, a, b, c, d, 0x90befffa, w12 += sigma1(w10) + w5 + sigma0(w13));
+ Round(d, e, f, g, h, a, b, c, 0xa4506ceb, w13 += sigma1(w11) + w6 + sigma0(w14));
+ Round(c, d, e, f, g, h, a, b, 0xbef9a3f7, w14 + sigma1(w12) + w7 + sigma0(w15));
+ Round(b, c, d, e, f, g, h, a, 0xc67178f2, w15 + sigma1(w13) + w8 + sigma0( w0));
+
+ s[0] += a;
+ s[1] += b;
+ s[2] += c;
+ s[3] += d;
+ s[4] += e;
+ s[5] += f;
+ s[6] += g;
+ s[7] += h;
+}
+
+} // namespace sha256
+
+/// Internal SHA-512 implementation.
+namespace sha512 {
+
+uint64_t inline Ch(uint64_t x, uint64_t y, uint64_t z) { return z ^ (x & (y ^ z)); }
+uint64_t inline Maj(uint64_t x, uint64_t y, uint64_t z) { return (x & y) | (z & (x | y)); }
+uint64_t inline Sigma0(uint64_t x) { return (x >> 28 | x << 36) ^ (x >> 34 | x << 30) ^ (x >> 39 | x << 25); }
+uint64_t inline Sigma1(uint64_t x) { return (x >> 14 | x << 50) ^ (x >> 18 | x << 46) ^ (x >> 41 | x << 23); }
+uint64_t inline sigma0(uint64_t x) { return (x >> 1 | x << 63) ^ (x >> 8 | x << 56) ^ (x >> 7); }
+uint64_t inline sigma1(uint64_t x) { return (x >> 19 | x << 45) ^ (x >> 61 | x << 3) ^ (x >> 6); }
+
+/** One round of SHA-512. */
+void inline Round(uint64_t a, uint64_t b, uint64_t c, uint64_t &d,
+ uint64_t e, uint64_t f, uint64_t g, uint64_t &h,
+ uint64_t k, uint64_t w) {
+ uint64_t t1 = h + Sigma1(e) + Ch(e, f, g) + k + w;
+ uint64_t t2 = Sigma0(a) + Maj(a, b, c);
+ d += t1;
+ h = t1 + t2;
+}
+
+/** Initialize SHA-256 state. */
+void inline Initialize(uint64_t *s) {
+ s[0] = 0x6a09e667f3bcc908ull;
+ s[1] = 0xbb67ae8584caa73bull;
+ s[2] = 0x3c6ef372fe94f82bull;
+ s[3] = 0xa54ff53a5f1d36f1ull;
+ s[4] = 0x510e527fade682d1ull;
+ s[5] = 0x9b05688c2b3e6c1full;
+ s[6] = 0x1f83d9abfb41bd6bull;
+ s[7] = 0x5be0cd19137e2179ull;
+}
+
+/** Perform one SHA-512 transformation, processing a 128-byte chunk. */
+void Transform(uint64_t *s, const unsigned char *chunk) {
+ uint64_t a = s[0], b = s[1], c = s[2], d = s[3], e = s[4], f = s[5], g = s[6], h = s[7];
+ uint64_t w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13, w14, w15;
+
+ Round(a, b, c, d, e, f, g, h, 0x428a2f98d728ae22ull, w0 = ReadBE64(chunk + 0));
+ Round(h, a, b, c, d, e, f, g, 0x7137449123ef65cdull, w1 = ReadBE64(chunk + 8));
+ Round(g, h, a, b, c, d, e, f, 0xb5c0fbcfec4d3b2full, w2 = ReadBE64(chunk + 16));
+ Round(f, g, h, a, b, c, d, e, 0xe9b5dba58189dbbcull, w3 = ReadBE64(chunk + 24));
+ Round(e, f, g, h, a, b, c, d, 0x3956c25bf348b538ull, w4 = ReadBE64(chunk + 32));
+ Round(d, e, f, g, h, a, b, c, 0x59f111f1b605d019ull, w5 = ReadBE64(chunk + 40));
+ Round(c, d, e, f, g, h, a, b, 0x923f82a4af194f9bull, w6 = ReadBE64(chunk + 48));
+ Round(b, c, d, e, f, g, h, a, 0xab1c5ed5da6d8118ull, w7 = ReadBE64(chunk + 56));
+ Round(a, b, c, d, e, f, g, h, 0xd807aa98a3030242ull, w8 = ReadBE64(chunk + 64));
+ Round(h, a, b, c, d, e, f, g, 0x12835b0145706fbeull, w9 = ReadBE64(chunk + 72));
+ Round(g, h, a, b, c, d, e, f, 0x243185be4ee4b28cull, w10 = ReadBE64(chunk + 80));
+ Round(f, g, h, a, b, c, d, e, 0x550c7dc3d5ffb4e2ull, w11 = ReadBE64(chunk + 88));
+ Round(e, f, g, h, a, b, c, d, 0x72be5d74f27b896full, w12 = ReadBE64(chunk + 96));
+ Round(d, e, f, g, h, a, b, c, 0x80deb1fe3b1696b1ull, w13 = ReadBE64(chunk + 104));
+ Round(c, d, e, f, g, h, a, b, 0x9bdc06a725c71235ull, w14 = ReadBE64(chunk + 112));
+ Round(b, c, d, e, f, g, h, a, 0xc19bf174cf692694ull, w15 = ReadBE64(chunk + 120));
+
+ Round(a, b, c, d, e, f, g, h, 0xe49b69c19ef14ad2ull, w0 += sigma1(w14) + w9 + sigma0( w1));
+ Round(h, a, b, c, d, e, f, g, 0xefbe4786384f25e3ull, w1 += sigma1(w15) + w10 + sigma0( w2));
+ Round(g, h, a, b, c, d, e, f, 0x0fc19dc68b8cd5b5ull, w2 += sigma1( w0) + w11 + sigma0( w3));
+ Round(f, g, h, a, b, c, d, e, 0x240ca1cc77ac9c65ull, w3 += sigma1( w1) + w12 + sigma0( w4));
+ Round(e, f, g, h, a, b, c, d, 0x2de92c6f592b0275ull, w4 += sigma1( w2) + w13 + sigma0( w5));
+ Round(d, e, f, g, h, a, b, c, 0x4a7484aa6ea6e483ull, w5 += sigma1( w3) + w14 + sigma0( w6));
+ Round(c, d, e, f, g, h, a, b, 0x5cb0a9dcbd41fbd4ull, w6 += sigma1( w4) + w15 + sigma0( w7));
+ Round(b, c, d, e, f, g, h, a, 0x76f988da831153b5ull, w7 += sigma1( w5) + w0 + sigma0( w8));
+ Round(a, b, c, d, e, f, g, h, 0x983e5152ee66dfabull, w8 += sigma1( w6) + w1 + sigma0( w9));
+ Round(h, a, b, c, d, e, f, g, 0xa831c66d2db43210ull, w9 += sigma1( w7) + w2 + sigma0(w10));
+ Round(g, h, a, b, c, d, e, f, 0xb00327c898fb213full, w10 += sigma1( w8) + w3 + sigma0(w11));
+ Round(f, g, h, a, b, c, d, e, 0xbf597fc7beef0ee4ull, w11 += sigma1( w9) + w4 + sigma0(w12));
+ Round(e, f, g, h, a, b, c, d, 0xc6e00bf33da88fc2ull, w12 += sigma1(w10) + w5 + sigma0(w13));
+ Round(d, e, f, g, h, a, b, c, 0xd5a79147930aa725ull, w13 += sigma1(w11) + w6 + sigma0(w14));
+ Round(c, d, e, f, g, h, a, b, 0x06ca6351e003826full, w14 += sigma1(w12) + w7 + sigma0(w15));
+ Round(b, c, d, e, f, g, h, a, 0x142929670a0e6e70ull, w15 += sigma1(w13) + w8 + sigma0( w0));
+
+ Round(a, b, c, d, e, f, g, h, 0x27b70a8546d22ffcull, w0 += sigma1(w14) + w9 + sigma0( w1));
+ Round(h, a, b, c, d, e, f, g, 0x2e1b21385c26c926ull, w1 += sigma1(w15) + w10 + sigma0( w2));
+ Round(g, h, a, b, c, d, e, f, 0x4d2c6dfc5ac42aedull, w2 += sigma1( w0) + w11 + sigma0( w3));
+ Round(f, g, h, a, b, c, d, e, 0x53380d139d95b3dfull, w3 += sigma1( w1) + w12 + sigma0( w4));
+ Round(e, f, g, h, a, b, c, d, 0x650a73548baf63deull, w4 += sigma1( w2) + w13 + sigma0( w5));
+ Round(d, e, f, g, h, a, b, c, 0x766a0abb3c77b2a8ull, w5 += sigma1( w3) + w14 + sigma0( w6));
+ Round(c, d, e, f, g, h, a, b, 0x81c2c92e47edaee6ull, w6 += sigma1( w4) + w15 + sigma0( w7));
+ Round(b, c, d, e, f, g, h, a, 0x92722c851482353bull, w7 += sigma1( w5) + w0 + sigma0( w8));
+ Round(a, b, c, d, e, f, g, h, 0xa2bfe8a14cf10364ull, w8 += sigma1( w6) + w1 + sigma0( w9));
+ Round(h, a, b, c, d, e, f, g, 0xa81a664bbc423001ull, w9 += sigma1( w7) + w2 + sigma0(w10));
+ Round(g, h, a, b, c, d, e, f, 0xc24b8b70d0f89791ull, w10 += sigma1( w8) + w3 + sigma0(w11));
+ Round(f, g, h, a, b, c, d, e, 0xc76c51a30654be30ull, w11 += sigma1( w9) + w4 + sigma0(w12));
+ Round(e, f, g, h, a, b, c, d, 0xd192e819d6ef5218ull, w12 += sigma1(w10) + w5 + sigma0(w13));
+ Round(d, e, f, g, h, a, b, c, 0xd69906245565a910ull, w13 += sigma1(w11) + w6 + sigma0(w14));
+ Round(c, d, e, f, g, h, a, b, 0xf40e35855771202aull, w14 += sigma1(w12) + w7 + sigma0(w15));
+ Round(b, c, d, e, f, g, h, a, 0x106aa07032bbd1b8ull, w15 += sigma1(w13) + w8 + sigma0( w0));
+
+ Round(a, b, c, d, e, f, g, h, 0x19a4c116b8d2d0c8ull, w0 += sigma1(w14) + w9 + sigma0( w1));
+ Round(h, a, b, c, d, e, f, g, 0x1e376c085141ab53ull, w1 += sigma1(w15) + w10 + sigma0( w2));
+ Round(g, h, a, b, c, d, e, f, 0x2748774cdf8eeb99ull, w2 += sigma1( w0) + w11 + sigma0( w3));
+ Round(f, g, h, a, b, c, d, e, 0x34b0bcb5e19b48a8ull, w3 += sigma1( w1) + w12 + sigma0( w4));
+ Round(e, f, g, h, a, b, c, d, 0x391c0cb3c5c95a63ull, w4 += sigma1( w2) + w13 + sigma0( w5));
+ Round(d, e, f, g, h, a, b, c, 0x4ed8aa4ae3418acbull, w5 += sigma1( w3) + w14 + sigma0( w6));
+ Round(c, d, e, f, g, h, a, b, 0x5b9cca4f7763e373ull, w6 += sigma1( w4) + w15 + sigma0( w7));
+ Round(b, c, d, e, f, g, h, a, 0x682e6ff3d6b2b8a3ull, w7 += sigma1( w5) + w0 + sigma0( w8));
+ Round(a, b, c, d, e, f, g, h, 0x748f82ee5defb2fcull, w8 += sigma1( w6) + w1 + sigma0( w9));
+ Round(h, a, b, c, d, e, f, g, 0x78a5636f43172f60ull, w9 += sigma1( w7) + w2 + sigma0(w10));
+ Round(g, h, a, b, c, d, e, f, 0x84c87814a1f0ab72ull, w10 += sigma1( w8) + w3 + sigma0(w11));
+ Round(f, g, h, a, b, c, d, e, 0x8cc702081a6439ecull, w11 += sigma1( w9) + w4 + sigma0(w12));
+ Round(e, f, g, h, a, b, c, d, 0x90befffa23631e28ull, w12 += sigma1(w10) + w5 + sigma0(w13));
+ Round(d, e, f, g, h, a, b, c, 0xa4506cebde82bde9ull, w13 += sigma1(w11) + w6 + sigma0(w14));
+ Round(c, d, e, f, g, h, a, b, 0xbef9a3f7b2c67915ull, w14 += sigma1(w12) + w7 + sigma0(w15));
+ Round(b, c, d, e, f, g, h, a, 0xc67178f2e372532bull, w15 += sigma1(w13) + w8 + sigma0( w0));
+
+ Round(a, b, c, d, e, f, g, h, 0xca273eceea26619cull, w0 += sigma1(w14) + w9 + sigma0( w1));
+ Round(h, a, b, c, d, e, f, g, 0xd186b8c721c0c207ull, w1 += sigma1(w15) + w10 + sigma0( w2));
+ Round(g, h, a, b, c, d, e, f, 0xeada7dd6cde0eb1eull, w2 += sigma1( w0) + w11 + sigma0( w3));
+ Round(f, g, h, a, b, c, d, e, 0xf57d4f7fee6ed178ull, w3 += sigma1( w1) + w12 + sigma0( w4));
+ Round(e, f, g, h, a, b, c, d, 0x06f067aa72176fbaull, w4 += sigma1( w2) + w13 + sigma0( w5));
+ Round(d, e, f, g, h, a, b, c, 0x0a637dc5a2c898a6ull, w5 += sigma1( w3) + w14 + sigma0( w6));
+ Round(c, d, e, f, g, h, a, b, 0x113f9804bef90daeull, w6 += sigma1( w4) + w15 + sigma0( w7));
+ Round(b, c, d, e, f, g, h, a, 0x1b710b35131c471bull, w7 += sigma1( w5) + w0 + sigma0( w8));
+ Round(a, b, c, d, e, f, g, h, 0x28db77f523047d84ull, w8 += sigma1( w6) + w1 + sigma0( w9));
+ Round(h, a, b, c, d, e, f, g, 0x32caab7b40c72493ull, w9 += sigma1( w7) + w2 + sigma0(w10));
+ Round(g, h, a, b, c, d, e, f, 0x3c9ebe0a15c9bebcull, w10 += sigma1( w8) + w3 + sigma0(w11));
+ Round(f, g, h, a, b, c, d, e, 0x431d67c49c100d4cull, w11 += sigma1( w9) + w4 + sigma0(w12));
+ Round(e, f, g, h, a, b, c, d, 0x4cc5d4becb3e42b6ull, w12 += sigma1(w10) + w5 + sigma0(w13));
+ Round(d, e, f, g, h, a, b, c, 0x597f299cfc657e2aull, w13 += sigma1(w11) + w6 + sigma0(w14));
+ Round(c, d, e, f, g, h, a, b, 0x5fcb6fab3ad6faecull, w14 += sigma1(w12) + w7 + sigma0(w15));
+ Round(b, c, d, e, f, g, h, a, 0x6c44198c4a475817ull, w15 += sigma1(w13) + w8 + sigma0( w0));
+
+ s[0] += a;
+ s[1] += b;
+ s[2] += c;
+ s[3] += d;
+ s[4] += e;
+ s[5] += f;
+ s[6] += g;
+ s[7] += h;
+}
+
+} // namespace sha512
+
+} // namespace
+
+
+////// SHA-256
+
+CSHA256::CSHA256() : bytes(0) {
+ sha256::Initialize(s);
+}
+
+CSHA256& CSHA256::Write(const unsigned char *data, size_t len) {
+ const unsigned char *end = data + len;
+ size_t bufsize = bytes % 64;
+ if (bufsize && bufsize + len >= 64) {
+ // Fill the buffer, and process it.
+ memcpy(buf + bufsize, data, 64 - bufsize);
+ bytes += 64 - bufsize;
+ data += 64 - bufsize;
+ sha256::Transform(s, buf);
+ bufsize = 0;
+ }
+ while (end >= data + 64) {
+ // Process full chunks directly from the source.
+ sha256::Transform(s, data);
+ bytes += 64;
+ data += 64;
+ }
+ if (end > data) {
+ // Fill the buffer with what remains.
+ memcpy(buf + bufsize, data, end - data);
+ bytes += end - data;
+ }
+ return *this;
+}
+
+void CSHA256::Finalize(unsigned char hash[OUTPUT_SIZE]) {
+ static const unsigned char pad[64] = {0x80};
+ unsigned char sizedesc[8];
+ WriteBE64(sizedesc, bytes << 3);
+ Write(pad, 1 + ((119 - (bytes % 64)) % 64));
+ Write(sizedesc, 8);
+ WriteBE32(hash, s[0]);
+ WriteBE32(hash+4, s[1]);
+ WriteBE32(hash+8, s[2]);
+ WriteBE32(hash+12, s[3]);
+ WriteBE32(hash+16, s[4]);
+ WriteBE32(hash+20, s[5]);
+ WriteBE32(hash+24, s[6]);
+ WriteBE32(hash+28, s[7]);
+}
+
+CSHA256& CSHA256::Reset() {
+ bytes = 0;
+ sha256::Initialize(s);
+ return *this;
+}
+
+////// SHA-512
+
+CSHA512::CSHA512() : bytes(0) {
+ sha512::Initialize(s);
+}
+
+CSHA512& CSHA512::Write(const unsigned char *data, size_t len) {
+ const unsigned char *end = data + len;
+ size_t bufsize = bytes % 128;
+ if (bufsize && bufsize + len >= 128) {
+ // Fill the buffer, and process it.
+ memcpy(buf + bufsize, data, 128 - bufsize);
+ bytes += 128 - bufsize;
+ data += 128 - bufsize;
+ sha512::Transform(s, buf);
+ bufsize = 0;
+ }
+ while (end >= data + 128) {
+ // Process full chunks directly from the source.
+ sha512::Transform(s, data);
+ data += 128;
+ bytes += 128;
+ }
+ if (end > data) {
+ // Fill the buffer with what remains.
+ memcpy(buf + bufsize, data, end - data);
+ bytes += end - data;
+ }
+ return *this;
+}
+
+void CSHA512::Finalize(unsigned char hash[OUTPUT_SIZE]) {
+ static const unsigned char pad[128] = {0x80};
+ unsigned char sizedesc[16] = {0x00};
+ WriteBE64(sizedesc+8, bytes << 3);
+ Write(pad, 1 + ((239 - (bytes % 128)) % 128));
+ Write(sizedesc, 16);
+ WriteBE64(hash, s[0]);
+ WriteBE64(hash+8, s[1]);
+ WriteBE64(hash+16, s[2]);
+ WriteBE64(hash+24, s[3]);
+ WriteBE64(hash+32, s[4]);
+ WriteBE64(hash+40, s[5]);
+ WriteBE64(hash+48, s[6]);
+ WriteBE64(hash+56, s[7]);
+}
+
+CSHA512& CSHA512::Reset() {
+ bytes = 0;
+ sha512::Initialize(s);
+ return *this;
+}
+
+////// HMAC-SHA-512
+
+CHMAC_SHA512::CHMAC_SHA512(const unsigned char *key, size_t keylen) {
+ unsigned char rkey[128];
+ if (keylen <= 128) {
+ memcpy(rkey, key, keylen);
+ memset(rkey + keylen, 0, 128 - keylen);
+ } else {
+ CSHA512().Write(key, keylen).Finalize(rkey);
+ memset(rkey + 64, 0, 64);
+ }
+
+ for (int n=0; n<128; n++)
+ rkey[n] ^= 0x5c;
+ outer.Write(rkey, 128);
+
+ for (int n=0; n<128; n++)
+ rkey[n] ^= 0x5c ^ 0x36;
+ inner.Write(rkey, 128);
+}
+
+void CHMAC_SHA512::Finalize(unsigned char hash[OUTPUT_SIZE]) {
+ unsigned char temp[64];
+ inner.Finalize(temp);
+ outer.Write(temp, 64).Finalize(hash);
+}
diff --git a/src/crypto/sha2.h b/src/crypto/sha2.h
new file mode 100644
index 0000000000..088d5e194c
--- /dev/null
+++ b/src/crypto/sha2.h
@@ -0,0 +1,60 @@
+// Copyright (c) 2014 The Bitcoin developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_SHA2_H
+#define BITCOIN_SHA2_H
+
+#include <stdint.h>
+#include <stdlib.h>
+
+/** A hasher class for SHA-256. */
+class CSHA256 {
+private:
+ uint32_t s[8];
+ unsigned char buf[64];
+ size_t bytes;
+
+public:
+ static const size_t OUTPUT_SIZE = 32;
+
+ CSHA256();
+ CSHA256& Write(const unsigned char *data, size_t len);
+ void Finalize(unsigned char hash[OUTPUT_SIZE]);
+ CSHA256& Reset();
+};
+
+/** A hasher class for SHA-512. */
+class CSHA512 {
+private:
+ uint64_t s[8];
+ unsigned char buf[128];
+ size_t bytes;
+
+public:
+ static const size_t OUTPUT_SIZE = 64;
+
+ CSHA512();
+ CSHA512& Write(const unsigned char *data, size_t len);
+ void Finalize(unsigned char hash[OUTPUT_SIZE]);
+ CSHA512& Reset();
+};
+
+/** A hasher class for HMAC-SHA-512. */
+class CHMAC_SHA512 {
+private:
+ CSHA512 outer;
+ CSHA512 inner;
+
+public:
+ static const size_t OUTPUT_SIZE = 64;
+
+ CHMAC_SHA512(const unsigned char *key, size_t keylen);
+ CHMAC_SHA512& Write(const unsigned char *data, size_t len) {
+ inner.Write(data, len);
+ return *this;
+ }
+ void Finalize(unsigned char hash[OUTPUT_SIZE]);
+};
+
+#endif
diff --git a/src/hash.cpp b/src/hash.cpp
index 7b054bd154..bddd8abf38 100644
--- a/src/hash.cpp
+++ b/src/hash.cpp
@@ -56,44 +56,3 @@ unsigned int MurmurHash3(unsigned int nHashSeed, const std::vector<unsigned char
return h1;
}
-
-int HMAC_SHA512_Init(HMAC_SHA512_CTX *pctx, const void *pkey, size_t len)
-{
- unsigned char key[128];
- if (len <= 128)
- {
- memcpy(key, pkey, len);
- memset(key + len, 0, 128-len);
- }
- else
- {
- SHA512_CTX ctxKey;
- SHA512_Init(&ctxKey);
- SHA512_Update(&ctxKey, pkey, len);
- SHA512_Final(key, &ctxKey);
- memset(key + 64, 0, 64);
- }
-
- for (int n=0; n<128; n++)
- key[n] ^= 0x5c;
- SHA512_Init(&pctx->ctxOuter);
- SHA512_Update(&pctx->ctxOuter, key, 128);
-
- for (int n=0; n<128; n++)
- key[n] ^= 0x5c ^ 0x36;
- SHA512_Init(&pctx->ctxInner);
- return SHA512_Update(&pctx->ctxInner, key, 128);
-}
-
-int HMAC_SHA512_Update(HMAC_SHA512_CTX *pctx, const void *pdata, size_t len)
-{
- return SHA512_Update(&pctx->ctxInner, pdata, len);
-}
-
-int HMAC_SHA512_Final(unsigned char *pmd, HMAC_SHA512_CTX *pctx)
-{
- unsigned char buf[64];
- SHA512_Final(buf, &pctx->ctxInner);
- SHA512_Update(&pctx->ctxOuter, buf, 64);
- return SHA512_Final(pmd, &pctx->ctxOuter);
-}
diff --git a/src/hash.h b/src/hash.h
index 7dbf1b6448..f2a0ebfe1f 100644
--- a/src/hash.h
+++ b/src/hash.h
@@ -6,55 +6,138 @@
#ifndef BITCOIN_HASH_H
#define BITCOIN_HASH_H
+#include "crypto/sha2.h"
+#include "crypto/ripemd160.h"
#include "serialize.h"
#include "uint256.h"
#include "version.h"
#include <vector>
-#include <openssl/ripemd.h>
-#include <openssl/sha.h>
+/** A hasher class for Bitcoin's 256-bit hash (double SHA-256). */
+class CHash256 {
+private:
+ CSHA256 sha;
+public:
+ static const size_t OUTPUT_SIZE = CSHA256::OUTPUT_SIZE;
+
+ void Finalize(unsigned char hash[OUTPUT_SIZE]) {
+ unsigned char buf[sha.OUTPUT_SIZE];
+ sha.Finalize(buf);
+ sha.Reset().Write(buf, sha.OUTPUT_SIZE).Finalize(hash);
+ }
+
+ CHash256& Write(const unsigned char *data, size_t len) {
+ sha.Write(data, len);
+ return *this;
+ }
+
+ CHash256& Reset() {
+ sha.Reset();
+ return *this;
+ }
+};
+/** A hasher class for Bitcoin's 160-bit hash (SHA-256 + RIPEMD-160). */
+class CHash160 {
+private:
+ CSHA256 sha;
+public:
+ static const size_t OUTPUT_SIZE = CRIPEMD160::OUTPUT_SIZE;
+
+ void Finalize(unsigned char hash[OUTPUT_SIZE]) {
+ unsigned char buf[sha.OUTPUT_SIZE];
+ sha.Finalize(buf);
+ CRIPEMD160().Write(buf, sha.OUTPUT_SIZE).Finalize(hash);
+ }
+
+ CHash160& Write(const unsigned char *data, size_t len) {
+ sha.Write(data, len);
+ return *this;
+ }
+
+ CHash160& Reset() {
+ sha.Reset();
+ return *this;
+ }
+};
+
+/** Compute the 256-bit hash of an object. */
template<typename T1>
inline uint256 Hash(const T1 pbegin, const T1 pend)
{
- static unsigned char pblank[1];
- uint256 hash1;
- SHA256((pbegin == pend ? pblank : (unsigned char*)&pbegin[0]), (pend - pbegin) * sizeof(pbegin[0]), (unsigned char*)&hash1);
- uint256 hash2;
- SHA256((unsigned char*)&hash1, sizeof(hash1), (unsigned char*)&hash2);
- return hash2;
+ static const unsigned char pblank[1] = {};
+ uint256 result;
+ CHash256().Write(pbegin == pend ? pblank : (const unsigned char*)&pbegin[0], (pend - pbegin) * sizeof(pbegin[0]))
+ .Finalize((unsigned char*)&result);
+ return result;
+}
+
+/** Compute the 256-bit hash of the concatenation of two objects. */
+template<typename T1, typename T2>
+inline uint256 Hash(const T1 p1begin, const T1 p1end,
+ const T2 p2begin, const T2 p2end) {
+ static const unsigned char pblank[1] = {};
+ uint256 result;
+ CHash256().Write(p1begin == p1end ? pblank : (const unsigned char*)&p1begin[0], (p1end - p1begin) * sizeof(p1begin[0]))
+ .Write(p2begin == p2end ? pblank : (const unsigned char*)&p2begin[0], (p2end - p2begin) * sizeof(p2begin[0]))
+ .Finalize((unsigned char*)&result);
+ return result;
+}
+
+/** Compute the 256-bit hash of the concatenation of three objects. */
+template<typename T1, typename T2, typename T3>
+inline uint256 Hash(const T1 p1begin, const T1 p1end,
+ const T2 p2begin, const T2 p2end,
+ const T3 p3begin, const T3 p3end) {
+ static const unsigned char pblank[1] = {};
+ uint256 result;
+ CHash256().Write(p1begin == p1end ? pblank : (const unsigned char*)&p1begin[0], (p1end - p1begin) * sizeof(p1begin[0]))
+ .Write(p2begin == p2end ? pblank : (const unsigned char*)&p2begin[0], (p2end - p2begin) * sizeof(p2begin[0]))
+ .Write(p3begin == p3end ? pblank : (const unsigned char*)&p3begin[0], (p3end - p3begin) * sizeof(p3begin[0]))
+ .Finalize((unsigned char*)&result);
+ return result;
+}
+
+/** Compute the 160-bit hash an object. */
+template<typename T1>
+inline uint160 Hash160(const T1 pbegin, const T1 pend)
+{
+ static unsigned char pblank[1] = {};
+ uint160 result;
+ CHash160().Write(pbegin == pend ? pblank : (const unsigned char*)&pbegin[0], (pend - pbegin) * sizeof(pbegin[0]))
+ .Finalize((unsigned char*)&result);
+ return result;
}
+/** Compute the 160-bit hash of a vector. */
+inline uint160 Hash160(const std::vector<unsigned char>& vch)
+{
+ return Hash160(vch.begin(), vch.end());
+}
+
+/** A writer stream (for serialization) that computes a 256-bit hash. */
class CHashWriter
{
private:
- SHA256_CTX ctx;
+ CHash256 ctx;
public:
int nType;
int nVersion;
- void Init() {
- SHA256_Init(&ctx);
- }
-
- CHashWriter(int nTypeIn, int nVersionIn) : nType(nTypeIn), nVersion(nVersionIn) {
- Init();
- }
+ CHashWriter(int nTypeIn, int nVersionIn) : nType(nTypeIn), nVersion(nVersionIn) {}
CHashWriter& write(const char *pch, size_t size) {
- SHA256_Update(&ctx, pch, size);
+ ctx.Write((const unsigned char*)pch, size);
return (*this);
}
// invalidates the object
uint256 GetHash() {
- uint256 hash1;
- SHA256_Final((unsigned char*)&hash1, &ctx);
- uint256 hash2;
- SHA256((unsigned char*)&hash1, sizeof(hash1), (unsigned char*)&hash2);
- return hash2;
+ uint256 result;
+ ctx.Finalize((unsigned char*)&result);
+ return result;
}
template<typename T>
@@ -65,41 +148,7 @@ public:
}
};
-
-template<typename T1, typename T2>
-inline uint256 Hash(const T1 p1begin, const T1 p1end,
- const T2 p2begin, const T2 p2end)
-{
- static unsigned char pblank[1];
- uint256 hash1;
- SHA256_CTX ctx;
- SHA256_Init(&ctx);
- SHA256_Update(&ctx, (p1begin == p1end ? pblank : (unsigned char*)&p1begin[0]), (p1end - p1begin) * sizeof(p1begin[0]));
- SHA256_Update(&ctx, (p2begin == p2end ? pblank : (unsigned char*)&p2begin[0]), (p2end - p2begin) * sizeof(p2begin[0]));
- SHA256_Final((unsigned char*)&hash1, &ctx);
- uint256 hash2;
- SHA256((unsigned char*)&hash1, sizeof(hash1), (unsigned char*)&hash2);
- return hash2;
-}
-
-template<typename T1, typename T2, typename T3>
-inline uint256 Hash(const T1 p1begin, const T1 p1end,
- const T2 p2begin, const T2 p2end,
- const T3 p3begin, const T3 p3end)
-{
- static unsigned char pblank[1];
- uint256 hash1;
- SHA256_CTX ctx;
- SHA256_Init(&ctx);
- SHA256_Update(&ctx, (p1begin == p1end ? pblank : (unsigned char*)&p1begin[0]), (p1end - p1begin) * sizeof(p1begin[0]));
- SHA256_Update(&ctx, (p2begin == p2end ? pblank : (unsigned char*)&p2begin[0]), (p2end - p2begin) * sizeof(p2begin[0]));
- SHA256_Update(&ctx, (p3begin == p3end ? pblank : (unsigned char*)&p3begin[0]), (p3end - p3begin) * sizeof(p3begin[0]));
- SHA256_Final((unsigned char*)&hash1, &ctx);
- uint256 hash2;
- SHA256((unsigned char*)&hash1, sizeof(hash1), (unsigned char*)&hash2);
- return hash2;
-}
-
+/** Compute the 256-bit hash of an object's serialization. */
template<typename T>
uint256 SerializeHash(const T& obj, int nType=SER_GETHASH, int nVersion=PROTOCOL_VERSION)
{
@@ -108,32 +157,6 @@ uint256 SerializeHash(const T& obj, int nType=SER_GETHASH, int nVersion=PROTOCOL
return ss.GetHash();
}
-template<typename T1>
-inline uint160 Hash160(const T1 pbegin, const T1 pend)
-{
- static unsigned char pblank[1];
- uint256 hash1;
- SHA256((pbegin == pend ? pblank : (unsigned char*)&pbegin[0]), (pend - pbegin) * sizeof(pbegin[0]), (unsigned char*)&hash1);
- uint160 hash2;
- RIPEMD160((unsigned char*)&hash1, sizeof(hash1), (unsigned char*)&hash2);
- return hash2;
-}
-
-inline uint160 Hash160(const std::vector<unsigned char>& vch)
-{
- return Hash160(vch.begin(), vch.end());
-}
-
unsigned int MurmurHash3(unsigned int nHashSeed, const std::vector<unsigned char>& vDataToHash);
-typedef struct
-{
- SHA512_CTX ctxInner;
- SHA512_CTX ctxOuter;
-} HMAC_SHA512_CTX;
-
-int HMAC_SHA512_Init(HMAC_SHA512_CTX *pctx, const void *pkey, size_t len);
-int HMAC_SHA512_Update(HMAC_SHA512_CTX *pctx, const void *pdata, size_t len);
-int HMAC_SHA512_Final(unsigned char *pmd, HMAC_SHA512_CTX *pctx);
-
#endif
diff --git a/src/init.cpp b/src/init.cpp
index 7664988762..f9e568a207 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -4,13 +4,14 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#if defined(HAVE_CONFIG_H)
-#include "bitcoin-config.h"
+#include "config/bitcoin-config.h"
#endif
#include "init.h"
#include "addrman.h"
#include "checkpoints.h"
+#include "key.h"
#include "main.h"
#include "miner.h"
#include "net.h"
@@ -30,6 +31,7 @@
#ifndef WIN32
#include <signal.h>
#endif
+#include "compat/sanity.h"
#include <boost/algorithm/string/predicate.hpp>
#include <boost/filesystem.hpp>
@@ -40,7 +42,6 @@ using namespace std;
using namespace boost;
#ifdef ENABLE_WALLET
-std::string strWalletFile;
CWallet* pwalletMain;
#endif
@@ -60,6 +61,8 @@ enum BindFlags {
BF_REPORT_ERROR = (1U << 1)
};
+static const char* FEE_ESTIMATES_FILENAME="fee_estimates.dat";
+CClientUIInterface uiInterface;
//////////////////////////////////////////////////////////////////////////////
//
@@ -114,7 +117,6 @@ void Shutdown()
RenameThread("bitcoin-shutoff");
mempool.AddTransactionsUpdated(1);
StopRPCThreads();
- ShutdownRPCMining();
#ifdef ENABLE_WALLET
if (pwalletMain)
bitdb.Flush(false);
@@ -122,6 +124,14 @@ void Shutdown()
#endif
StopNode();
UnregisterNodeSignals(GetNodeSignals());
+
+ boost::filesystem::path est_path = GetDataDir() / FEE_ESTIMATES_FILENAME;
+ CAutoFile est_fileout = CAutoFile(fopen(est_path.string().c_str(), "wb"), SER_DISK, CLIENT_VERSION);
+ if (est_fileout)
+ mempool.WriteFeeEstimates(est_fileout);
+ else
+ LogPrintf("failed to write fee estimates");
+
{
LOCK(cs_main);
#ifdef ENABLE_WALLET
@@ -186,9 +196,9 @@ bool static Bind(const CService &addr, unsigned int flags) {
return true;
}
-// Core-specific options shared between UI, daemon and RPC client
-std::string HelpMessage(HelpMessageMode hmm)
+std::string HelpMessage(HelpMessageMode mode)
{
+ // When adding new options to the categories, please keep and ensure alphabetical ordering.
string strUsage = _("Options:") + "\n";
strUsage += " -? " + _("This help message") + "\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";
@@ -196,7 +206,7 @@ std::string HelpMessage(HelpMessageMode hmm)
strUsage += " -checkblocks=<n> " + _("How many blocks to check at startup (default: 288, 0 = all)") + "\n";
strUsage += " -checklevel=<n> " + _("How thorough the block verification of -checkblocks is (0-4, default: 3)") + "\n";
strUsage += " -conf=<file> " + _("Specify configuration file (default: bitcoin.conf)") + "\n";
- if (hmm == HMM_BITCOIND)
+ if (mode == HMM_BITCOIND)
{
#if !defined(WIN32)
strUsage += " -daemon " + _("Run in the background as a daemon and accept commands") + "\n";
@@ -206,6 +216,7 @@ std::string HelpMessage(HelpMessageMode hmm)
strUsage += " -dbcache=<n> " + strprintf(_("Set database cache size in megabytes (%d to %d, default: %d)"), nMinDbCache, nMaxDbCache, nDefaultDbCache) + "\n";
strUsage += " -keypool=<n> " + _("Set key pool size to <n> (default: 100)") + "\n";
strUsage += " -loadblock=<file> " + _("Imports blocks from external blk000??.dat file") + " " + _("on startup") + "\n";
+ strUsage += " -maxorphanblocks=<n> " + strprintf(_("Keep at most <n> unconnectable blocks in memory (default: %u)"), DEFAULT_MAX_ORPHAN_BLOCKS) + "\n";
strUsage += " -par=<n> " + strprintf(_("Set the number of script verification threads (%u to %d, 0 = auto, <0 = leave that many cores free, default: %d)"), -(int)boost::thread::hardware_concurrency(), MAX_SCRIPTCHECK_THREADS, DEFAULT_SCRIPTCHECK_THREADS) + "\n";
strUsage += " -pid=<file> " + _("Specify pid file (default: bitcoind.pid)") + "\n";
strUsage += " -reindex " + _("Rebuild block chain index from current blk000??.dat files") + " " + _("on startup") + "\n";
@@ -228,9 +239,8 @@ std::string HelpMessage(HelpMessageMode hmm)
strUsage += " -onion=<ip:port> " + _("Use separate SOCKS5 proxy to reach peers via Tor hidden services (default: -proxy)") + "\n";
strUsage += " -onlynet=<net> " + _("Only connect to nodes in network <net> (IPv4, IPv6 or Tor)") + "\n";
strUsage += " -port=<port> " + _("Listen for connections on <port> (default: 8333 or testnet: 18333)") + "\n";
- strUsage += " -proxy=<ip:port> " + _("Connect through SOCKS proxy") + "\n";
+ strUsage += " -proxy=<ip:port> " + _("Connect through SOCKS5 proxy") + "\n";
strUsage += " -seednode=<ip> " + _("Connect to a node to retrieve peer addresses, and disconnect") + "\n";
- strUsage += " -socks=<n> " + _("Select SOCKS version for -proxy (4 or 5, default: 5)") + "\n";
strUsage += " -timeout=<n> " + _("Specify connection timeout in milliseconds (default: 5000)") + "\n";
#ifdef USE_UPNP
#if USE_UPNP
@@ -243,14 +253,19 @@ std::string HelpMessage(HelpMessageMode hmm)
#ifdef ENABLE_WALLET
strUsage += "\n" + _("Wallet options:") + "\n";
strUsage += " -disablewallet " + _("Do not load the wallet and disable wallet RPC calls") + "\n";
- strUsage += " -paytxfee=<amt> " + _("Fee per kB to add to transactions you send") + "\n";
+ if (GetBoolArg("-help-debug", false))
+ strUsage += " -mintxfee=<amt> " + strprintf(_("Fees (in BTC/Kb) smaller than this are considered zero fee for transaction creation (default: %s)"), FormatMoney(CWallet::minTxFee.GetFeePerK())) + "\n";
+ strUsage += " -paytxfee=<amt> " + strprintf(_("Fee (in BTC/kB) to add to transactions you send (default: %s)"), FormatMoney(payTxFee.GetFeePerK())) + "\n";
strUsage += " -rescan " + _("Rescan the block chain for missing wallet transactions") + " " + _("on startup") + "\n";
+ strUsage += " -respendnotify=<cmd> " + _("Execute command when a network tx respends wallet tx input (%s=respend TxID, %t=wallet TxID)") + "\n";
strUsage += " -salvagewallet " + _("Attempt to recover private keys from a corrupt wallet.dat") + " " + _("on startup") + "\n";
strUsage += " -spendzeroconfchange " + _("Spend unconfirmed change when sending transactions (default: 1)") + "\n";
+ strUsage += " -txconfirmtarget=<n> " + _("If paytxfee is not set, include enough fee so transactions are confirmed on average within n blocks (default: 1)") + "\n";
strUsage += " -upgradewallet " + _("Upgrade wallet to latest format") + " " + _("on startup") + "\n";
strUsage += " -wallet=<file> " + _("Specify wallet file (within data directory)") + " " + _("(default: wallet.dat)") + "\n";
strUsage += " -walletnotify=<cmd> " + _("Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)") + "\n";
- strUsage += " -zapwallettxes " + _("Clear list of wallet transactions (diagnostic tool; implies -rescan)") + "\n";
+ strUsage += " -zapwallettxes=<mode> " + _("Delete all wallet transactions and only recover those part of the blockchain through -rescan on startup") + "\n";
+ strUsage += " " + _("(default: 1, 1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data)") + "\n";
#endif
strUsage += "\n" + _("Debugging/Testing options:") + "\n";
@@ -264,25 +279,26 @@ std::string HelpMessage(HelpMessageMode hmm)
strUsage += " -dropmessagestest=<n> " + _("Randomly drop 1 of every <n> network messages") + "\n";
strUsage += " -fuzzmessagestest=<n> " + _("Randomly fuzz 1 of every <n> network messages") + "\n";
strUsage += " -flushwallet " + _("Run a thread to flush wallet periodically (default: 1)") + "\n";
+ strUsage += " -stopafterblockimport " + _("Stop running after importing blocks from disk (default: 0)") + "\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)
+ if (mode == HMM_BITCOIN_QT)
strUsage += ", qt";
strUsage += ".\n";
strUsage += " -gen " + _("Generate coins (default: 0)") + "\n";
strUsage += " -genproclimit=<n> " + _("Set the processor limit for when generation is on (-1 = unlimited, default: -1)") + "\n";
strUsage += " -help-debug " + _("Show all debugging options (usage: --help -help-debug)") + "\n";
+ strUsage += " -logips " + _("Include IP addresses in debug output (default: 0)") + "\n";
strUsage += " -logtimestamps " + _("Prepend debug output with timestamp (default: 1)") + "\n";
if (GetBoolArg("-help-debug", false))
{
strUsage += " -limitfreerelay=<n> " + _("Continuously rate-limit free transactions to <n>*1000 bytes per minute (default:15)") + "\n";
strUsage += " -maxsigcachesize=<n> " + _("Limit size of signature cache to <n> entries (default: 50000)") + "\n";
}
- strUsage += " -mintxfee=<amt> " + _("Fees smaller than this are considered zero fee (for transaction creation) (default:") + " " + FormatMoney(CTransaction::nMinTxFee) + ")" + "\n";
- strUsage += " -minrelaytxfee=<amt> " + _("Fees smaller than this are considered zero fee (for relaying) (default:") + " " + FormatMoney(CTransaction::nMinRelayTxFee) + ")" + "\n";
+ strUsage += " -minrelaytxfee=<amt> " + strprintf(_("Fees (in BTC/Kb) smaller than this are considered zero fee for relaying (default: %s)"), FormatMoney(::minRelayTxFee.GetFeePerK())) + "\n";
strUsage += " -printtoconsole " + _("Send trace/debug info to console instead of debug.log file") + "\n";
if (GetBoolArg("-help-debug", false))
{
@@ -297,6 +313,8 @@ std::string HelpMessage(HelpMessageMode hmm)
strUsage += " -shrinkdebugfile " + _("Shrink debug.log file on client startup (default: 1 when no -debug)") + "\n";
strUsage += " -testnet " + _("Use the test network") + "\n";
+ strUsage += "\n" + _("Node relay options:") + "\n";
+ strUsage += " -datacarrier " + _("Relay and mine data carrier transactions (default: 1)") + "\n";
strUsage += "\n" + _("Block creation options:") + "\n";
strUsage += " -blockminsize=<n> " + _("Set minimum block size in bytes (default: 0)") + "\n";
strUsage += " -blockmaxsize=<n> " + strprintf(_("Set maximum block size in bytes (default: %d)"), DEFAULT_BLOCK_MAX_SIZE) + "\n";
@@ -308,7 +326,7 @@ std::string HelpMessage(HelpMessageMode hmm)
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. This option can be specified multiple times") + "\n";
+ strUsage += " -rpcallowip=<ip> " + _("Allow JSON-RPC connections from specified source. Valid for <ip> are a single IP (e.g. 1.2.3.4), a network/netmask (e.g. 1.2.3.4/255.255.255.0) or a network/CIDR (e.g. 1.2.3.4/24). This option can be specified multiple times") + "\n";
strUsage += " -rpcthreads=<n> " + _("Set the number of threads to service RPC calls (default: 4)") + "\n";
strUsage += "\n" + _("RPC SSL options: (see the Bitcoin Wiki for SSL setup instructions)") + "\n";
@@ -320,6 +338,18 @@ std::string HelpMessage(HelpMessageMode hmm)
return strUsage;
}
+std::string LicenseInfo()
+{
+ return FormatParagraph(strprintf(_("Copyright (C) 2009-%i The Bitcoin Core Developers"), COPYRIGHT_YEAR)) + "\n" +
+ "\n" +
+ FormatParagraph(_("This is experimental software.")) + "\n" +
+ "\n" +
+ FormatParagraph(_("Distributed under the MIT/X11 software license, see the accompanying file COPYING or <http://www.opensource.org/licenses/mit-license.php>.")) + "\n" +
+ "\n" +
+ FormatParagraph(_("This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit <https://www.openssl.org/> and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard.")) +
+ "\n";
+}
+
struct CImportingNow
{
CImportingNow() {
@@ -383,6 +413,28 @@ void ThreadImport(std::vector<boost::filesystem::path> vImportFiles)
LogPrintf("Warning: Could not open blocks file %s\n", path.string());
}
}
+
+ if (GetBoolArg("-stopafterblockimport", false)) {
+ LogPrintf("Stopping after block import\n");
+ StartShutdown();
+ }
+}
+
+/** Sanity checks
+ * Ensure that Bitcoin is running in a usable environment with all
+ * necessary library support.
+ */
+bool InitSanityCheck(void)
+{
+ if(!ECC_InitSanityCheck()) {
+ InitError("OpenSSL appears to lack support for elliptic curve cryptography. For more "
+ "information, visit https://en.bitcoin.it/wiki/OpenSSL_and_EC_Libraries");
+ return false;
+ }
+ if (!glibc_sanity_test() || !glibcxx_sanity_test())
+ return false;
+
+ return true;
}
/** Initialize bitcoin.
@@ -491,7 +543,7 @@ bool AppInit2(boost::thread_group& threadGroup)
// -zapwallettx implies a rescan
if (GetBoolArg("-zapwallettxes", false)) {
if (SoftSetBoolArg("-rescan", true))
- LogPrintf("AppInit2 : parameter interaction: -zapwallettxes=1 -> setting -rescan=1\n");
+ LogPrintf("AppInit2 : parameter interaction: -zapwallettxes=<mode> -> setting -rescan=1\n");
}
// Make sure enough file descriptors are available
@@ -515,9 +567,16 @@ bool AppInit2(boost::thread_group& threadGroup)
// Check for -debugnet (deprecated)
if (GetBoolArg("-debugnet", false))
InitWarning(_("Warning: Deprecated argument -debugnet ignored, use -debug=net"));
+ // Check for -socks - as this is a privacy risk to continue, exit here
+ if (mapArgs.count("-socks"))
+ return InitError(_("Error: Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported."));
+ // Check for -tor - as this is a privacy risk to continue, exit here
+ if (GetBoolArg("-tor", false))
+ return InitError(_("Error: Unsupported argument -tor found, use -onion."));
fBenchmark = GetBoolArg("-benchmark", false);
- mempool.setSanityCheck(GetBoolArg("-checkmempool", RegTest()));
+ // Checkmempool defaults to true in regtest mode
+ mempool.setSanityCheck(GetBoolArg("-checkmempool", Params().DefaultCheckMemPool()));
Checkpoints::fEnabled = GetBoolArg("-checkpoints", true);
// -par=0 means autodetect, but nScriptCheckThreads==0 means no concurrency
@@ -532,6 +591,7 @@ bool AppInit2(boost::thread_group& threadGroup)
fServer = GetBoolArg("-server", false);
fPrintToConsole = GetBoolArg("-printtoconsole", false);
fLogTimestamps = GetBoolArg("-logtimestamps", true);
+ fLogIPs = GetBoolArg("-logips", false);
setvbuf(stdout, NULL, _IOLBF, 0);
#ifdef ENABLE_WALLET
bool fDisableWallet = GetBoolArg("-disablewallet", false);
@@ -556,36 +616,47 @@ bool AppInit2(boost::thread_group& threadGroup)
// a transaction spammer can cheaply fill blocks using
// 1-satoshi-fee transactions. It should be set above the real
// cost to you of processing a transaction.
- if (mapArgs.count("-mintxfee"))
- {
- int64_t n = 0;
- if (ParseMoney(mapArgs["-mintxfee"], n) && n > 0)
- CTransaction::nMinTxFee = n;
- else
- return InitError(strprintf(_("Invalid amount for -mintxfee=<amount>: '%s'"), mapArgs["-mintxfee"]));
- }
if (mapArgs.count("-minrelaytxfee"))
{
int64_t n = 0;
if (ParseMoney(mapArgs["-minrelaytxfee"], n) && n > 0)
- CTransaction::nMinRelayTxFee = n;
+ ::minRelayTxFee = CFeeRate(n);
else
return InitError(strprintf(_("Invalid amount for -minrelaytxfee=<amount>: '%s'"), mapArgs["-minrelaytxfee"]));
}
#ifdef ENABLE_WALLET
+ if (mapArgs.count("-mintxfee"))
+ {
+ int64_t n = 0;
+ if (ParseMoney(mapArgs["-mintxfee"], n) && n > 0)
+ CWallet::minTxFee = CFeeRate(n);
+ else
+ return InitError(strprintf(_("Invalid amount for -mintxfee=<amount>: '%s'"), mapArgs["-mintxfee"]));
+ }
if (mapArgs.count("-paytxfee"))
{
- if (!ParseMoney(mapArgs["-paytxfee"], nTransactionFee))
+ int64_t nFeePerK = 0;
+ if (!ParseMoney(mapArgs["-paytxfee"], nFeePerK))
return InitError(strprintf(_("Invalid amount for -paytxfee=<amount>: '%s'"), mapArgs["-paytxfee"]));
- if (nTransactionFee > nHighTransactionFeeWarning)
+ if (nFeePerK > nHighTransactionFeeWarning)
InitWarning(_("Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction."));
+ payTxFee = CFeeRate(nFeePerK, 1000);
+ if (payTxFee < ::minRelayTxFee)
+ {
+ return InitError(strprintf(_("Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s)"),
+ mapArgs["-paytxfee"], ::minRelayTxFee.ToString()));
+ }
}
+ nTxConfirmTarget = GetArg("-txconfirmtarget", 1);
bSpendZeroConfChange = GetArg("-spendzeroconfchange", true);
- strWalletFile = GetArg("-wallet", "wallet.dat");
+ std::string strWalletFile = GetArg("-wallet", "wallet.dat");
#endif
// ********************************************************* Step 4: application initialization: dir lock, daemonize, pidfile, debug log
+ // Sanity check
+ if (!InitSanityCheck())
+ return InitError(_("Initialization sanity check failed. Bitcoin Core is shutting down."));
std::string strDataDir = GetDataDir().string();
#ifdef ENABLE_WALLET
@@ -613,6 +684,7 @@ bool AppInit2(boost::thread_group& threadGroup)
LogPrintf("Startup time: %s\n", DateTimeStrFormat("%Y-%m-%d %H:%M:%S", GetTime()));
LogPrintf("Default data directory %s\n", GetDefaultDataDir().string());
LogPrintf("Using data directory %s\n", strDataDir);
+ LogPrintf("Using config file %s\n", GetConfigFile().string());
LogPrintf("Using at most %i connections (%i file descriptors available)\n", nMaxConnections, nFD);
std::ostringstream strErrors;
@@ -677,10 +749,6 @@ bool AppInit2(boost::thread_group& threadGroup)
RegisterNodeSignals(GetNodeSignals());
- int nSocksVersion = GetArg("-socks", 5);
- if (nSocksVersion != 4 && nSocksVersion != 5)
- return InitError(strprintf(_("Unknown -socks proxy version requested: %i"), nSocksVersion));
-
if (mapArgs.count("-onlynet")) {
std::set<enum Network> nets;
BOOST_FOREACH(std::string snet, mapMultiArgs["-onlynet"]) {
@@ -704,40 +772,34 @@ bool AppInit2(boost::thread_group& threadGroup)
return InitError(strprintf(_("Invalid -proxy address: '%s'"), mapArgs["-proxy"]));
if (!IsLimited(NET_IPV4))
- SetProxy(NET_IPV4, addrProxy, nSocksVersion);
- if (nSocksVersion > 4) {
- if (!IsLimited(NET_IPV6))
- SetProxy(NET_IPV6, addrProxy, nSocksVersion);
- SetNameProxy(addrProxy, nSocksVersion);
- }
+ SetProxy(NET_IPV4, addrProxy);
+ if (!IsLimited(NET_IPV6))
+ SetProxy(NET_IPV6, addrProxy);
+ SetNameProxy(addrProxy);
fProxy = true;
}
// -onion can override normal proxy, -noonion disables tor entirely
- // -tor here is a temporary backwards compatibility measure
- if (mapArgs.count("-tor"))
- printf("Notice: option -tor has been replaced with -onion and will be removed in a later version.\n");
if (!(mapArgs.count("-onion") && mapArgs["-onion"] == "0") &&
- !(mapArgs.count("-tor") && mapArgs["-tor"] == "0") &&
- (fProxy || mapArgs.count("-onion") || mapArgs.count("-tor"))) {
+ (fProxy || mapArgs.count("-onion"))) {
CService addrOnion;
- if (!mapArgs.count("-onion") && !mapArgs.count("-tor"))
+ if (!mapArgs.count("-onion"))
addrOnion = addrProxy;
else
- addrOnion = mapArgs.count("-onion")?CService(mapArgs["-onion"], 9050):CService(mapArgs["-tor"], 9050);
+ addrOnion = CService(mapArgs["-onion"], 9050);
if (!addrOnion.IsValid())
- return InitError(strprintf(_("Invalid -onion address: '%s'"), mapArgs.count("-onion")?mapArgs["-onion"]:mapArgs["-tor"]));
- SetProxy(NET_TOR, addrOnion, 5);
+ return InitError(strprintf(_("Invalid -onion address: '%s'"), mapArgs["-onion"]));
+ SetProxy(NET_TOR, addrOnion);
SetReachable(NET_TOR);
}
// see Step 2: parameter interactions for more information about these
- fNoListen = !GetBoolArg("-listen", true);
+ fListen = GetBoolArg("-listen", DEFAULT_LISTEN);
fDiscover = GetBoolArg("-discover", true);
fNameLookup = GetBoolArg("-dns", true);
bool fBound = false;
- if (!fNoListen) {
+ if (fListen) {
if (mapArgs.count("-bind")) {
BOOST_FOREACH(std::string strBind, mapMultiArgs["-bind"]) {
CService addrBind;
@@ -858,7 +920,7 @@ bool AppInit2(boost::thread_group& threadGroup)
}
uiInterface.InitMessage(_("Verifying blocks..."));
- if (!VerifyDB(GetArg("-checklevel", 3),
+ if (!CVerifyDB().VerifyDB(GetArg("-checklevel", 3),
GetArg("-checkblocks", 288))) {
strLoadError = _("Corrupted block database detected");
break;
@@ -914,7 +976,7 @@ bool AppInit2(boost::thread_group& threadGroup)
for (map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.begin(); mi != mapBlockIndex.end(); ++mi)
{
uint256 hash = (*mi).first;
- if (strncmp(hash.ToString().c_str(), strMatch.c_str(), strMatch.size()) == 0)
+ if (boost::algorithm::starts_with(hash.ToString(), strMatch))
{
CBlockIndex* pindex = (*mi).second;
CBlock block;
@@ -930,17 +992,26 @@ bool AppInit2(boost::thread_group& threadGroup)
return false;
}
+ boost::filesystem::path est_path = GetDataDir() / FEE_ESTIMATES_FILENAME;
+ CAutoFile est_filein = CAutoFile(fopen(est_path.string().c_str(), "rb"), SER_DISK, CLIENT_VERSION);
+ if (est_filein)
+ mempool.ReadFeeEstimates(est_filein);
+
// ********************************************************* Step 8: load wallet
#ifdef ENABLE_WALLET
if (fDisableWallet) {
pwalletMain = NULL;
LogPrintf("Wallet disabled!\n");
} else {
+
+ // needed to restore wallet transaction meta data after -zapwallettxes
+ std::vector<CWalletTx> vWtx;
+
if (GetBoolArg("-zapwallettxes", false)) {
uiInterface.InitMessage(_("Zapping all transactions from wallet..."));
pwalletMain = new CWallet(strWalletFile);
- DBErrors nZapWalletRet = pwalletMain->ZapWalletTx();
+ DBErrors nZapWalletRet = pwalletMain->ZapWalletTx(vWtx);
if (nZapWalletRet != DB_LOAD_OK) {
uiInterface.InitMessage(_("Error loading wallet.dat: Wallet corrupted"));
return false;
@@ -1035,6 +1106,29 @@ bool AppInit2(boost::thread_group& threadGroup)
LogPrintf(" rescan %15dms\n", GetTimeMillis() - nStart);
pwalletMain->SetBestChain(chainActive.GetLocator());
nWalletDBUpdated++;
+
+ // Restore wallet transaction metadata after -zapwallettxes=1
+ if (GetBoolArg("-zapwallettxes", false) && GetArg("-zapwallettxes", "1") != "2")
+ {
+ BOOST_FOREACH(const CWalletTx& wtxOld, vWtx)
+ {
+ uint256 hash = wtxOld.GetHash();
+ std::map<uint256, CWalletTx>::iterator mi = pwalletMain->mapWallet.find(hash);
+ if (mi != pwalletMain->mapWallet.end())
+ {
+ const CWalletTx* copyFrom = &wtxOld;
+ CWalletTx* copyTo = &mi->second;
+ copyTo->mapValue = copyFrom->mapValue;
+ copyTo->vOrderForm = copyFrom->vOrderForm;
+ copyTo->nTimeReceived = copyFrom->nTimeReceived;
+ copyTo->nTimeSmart = copyFrom->nTimeSmart;
+ copyTo->fFromMe = copyFrom->fFromMe;
+ copyTo->strFromAccount = copyFrom->strFromAccount;
+ copyTo->nOrderPos = copyFrom->nOrderPos;
+ copyTo->WriteToDisk();
+ }
+ }
+ }
}
} // (!fDisableWallet)
#else // ENABLE_WALLET
@@ -1089,9 +1183,8 @@ bool AppInit2(boost::thread_group& threadGroup)
LogPrintf("mapAddressBook.size() = %u\n", pwalletMain ? pwalletMain->mapAddressBook.size() : 0);
#endif
+ InitRespendFilter();
StartNode(threadGroup);
- // InitRPCMining is needed here so getwork/getblocktemplate in the GUI debug console works properly.
- InitRPCMining();
if (fServer)
StartRPCThreads();
diff --git a/src/init.h b/src/init.h
index 2f56923055..626525c9ad 100644
--- a/src/init.h
+++ b/src/init.h
@@ -12,9 +12,8 @@ class CWallet;
namespace boost {
class thread_group;
-};
+} // namespace boost
-extern std::string strWalletFile;
extern CWallet* pwalletMain;
void StartShutdown();
@@ -29,6 +28,9 @@ enum HelpMessageMode
HMM_BITCOIN_QT
};
+/** Help for options shared between UI and daemon (for -help) */
std::string HelpMessage(HelpMessageMode mode);
+/** Returns licensing information (for -version) */
+std::string LicenseInfo();
#endif
diff --git a/src/key.cpp b/src/key.cpp
index 2199996cf3..3c4fa77e72 100644
--- a/src/key.cpp
+++ b/src/key.cpp
@@ -4,14 +4,35 @@
#include "key.h"
+#include "crypto/sha2.h"
+#include <openssl/rand.h>
+
+#ifdef USE_SECP256K1
+#include <secp256k1.h>
+#else
#include <openssl/bn.h>
#include <openssl/ecdsa.h>
#include <openssl/obj_mac.h>
-#include <openssl/rand.h>
+#endif
// anonymous namespace with local implementation code (OpenSSL interaction)
namespace {
+#ifdef USE_SECP256K1
+#include <secp256k1.h>
+class CSecp256k1Init {
+public:
+ CSecp256k1Init() {
+ secp256k1_start();
+ }
+ ~CSecp256k1Init() {
+ secp256k1_stop();
+ }
+};
+static CSecp256k1Init instance_of_csecp256k1;
+
+#else
+
// Generate a private key from just the secret parameter
int EC_KEY_regenerate_key(EC_KEY *eckey, BIGNUM *priv_key)
{
@@ -332,6 +353,8 @@ public:
}
};
+#endif
+
int CompareBigEndian(const unsigned char *c1, size_t c1len, const unsigned char *c2, size_t c2len) {
while (c1len > c2len) {
if (*c1)
@@ -375,8 +398,7 @@ const unsigned char vchMaxModHalfOrder[32] = {
const unsigned char vchZero[0] = {};
-
-}; // end of anonymous namespace
+} // anon namespace
bool CKey::Check(const unsigned char *vch) {
return CompareBigEndian(vch, 32, vchZero, 0) > 0 &&
@@ -397,10 +419,15 @@ void CKey::MakeNewKey(bool fCompressedIn) {
}
bool CKey::SetPrivKey(const CPrivKey &privkey, bool fCompressedIn) {
+#ifdef USE_SECP256K1
+ if (!secp256k1_ecdsa_privkey_import((unsigned char*)begin(), &privkey[0], privkey.size()))
+ return false;
+#else
CECKey key;
if (!key.SetPrivKey(privkey))
return false;
key.GetSecretBytes(vch);
+#endif
fCompressed = fCompressedIn;
fValid = true;
return true;
@@ -408,114 +435,167 @@ bool CKey::SetPrivKey(const CPrivKey &privkey, bool fCompressedIn) {
CPrivKey CKey::GetPrivKey() const {
assert(fValid);
+ CPrivKey privkey;
+#ifdef USE_SECP256K1
+ privkey.resize(279);
+ int privkeylen = 279;
+ int ret = secp256k1_ecdsa_privkey_export(begin(), (unsigned char*)&privkey[0], &privkeylen, fCompressed);
+ assert(ret);
+ privkey.resize(privkeylen);
+#else
CECKey key;
key.SetSecretBytes(vch);
- CPrivKey privkey;
key.GetPrivKey(privkey, fCompressed);
+#endif
return privkey;
}
CPubKey CKey::GetPubKey() const {
assert(fValid);
+ CPubKey pubkey;
+#ifdef USE_SECP256K1
+ int clen = 65;
+ int ret = secp256k1_ecdsa_pubkey_create((unsigned char*)pubkey.begin(), &clen, begin(), fCompressed);
+ assert(ret);
+ assert(pubkey.IsValid());
+ assert((int)pubkey.size() == clen);
+#else
CECKey key;
key.SetSecretBytes(vch);
- CPubKey pubkey;
key.GetPubKey(pubkey, fCompressed);
+#endif
return pubkey;
}
bool CKey::Sign(const uint256 &hash, std::vector<unsigned char>& vchSig) const {
if (!fValid)
return false;
+#ifdef USE_SECP256K1
+ vchSig.resize(72);
+ int nSigLen = 72;
+ CKey nonce;
+ do {
+ nonce.MakeNewKey(true);
+ if (secp256k1_ecdsa_sign((const unsigned char*)&hash, 32, (unsigned char*)&vchSig[0], &nSigLen, begin(), nonce.begin()))
+ break;
+ } while(true);
+ vchSig.resize(nSigLen);
+ return true;
+#else
CECKey key;
key.SetSecretBytes(vch);
return key.Sign(hash, vchSig);
+#endif
}
bool CKey::SignCompact(const uint256 &hash, std::vector<unsigned char>& vchSig) const {
if (!fValid)
return false;
- CECKey key;
- key.SetSecretBytes(vch);
vchSig.resize(65);
int rec = -1;
+#ifdef USE_SECP256K1
+ CKey nonce;
+ do {
+ nonce.MakeNewKey(true);
+ if (secp256k1_ecdsa_sign_compact((const unsigned char*)&hash, 32, &vchSig[1], begin(), nonce.begin(), &rec))
+ break;
+ } while(true);
+#else
+ CECKey key;
+ key.SetSecretBytes(vch);
if (!key.SignCompact(hash, &vchSig[1], rec))
return false;
+#endif
assert(rec != -1);
vchSig[0] = 27 + rec + (fCompressed ? 4 : 0);
return true;
}
bool CKey::Load(CPrivKey &privkey, CPubKey &vchPubKey, bool fSkipCheck=false) {
+#ifdef USE_SECP256K1
+ if (!secp256k1_ecdsa_privkey_import((unsigned char*)begin(), &privkey[0], privkey.size()))
+ return false;
+#else
CECKey key;
if (!key.SetPrivKey(privkey, fSkipCheck))
return false;
-
key.GetSecretBytes(vch);
+#endif
fCompressed = vchPubKey.IsCompressed();
fValid = true;
-
+
if (fSkipCheck)
return true;
-
+
if (GetPubKey() != vchPubKey)
return false;
-
+
return true;
}
bool CPubKey::Verify(const uint256 &hash, const std::vector<unsigned char>& vchSig) const {
if (!IsValid())
return false;
+#ifdef USE_SECP256K1
+ if (secp256k1_ecdsa_verify((const unsigned char*)&hash, 32, &vchSig[0], vchSig.size(), begin(), size()) != 1)
+ return false;
+#else
CECKey key;
if (!key.SetPubKey(*this))
return false;
if (!key.Verify(hash, vchSig))
return false;
+#endif
return true;
}
bool CPubKey::RecoverCompact(const uint256 &hash, const std::vector<unsigned char>& vchSig) {
if (vchSig.size() != 65)
return false;
- CECKey key;
- if (!key.Recover(hash, &vchSig[1], (vchSig[0] - 27) & ~4))
- return false;
- key.GetPubKey(*this, (vchSig[0] - 27) & 4);
- return true;
-}
-
-bool CPubKey::VerifyCompact(const uint256 &hash, const std::vector<unsigned char>& vchSig) const {
- if (!IsValid())
- return false;
- if (vchSig.size() != 65)
+ int recid = (vchSig[0] - 27) & 3;
+ bool fComp = (vchSig[0] - 27) & 4;
+#ifdef USE_SECP256K1
+ int pubkeylen = 65;
+ if (!secp256k1_ecdsa_recover_compact((const unsigned char*)&hash, 32, &vchSig[1], (unsigned char*)begin(), &pubkeylen, fComp, recid))
return false;
+ assert((int)size() == pubkeylen);
+#else
CECKey key;
- if (!key.Recover(hash, &vchSig[1], (vchSig[0] - 27) & ~4))
- return false;
- CPubKey pubkeyRec;
- key.GetPubKey(pubkeyRec, IsCompressed());
- if (*this != pubkeyRec)
+ if (!key.Recover(hash, &vchSig[1], recid))
return false;
+ key.GetPubKey(*this, fComp);
+#endif
return true;
}
bool CPubKey::IsFullyValid() const {
if (!IsValid())
return false;
+#ifdef USE_SECP256K1
+ if (!secp256k1_ecdsa_pubkey_verify(begin(), size()))
+ return false;
+#else
CECKey key;
if (!key.SetPubKey(*this))
return false;
+#endif
return true;
}
bool CPubKey::Decompress() {
if (!IsValid())
return false;
+#ifdef USE_SECP256K1
+ int clen = size();
+ int ret = secp256k1_ecdsa_pubkey_decompress((unsigned char*)begin(), &clen);
+ assert(ret);
+ assert(clen == (int)size());
+#else
CECKey key;
if (!key.SetPubKey(*this))
return false;
key.GetPubKey(*this, false);
+#endif
return true;
}
@@ -525,12 +605,10 @@ void static BIP32Hash(const unsigned char chainCode[32], unsigned int nChild, un
num[1] = (nChild >> 16) & 0xFF;
num[2] = (nChild >> 8) & 0xFF;
num[3] = (nChild >> 0) & 0xFF;
- HMAC_SHA512_CTX ctx;
- HMAC_SHA512_Init(&ctx, chainCode, 32);
- HMAC_SHA512_Update(&ctx, &header, 1);
- HMAC_SHA512_Update(&ctx, data, 32);
- HMAC_SHA512_Update(&ctx, num, 4);
- HMAC_SHA512_Final(output, &ctx);
+ CHMAC_SHA512(chainCode, 32).Write(&header, 1)
+ .Write(data, 32)
+ .Write(num, 4)
+ .Finalize(output);
}
bool CKey::Derive(CKey& keyChild, unsigned char ccChild[32], unsigned int nChild, const unsigned char cc[32]) const {
@@ -547,7 +625,12 @@ bool CKey::Derive(CKey& keyChild, unsigned char ccChild[32], unsigned int nChild
BIP32Hash(cc, nChild, 0, begin(), out);
}
memcpy(ccChild, out+32, 32);
+#ifdef USE_SECP256K1
+ memcpy((unsigned char*)keyChild.begin(), begin(), 32);
+ bool ret = secp256k1_ecdsa_privkey_tweak_add((unsigned char*)keyChild.begin(), out);
+#else
bool ret = CECKey::TweakSecret((unsigned char*)keyChild.begin(), begin(), out);
+#endif
UnlockObject(out);
keyChild.fCompressed = true;
keyChild.fValid = ret;
@@ -561,10 +644,15 @@ bool CPubKey::Derive(CPubKey& pubkeyChild, unsigned char ccChild[32], unsigned i
unsigned char out[64];
BIP32Hash(cc, nChild, *begin(), begin()+1, out);
memcpy(ccChild, out+32, 32);
+#ifdef USE_SECP256K1
+ pubkeyChild = *this;
+ bool ret = secp256k1_ecdsa_pubkey_tweak_add((unsigned char*)pubkeyChild.begin(), pubkeyChild.size(), out);
+#else
CECKey key;
bool ret = key.SetPubKey(*this);
ret &= key.TweakPublic(out);
key.GetPubKey(pubkeyChild, true);
+#endif
return ret;
}
@@ -577,13 +665,10 @@ bool CExtKey::Derive(CExtKey &out, unsigned int nChild) const {
}
void CExtKey::SetMaster(const unsigned char *seed, unsigned int nSeedLen) {
- static const char hashkey[] = {'B','i','t','c','o','i','n',' ','s','e','e','d'};
- HMAC_SHA512_CTX ctx;
- HMAC_SHA512_Init(&ctx, hashkey, sizeof(hashkey));
- HMAC_SHA512_Update(&ctx, seed, nSeedLen);
+ static const unsigned char hashkey[] = {'B','i','t','c','o','i','n',' ','s','e','e','d'};
unsigned char out[64];
LockObject(out);
- HMAC_SHA512_Final(out, &ctx);
+ CHMAC_SHA512(hashkey, sizeof(hashkey)).Write(seed, nSeedLen).Finalize(out);
key.Set(&out[0], &out[32], true);
memcpy(vchChainCode, &out[32], 32);
UnlockObject(out);
@@ -646,3 +731,19 @@ bool CExtPubKey::Derive(CExtPubKey &out, unsigned int nChild) const {
out.nChild = nChild;
return pubkey.Derive(out.pubkey, out.vchChainCode, nChild, vchChainCode);
}
+
+bool ECC_InitSanityCheck() {
+#ifdef USE_SECP256K1
+ return true;
+#else
+ EC_KEY *pkey = EC_KEY_new_by_curve_name(NID_secp256k1);
+ if(pkey == NULL)
+ return false;
+ EC_KEY_free(pkey);
+
+ // TODO Is there more EC functionality that could be missing?
+ return true;
+#endif
+}
+
+
diff --git a/src/key.h b/src/key.h
index 37a06810b4..11dc65de8c 100644
--- a/src/key.h
+++ b/src/key.h
@@ -156,10 +156,6 @@ public:
// If this public key is not fully valid, the return value will be false.
bool Verify(const uint256 &hash, const std::vector<unsigned char>& vchSig) const;
- // Verify a compact signature (~65 bytes).
- // See CKey::SignCompact.
- bool VerifyCompact(const uint256 &hash, const std::vector<unsigned char>& vchSig) const;
-
// Recover a public key from a compact signature.
bool RecoverCompact(const uint256 &hash, const std::vector<unsigned char>& vchSig);
@@ -310,4 +306,7 @@ struct CExtKey {
void SetMaster(const unsigned char *seed, unsigned int nSeedLen);
};
+/** Check that required EC support is available at runtime */
+bool ECC_InitSanityCheck(void);
+
#endif
diff --git a/src/keystore.cpp b/src/keystore.cpp
index 594e0c61da..2a4c88d565 100644
--- a/src/keystore.cpp
+++ b/src/keystore.cpp
@@ -59,3 +59,15 @@ bool CBasicKeyStore::GetCScript(const CScriptID &hash, CScript& redeemScriptOut)
return false;
}
+bool CBasicKeyStore::AddWatchOnly(const CScript &dest)
+{
+ LOCK(cs_KeyStore);
+ setWatchOnly.insert(dest);
+ return true;
+}
+
+bool CBasicKeyStore::HaveWatchOnly(const CScript &dest) const
+{
+ LOCK(cs_KeyStore);
+ return setWatchOnly.count(dest) > 0;
+}
diff --git a/src/keystore.h b/src/keystore.h
index 79d8661aca..72411a1387 100644
--- a/src/keystore.h
+++ b/src/keystore.h
@@ -8,11 +8,21 @@
#include "key.h"
#include "sync.h"
+#include "script.h" // for CNoDestination
#include <boost/signals2/signal.hpp>
+#include <boost/variant.hpp>
class CScript;
+/** A txout script template with a specific destination. It is either:
+ * * CNoDestination: no destination set
+ * * CKeyID: TX_PUBKEYHASH destination
+ * * CScriptID: TX_SCRIPTHASH destination
+ * A CTxDestination is the internal data type encoded in a CBitcoinAddress
+ */
+typedef boost::variant<CNoDestination, CKeyID, CScriptID> CTxDestination;
+
/** A virtual base class for key stores */
class CKeyStore
{
@@ -36,10 +46,15 @@ public:
virtual bool AddCScript(const CScript& redeemScript) =0;
virtual bool HaveCScript(const CScriptID &hash) const =0;
virtual bool GetCScript(const CScriptID &hash, CScript& redeemScriptOut) const =0;
+
+ // Support for Watch-only addresses
+ virtual bool AddWatchOnly(const CScript &dest) =0;
+ virtual bool HaveWatchOnly(const CScript &dest) const =0;
};
typedef std::map<CKeyID, CKey> KeyMap;
typedef std::map<CScriptID, CScript > ScriptMap;
+typedef std::set<CScript> WatchOnlySet;
/** Basic key store, that keeps keys in an address->secret map */
class CBasicKeyStore : public CKeyStore
@@ -47,6 +62,7 @@ class CBasicKeyStore : public CKeyStore
protected:
KeyMap mapKeys;
ScriptMap mapScripts;
+ WatchOnlySet setWatchOnly;
public:
bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey);
@@ -88,6 +104,9 @@ public:
virtual bool AddCScript(const CScript& redeemScript);
virtual bool HaveCScript(const CScriptID &hash) const;
virtual bool GetCScript(const CScriptID &hash, CScript& redeemScriptOut) const;
+
+ virtual bool AddWatchOnly(const CScript &dest);
+ virtual bool HaveWatchOnly(const CScript &dest) const;
};
typedef std::vector<unsigned char, secure_allocator<unsigned char> > CKeyingMaterial;
diff --git a/src/leveldbwrapper.h b/src/leveldbwrapper.h
index 53e9e439bd..043a56bf38 100644
--- a/src/leveldbwrapper.h
+++ b/src/leveldbwrapper.h
@@ -93,7 +93,7 @@ public:
if (!status.ok()) {
if (status.IsNotFound())
return false;
- LogPrintf("LevelDB read failure: %s\n", status.ToString().c_str());
+ LogPrintf("LevelDB read failure: %s\n", status.ToString());
HandleError(status);
}
try {
@@ -122,7 +122,7 @@ public:
if (!status.ok()) {
if (status.IsNotFound())
return false;
- LogPrintf("LevelDB read failure: %s\n", status.ToString().c_str());
+ LogPrintf("LevelDB read failure: %s\n", status.ToString());
HandleError(status);
}
return true;
diff --git a/src/m4/bitcoin_qt.m4 b/src/m4/bitcoin_qt.m4
index e71ecd7172..244b03a5c2 100644
--- a/src/m4/bitcoin_qt.m4
+++ b/src/m4/bitcoin_qt.m4
@@ -100,7 +100,7 @@ AC_DEFUN([BITCOIN_QT_CONFIGURE],[
BITCOIN_QT_PATH_PROGS([LRELEASE], [lrelease-qt${bitcoin_qt_got_major_vers} lrelease${bitcoin_qt_got_major_vers} lrelease], $qt_bin_path)
BITCOIN_QT_PATH_PROGS([LUPDATE], [lupdate-qt${bitcoin_qt_got_major_vers} lupdate${bitcoin_qt_got_major_vers} lupdate],$qt_bin_path, yes)
- MOC_DEFS='-DHAVE_CONFIG_H -I$(top_srcdir)/src'
+ MOC_DEFS='-DHAVE_CONFIG_H -I$(srcdir)'
case $host in
*darwin*)
BITCOIN_QT_CHECK([
diff --git a/src/main.cpp b/src/main.cpp
index a1fe6c07bc..a9c080ffae 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -7,11 +7,13 @@
#include "addrman.h"
#include "alert.h"
+#include "bloom.h"
#include "chainparams.h"
#include "checkpoints.h"
#include "checkqueue.h"
#include "init.h"
#include "net.h"
+#include "pow.h"
#include "txdb.h"
#include "txmempool.h"
#include "ui_interface.h"
@@ -36,11 +38,8 @@ using namespace boost;
CCriticalSection cs_main;
-CTxMemPool mempool;
-
map<uint256, CBlockIndex*> mapBlockIndex;
CChain chainActive;
-CChain chainMostWork;
int64_t nTimeBestReceived = 0;
int nScriptCheckThreads = 0;
bool fImporting = false;
@@ -49,10 +48,10 @@ bool fBenchmark = false;
bool fTxIndex = false;
unsigned int nCoinCacheSize = 5000;
-/** Fees smaller than this (in satoshi) are considered zero fee (for transaction creation) */
-int64_t CTransaction::nMinTxFee = 10000; // Override with -mintxfee
/** Fees smaller than this (in satoshi) are considered zero fee (for relaying and mining) */
-int64_t CTransaction::nMinRelayTxFee = 1000;
+CFeeRate minRelayTxFee = CFeeRate(1000);
+
+CTxMemPool mempool(::minRelayTxFee);
struct COrphanBlock {
uint256 hashBlock;
@@ -72,6 +71,7 @@ const string strMessageMagic = "Bitcoin Signed Message:\n";
// Internal stuff
namespace {
+
struct CBlockIndexWorkComparator
{
bool operator()(CBlockIndex *pa, CBlockIndex *pb) {
@@ -120,8 +120,18 @@ namespace {
};
map<uint256, pair<NodeId, list<QueuedBlock>::iterator> > mapBlocksInFlight;
map<uint256, pair<NodeId, list<uint256>::iterator> > mapBlocksToDownload;
+
+} // anon namespace
+
+// Bloom filter to limit respend relays to one
+static const unsigned int MAX_DOUBLESPEND_BLOOM = 1000;
+static CBloomFilter doubleSpendFilter;
+void InitRespendFilter() {
+ seed_insecure_rand();
+ doubleSpendFilter = CBloomFilter(MAX_DOUBLESPEND_BLOOM, 0.01, insecure_rand(), BLOOM_UPDATE_NONE);
}
+
//////////////////////////////////////////////////////////////////////////////
//
// dispatching functions
@@ -130,9 +140,10 @@ namespace {
// These functions dispatch to one or all registered wallets
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 updated transaction data (transaction, and optionally the block it is found in.
+ boost::signals2::signal<void (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).
@@ -144,10 +155,12 @@ struct CMainSignals {
// Tells listeners to broadcast their data.
boost::signals2::signal<void ()> Broadcast;
} g_signals;
-}
+
+} // anon namespace
+
void RegisterWallet(CWalletInterface* pwalletIn) {
- g_signals.SyncTransaction.connect(boost::bind(&CWalletInterface::SyncTransaction, pwalletIn, _1, _2, _3));
+ g_signals.SyncTransaction.connect(boost::bind(&CWalletInterface::SyncTransaction, pwalletIn, _1, _2));
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));
@@ -161,7 +174,7 @@ void UnregisterWallet(CWalletInterface* pwalletIn) {
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));
+ g_signals.SyncTransaction.disconnect(boost::bind(&CWalletInterface::SyncTransaction, pwalletIn, _1, _2));
}
void UnregisterAllWallets() {
@@ -173,8 +186,8 @@ void UnregisterAllWallets() {
g_signals.SyncTransaction.disconnect_all_slots();
}
-void SyncWithWallets(const uint256 &hash, const CTransaction &tx, const CBlock *pblock) {
- g_signals.SyncTransaction(hash, tx, pblock);
+void SyncWithWallets(const CTransaction &tx, const CBlock *pblock) {
+ g_signals.SyncTransaction(tx, pblock);
}
//////////////////////////////////////////////////////////////////////////////
@@ -203,6 +216,10 @@ struct CNodeState {
std::string name;
// List of asynchronously-determined block rejections to notify this peer about.
std::vector<CBlockReject> rejects;
+ // The best known block we know this peer has announced.
+ CBlockIndex *pindexBestKnownBlock;
+ // The hash of the last unknown block this peer has announced.
+ uint256 hashLastUnknownBlock;
list<QueuedBlock> vBlocksInFlight;
int nBlocksInFlight;
list<uint256> vBlocksToDownload;
@@ -213,6 +230,8 @@ struct CNodeState {
CNodeState() {
nMisbehavior = 0;
fShouldBan = false;
+ pindexBestKnownBlock = NULL;
+ hashLastUnknownBlock = uint256(0);
nBlocksToDownload = 0;
nBlocksInFlight = 0;
nLastBlockReceive = 0;
@@ -274,7 +293,6 @@ void MarkBlockAsReceived(const uint256 &hash, NodeId nodeFrom = -1) {
state->nLastBlockReceive = GetTimeMicros();
mapBlocksInFlight.erase(itInFlight);
}
-
}
// Requires cs_main.
@@ -310,14 +328,48 @@ void MarkBlockAsInFlight(NodeId nodeid, const uint256 &hash) {
mapBlocksInFlight[hash] = std::make_pair(nodeid, it);
}
+/** Check whether the last unknown block a peer advertized is not yet known. */
+void ProcessBlockAvailability(NodeId nodeid) {
+ CNodeState *state = State(nodeid);
+ assert(state != NULL);
+
+ if (state->hashLastUnknownBlock != 0) {
+ map<uint256, CBlockIndex*>::iterator itOld = mapBlockIndex.find(state->hashLastUnknownBlock);
+ if (itOld != mapBlockIndex.end() && itOld->second->nChainWork > 0) {
+ if (state->pindexBestKnownBlock == NULL || itOld->second->nChainWork >= state->pindexBestKnownBlock->nChainWork)
+ state->pindexBestKnownBlock = itOld->second;
+ state->hashLastUnknownBlock = uint256(0);
+ }
+ }
+}
+
+/** Update tracking information about which blocks a peer is assumed to have. */
+void UpdateBlockAvailability(NodeId nodeid, const uint256 &hash) {
+ CNodeState *state = State(nodeid);
+ assert(state != NULL);
+
+ ProcessBlockAvailability(nodeid);
+
+ map<uint256, CBlockIndex*>::iterator it = mapBlockIndex.find(hash);
+ if (it != mapBlockIndex.end() && it->second->nChainWork > 0) {
+ // An actually better block was announced.
+ if (state->pindexBestKnownBlock == NULL || it->second->nChainWork >= state->pindexBestKnownBlock->nChainWork)
+ state->pindexBestKnownBlock = it->second;
+ } else {
+ // An unknown block was announced; just assume that the latest one is the best one.
+ state->hashLastUnknownBlock = hash;
+ }
}
+} // anon namespace
+
bool GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats) {
LOCK(cs_main);
CNodeState *state = State(nodeid);
if (state == NULL)
return false;
stats.nMisbehavior = state->nMisbehavior;
+ stats.nSyncHeight = state->pindexBestKnownBlock ? state->pindexBestKnownBlock->nHeight : -1;
return true;
}
@@ -371,12 +423,13 @@ CBlockLocator CChain::GetLocator(const CBlockIndex *pindex) const {
break;
// Exponentially larger steps back, plus the genesis block.
int nHeight = std::max(pindex->nHeight - nStep, 0);
- // In case pindex is not in this chain, iterate pindex->pprev to find blocks.
- while (pindex->nHeight > nHeight && !Contains(pindex))
- pindex = pindex->pprev;
- // If pindex is in this chain, use direct height-based access.
- if (pindex->nHeight > nHeight)
+ if (Contains(pindex)) {
+ // Use O(1) CChain index if possible.
pindex = (*this)[nHeight];
+ } else {
+ // Otherwise, use O(log n) skiplist.
+ pindex = pindex->GetAncestor(nHeight);
+ }
if (vHave.size() > 10)
nStep *= 2;
}
@@ -398,6 +451,14 @@ CBlockIndex *CChain::FindFork(const CBlockLocator &locator) const {
return Genesis();
}
+CBlockIndex *CChain::FindFork(CBlockIndex *pindex) const {
+ if (pindex->nHeight > Height())
+ pindex = pindex->GetAncestor(Height());
+ while (pindex && !Contains(pindex))
+ pindex = pindex->pprev;
+ return pindex;
+}
+
CCoinsViewCache *pcoinsTip = NULL;
CBlockTreeDB *pblocktree = NULL;
@@ -482,7 +543,7 @@ bool IsStandardTx(const CTransaction& tx, string& reason)
// Treat non-final transactions as non-standard to prevent a specific type
// of double-spend attack, as well as DoS attacks. (if the transaction
// can't be mined, the attacker isn't expending resources broadcasting it)
- // Basically we don't want to propagate transactions that can't included in
+ // Basically we don't want to propagate transactions that can't be included in
// the next block.
//
// However, IsFinalTx() is confusing... Without arguments, it uses
@@ -515,7 +576,7 @@ bool IsStandardTx(const CTransaction& tx, string& reason)
{
// Biggest 'standard' txin is a 15-of-15 P2SH multisig with compressed
// keys. (remember the 520 byte limit on redeemScript size) That works
- // out to a (15*(33+1))+3=513 byte redeemScript, 513+1+15*(73+1)=1624
+ // out to a (15*(33+1))+3=513 byte redeemScript, 513+1+15*(73+1)+3=1627
// bytes of scriptSig, which we round off to 1650 bytes for some minor
// future-proofing. That's also enough to spend a 20-of-20
// CHECKMULTISIG scriptPubKey, though such a scriptPubKey is not
@@ -543,7 +604,7 @@ bool IsStandardTx(const CTransaction& tx, string& reason)
}
if (whichType == TX_NULL_DATA)
nDataOut++;
- else if (txout.IsDust(CTransaction::nMinRelayTxFee)) {
+ else if (txout.IsDust(::minRelayTxFee)) {
reason = "dust";
return false;
}
@@ -577,15 +638,13 @@ bool IsFinalTx(const CTransaction &tx, int nBlockHeight, int64_t nBlockTime)
}
//
-// Check transaction inputs, and make sure any
-// pay-to-script-hash transactions are evaluating IsStandard scripts
+// Check transaction inputs to mitigate two
+// potential denial-of-service attacks:
//
-// Why bother? To avoid denial-of-service attacks; an attacker
-// can submit a standard HASH... OP_EQUAL transaction,
-// which will get accepted into blocks. The redemption
-// script can be anything; an attacker could use a very
-// expensive-to-check-upon-redemption script like:
-// DUP CHECKSIG DROP ... repeated 100 times... OP_1
+// 1. scriptSigs with extra data stuffed into them,
+// not consumed by scriptPubKey (or P2SH script)
+// 2. P2SH scripts with a crazy number of expensive
+// CHECKSIG/CHECKMULTISIG operations
//
bool AreInputsStandard(const CTransaction& tx, CCoinsViewCache& mapInputs)
{
@@ -609,8 +668,9 @@ bool AreInputsStandard(const CTransaction& tx, CCoinsViewCache& mapInputs)
// Transactions with extra stuff in their scriptSigs are
// non-standard. Note that this EvalScript() call will
// be quick, because if there are any operations
- // beside "push data" in the scriptSig the
- // IsStandard() call returns false
+ // beside "push data" in the scriptSig
+ // IsStandard() will have already returned false
+ // and this method isn't called.
vector<vector<unsigned char> > stack;
if (!EvalScript(stack, tx.vin[i].scriptSig, tx, i, false, 0))
return false;
@@ -622,16 +682,20 @@ bool AreInputsStandard(const CTransaction& tx, CCoinsViewCache& mapInputs)
CScript subscript(stack.back().begin(), stack.back().end());
vector<vector<unsigned char> > vSolutions2;
txnouttype whichType2;
- if (!Solver(subscript, whichType2, vSolutions2))
- return false;
- if (whichType2 == TX_SCRIPTHASH)
- return false;
-
- int tmpExpected;
- tmpExpected = ScriptSigArgsExpected(whichType2, vSolutions2);
- if (tmpExpected < 0)
- return false;
- nArgsExpected += tmpExpected;
+ if (Solver(subscript, whichType2, vSolutions2))
+ {
+ int tmpExpected = ScriptSigArgsExpected(whichType2, vSolutions2);
+ if (tmpExpected < 0)
+ return false;
+ nArgsExpected += tmpExpected;
+ }
+ else
+ {
+ // Any other Script with less than 15 sigops OK:
+ unsigned int sigops = subscript.GetSigOpCount(true);
+ // ... extra data left on the stack after execution is OK, too:
+ return (sigops <= MAX_P2SH_SIGOPS);
+ }
}
if (stack.size() != (unsigned int)nArgsExpected)
@@ -781,12 +845,19 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state)
return true;
}
-int64_t GetMinFee(const CTransaction& tx, unsigned int nBytes, bool fAllowFree, enum GetMinFee_mode mode)
+int64_t GetMinRelayFee(const CTransaction& tx, unsigned int nBytes, bool fAllowFree)
{
- // Base fee is either nMinTxFee or nMinRelayTxFee
- int64_t nBaseFee = (mode == GMF_RELAY) ? tx.nMinRelayTxFee : tx.nMinTxFee;
+ {
+ LOCK(mempool.cs);
+ uint256 hash = tx.GetHash();
+ double dPriorityDelta = 0;
+ int64_t nFeeDelta = 0;
+ mempool.ApplyDeltas(hash, dPriorityDelta, nFeeDelta);
+ if (dPriorityDelta > 0 || nFeeDelta > 0)
+ return 0;
+ }
- int64_t nMinFee = (1 + (int64_t)nBytes / 1000) * nBaseFee;
+ int64_t nMinFee = ::minRelayTxFee.GetFee(nBytes);
if (fAllowFree)
{
@@ -794,27 +865,69 @@ int64_t GetMinFee(const CTransaction& tx, unsigned int nBytes, bool fAllowFree,
// * If we are relaying we allow transactions up to DEFAULT_BLOCK_PRIORITY_SIZE - 1000
// to be considered to fall into this category. We don't want to encourage sending
// multiple transactions instead of one big transaction to avoid fees.
- // * If we are creating a transaction we allow transactions up to 1,000 bytes
- // to be considered safe and assume they can likely make it into this section.
- if (nBytes < (mode == GMF_SEND ? 1000 : (DEFAULT_BLOCK_PRIORITY_SIZE - 1000)))
+ if (nBytes < (DEFAULT_BLOCK_PRIORITY_SIZE - 1000))
nMinFee = 0;
}
- // This code can be removed after enough miners have upgraded to version 0.9.
- // Until then, be safe when sending and require a fee if any output
- // is less than CENT:
- if (nMinFee < nBaseFee && mode == GMF_SEND)
- {
- BOOST_FOREACH(const CTxOut& txout, tx.vout)
- if (txout.nValue < CENT)
- nMinFee = nBaseFee;
- }
-
if (!MoneyRange(nMinFee))
nMinFee = MAX_MONEY;
return nMinFee;
}
+// Exponentially limit the rate of nSize flow to nLimit. nLimit unit is thousands-per-minute.
+bool RateLimitExceeded(double& dCount, int64_t& nLastTime, int64_t nLimit, unsigned int nSize)
+{
+ static CCriticalSection csLimiter;
+ int64_t nNow = GetTime();
+
+ LOCK(csLimiter);
+
+ dCount *= pow(1.0 - 1.0/600.0, (double)(nNow - nLastTime));
+ nLastTime = nNow;
+ if (dCount >= nLimit*10*1000)
+ return true;
+ dCount += nSize;
+ return false;
+}
+
+static bool RelayableRespend(const COutPoint& outPoint, const CTransaction& doubleSpend, bool fInBlock, CBloomFilter& filter)
+{
+ // Relaying double-spend attempts to our peers lets them detect when
+ // somebody might be trying to cheat them. However, blindly relaying
+ // every double-spend across the entire network gives attackers
+ // a denial-of-service attack: just generate a stream of double-spends
+ // re-spending the same (limited) set of outpoints owned by the attacker.
+ // So, we use a bloom filter and only relay (at most) the first double
+ // spend for each outpoint. False-positives ("we have already relayed")
+ // are OK, because if the peer doesn't hear about the double-spend
+ // from us they are very likely to hear about it from another peer, since
+ // each peer uses a different, randomized bloom filter.
+
+ if (fInBlock || filter.contains(outPoint)) return false;
+
+ // Apply an independent rate limit to double-spend relays
+ static double dRespendCount;
+ static int64_t nLastRespendTime;
+ static int64_t nRespendLimit = GetArg("-limitrespendrelay", 100);
+ unsigned int nSize = ::GetSerializeSize(doubleSpend, SER_NETWORK, PROTOCOL_VERSION);
+
+ if (RateLimitExceeded(dRespendCount, nLastRespendTime, nRespendLimit, nSize))
+ {
+ LogPrint("mempool", "Double-spend relay rejected by rate limiter\n");
+ return false;
+ }
+
+ LogPrint("mempool", "Rate limit dRespendCount: %g => %g\n", dRespendCount, dRespendCount+nSize);
+
+ // Clear the filter on average every MAX_DOUBLE_SPEND_BLOOM
+ // insertions
+ if (insecure_rand()%MAX_DOUBLESPEND_BLOOM == 0)
+ filter.clear();
+
+ filter.insert(outPoint);
+
+ return true;
+}
bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree,
bool* pfMissingInputs, bool fRejectInsaneFee)
@@ -833,7 +946,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
// Rather not work on nonstandard transactions (unless -testnet/-regtest)
string reason;
- if (Params().NetworkID() == CChainParams::MAIN && !IsStandardTx(tx, reason))
+ if (Params().RequireStandard() && !IsStandardTx(tx, reason))
return state.DoS(0,
error("AcceptToMemoryPool : nonstandard transaction: %s", reason),
REJECT_NONSTANDARD, reason);
@@ -844,15 +957,18 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
return false;
// Check for conflicts with in-memory transactions
+ bool relayableRespend = false;
{
LOCK(pool.cs); // protect pool.mapNextTx
for (unsigned int i = 0; i < tx.vin.size(); i++)
{
COutPoint outpoint = tx.vin[i].prevout;
- if (pool.mapNextTx.count(outpoint))
+ // Does tx conflict with a member of the pool, and is it not equivalent to that member?
+ if (pool.mapNextTx.count(outpoint) && !tx.IsEquivalentTo(*pool.mapNextTx[outpoint].ptx))
{
- // Disable replacement feature for now
- return false;
+ relayableRespend = RelayableRespend(outpoint, tx, false, doubleSpendFilter);
+ if (!relayableRespend)
+ return false;
}
}
}
@@ -861,6 +977,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
CCoinsView dummy;
CCoinsViewCache view(dummy);
+ int64_t nValueIn = 0;
{
LOCK(pool.cs);
CCoinsViewMemPool viewMemPool(*pcoinsTip, pool);
@@ -889,19 +1006,20 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
// Bring the best block into scope
view.GetBestBlock();
+ nValueIn = view.GetValueIn(tx);
+
// we have all inputs cached now, so switch back to dummy, so we don't need to keep lock on mempool
view.SetBackend(dummy);
}
// Check for non-standard pay-to-script-hash in inputs
- if (Params().NetworkID() == CChainParams::MAIN && !AreInputsStandard(tx, view))
+ if (Params().RequireStandard() && !AreInputsStandard(tx, view))
return error("AcceptToMemoryPool: : nonstandard transaction input");
// Note: if you modify this code to accept non-standard transactions, then
// you should add code here to check that the transaction does a
// reasonable number of ECDSA signature verifications.
- int64_t nValueIn = view.GetValueIn(tx);
int64_t nValueOut = tx.GetValueOut();
int64_t nFees = nValueIn-nValueOut;
double dPriority = view.GetPriority(tx, chainActive.Height());
@@ -910,40 +1028,32 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
unsigned int nSize = entry.GetTxSize();
// Don't accept it if it can't get into a block
- int64_t txMinFee = GetMinFee(tx, nSize, true, GMF_RELAY);
+ int64_t txMinFee = GetMinRelayFee(tx, nSize, true);
if (fLimitFree && nFees < txMinFee)
return state.DoS(0, error("AcceptToMemoryPool : not enough fees %s, %d < %d",
hash.ToString(), nFees, txMinFee),
REJECT_INSUFFICIENTFEE, "insufficient fee");
- // Continuously rate-limit free transactions
+ // Continuously rate-limit free (really, very-low-fee)transactions
// This mitigates 'penny-flooding' -- sending thousands of free transactions just to
// be annoying or make others' transactions take longer to confirm.
- if (fLimitFree && nFees < CTransaction::nMinRelayTxFee)
+ if (fLimitFree && nFees < ::minRelayTxFee.GetFee(nSize))
{
- static CCriticalSection csFreeLimiter;
static double dFreeCount;
- static int64_t nLastTime;
- int64_t nNow = GetTime();
-
- LOCK(csFreeLimiter);
+ static int64_t nLastFreeTime;
+ static int64_t nFreeLimit = GetArg("-limitfreerelay", 15);
- // Use an exponentially decaying ~10-minute window:
- dFreeCount *= pow(1.0 - 1.0/600.0, (double)(nNow - nLastTime));
- nLastTime = nNow;
- // -limitfreerelay unit is thousand-bytes-per-minute
- // At default rate it would take over a month to fill 1GB
- if (dFreeCount >= GetArg("-limitfreerelay", 15)*10*1000)
+ if (RateLimitExceeded(dFreeCount, nLastFreeTime, nFreeLimit, nSize))
return state.DoS(0, error("AcceptToMemoryPool : free transaction rejected by rate limiter"),
REJECT_INSUFFICIENTFEE, "insufficient priority");
+
LogPrint("mempool", "Rate limit dFreeCount: %g => %g\n", dFreeCount, dFreeCount+nSize);
- dFreeCount += nSize;
}
- if (fRejectInsaneFee && nFees > CTransaction::nMinRelayTxFee * 10000)
+ if (fRejectInsaneFee && nFees > ::minRelayTxFee.GetFee(nSize) * 10000)
return error("AcceptToMemoryPool: : insane fees %s, %d > %d",
hash.ToString(),
- nFees, CTransaction::nMinRelayTxFee * 10000);
+ nFees, ::minRelayTxFee.GetFee(nSize) * 10000);
// Check against previous transactions
// This is done last to help prevent CPU exhaustion denial-of-service attacks.
@@ -951,13 +1061,21 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
{
return error("AcceptToMemoryPool: : ConnectInputs failed %s", hash.ToString());
}
- // Store transaction in memory
- pool.addUnchecked(hash, entry);
+
+ if (relayableRespend)
+ {
+ RelayTransaction(tx);
+ }
+ else
+ {
+ // Store transaction in memory
+ pool.addUnchecked(hash, entry);
+ }
}
- g_signals.SyncTransaction(hash, tx, NULL);
+ g_signals.SyncTransaction(tx, NULL);
- return true;
+ return !relayableRespend;
}
@@ -1005,10 +1123,10 @@ int CMerkleTx::GetBlocksToMaturity() const
}
-bool CMerkleTx::AcceptToMemoryPool(bool fLimitFree)
+bool CMerkleTx::AcceptToMemoryPool(bool fLimitFree, bool fRejectInsaneFee)
{
CValidationState state;
- return ::AcceptToMemoryPool(mempool, state, *this, fLimitFree, NULL);
+ return ::AcceptToMemoryPool(mempool, state, *this, fLimitFree, NULL, fRejectInsaneFee);
}
@@ -1160,7 +1278,7 @@ uint256 static GetOrphanRoot(const uint256& hash)
// Remove a random orphan block (which does not have any dependent orphans).
void static PruneOrphanBlocks()
{
- if (mapOrphanBlocksByPrev.size() <= MAX_ORPHAN_BLOCKS)
+ if (mapOrphanBlocksByPrev.size() <= (size_t)std::max((int64_t)0, GetArg("-maxorphanblocks", DEFAULT_MAX_ORPHAN_BLOCKS)))
return;
// Pick a random orphan block.
@@ -1197,118 +1315,6 @@ int64_t GetBlockValue(int nHeight, int64_t nFees)
return nSubsidy + nFees;
}
-static const int64_t nTargetTimespan = 14 * 24 * 60 * 60; // two weeks
-static const int64_t nTargetSpacing = 10 * 60;
-static const int64_t nInterval = nTargetTimespan / nTargetSpacing;
-
-//
-// minimum amount of work that could possibly be required nTime after
-// minimum work required was nBase
-//
-unsigned int ComputeMinWork(unsigned int nBase, int64_t nTime)
-{
- const uint256 &bnLimit = Params().ProofOfWorkLimit();
- // Testnet has min-difficulty blocks
- // after nTargetSpacing*2 time between blocks:
- if (TestNet() && nTime > nTargetSpacing*2)
- return bnLimit.GetCompact();
-
- uint256 bnResult;
- bnResult.SetCompact(nBase);
- while (nTime > 0 && bnResult < bnLimit)
- {
- // Maximum 400% adjustment...
- bnResult *= 4;
- // ... in best-case exactly 4-times-normal target time
- nTime -= nTargetTimespan*4;
- }
- if (bnResult > bnLimit)
- bnResult = bnLimit;
- return bnResult.GetCompact();
-}
-
-unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock)
-{
- unsigned int nProofOfWorkLimit = Params().ProofOfWorkLimit().GetCompact();
-
- // Genesis block
- if (pindexLast == NULL)
- return nProofOfWorkLimit;
-
- // Only change once per interval
- if ((pindexLast->nHeight+1) % nInterval != 0)
- {
- if (TestNet())
- {
- // Special difficulty rule for testnet:
- // If the new block's timestamp is more than 2* 10 minutes
- // then allow mining of a min-difficulty block.
- if (pblock->nTime > pindexLast->nTime + nTargetSpacing*2)
- return nProofOfWorkLimit;
- else
- {
- // Return the last non-special-min-difficulty-rules-block
- const CBlockIndex* pindex = pindexLast;
- while (pindex->pprev && pindex->nHeight % nInterval != 0 && pindex->nBits == nProofOfWorkLimit)
- pindex = pindex->pprev;
- return pindex->nBits;
- }
- }
- return pindexLast->nBits;
- }
-
- // Go back by what we want to be 14 days worth of blocks
- const CBlockIndex* pindexFirst = pindexLast;
- for (int i = 0; pindexFirst && i < nInterval-1; i++)
- pindexFirst = pindexFirst->pprev;
- assert(pindexFirst);
-
- // Limit adjustment step
- int64_t nActualTimespan = pindexLast->GetBlockTime() - pindexFirst->GetBlockTime();
- LogPrintf(" nActualTimespan = %d before bounds\n", nActualTimespan);
- if (nActualTimespan < nTargetTimespan/4)
- nActualTimespan = nTargetTimespan/4;
- if (nActualTimespan > nTargetTimespan*4)
- nActualTimespan = nTargetTimespan*4;
-
- // Retarget
- uint256 bnNew;
- uint256 bnOld;
- bnNew.SetCompact(pindexLast->nBits);
- bnOld = bnNew;
- bnNew *= nActualTimespan;
- bnNew /= nTargetTimespan;
-
- if (bnNew > Params().ProofOfWorkLimit())
- bnNew = Params().ProofOfWorkLimit();
-
- /// debug print
- LogPrintf("GetNextWorkRequired RETARGET\n");
- LogPrintf("nTargetTimespan = %d nActualTimespan = %d\n", nTargetTimespan, nActualTimespan);
- LogPrintf("Before: %08x %s\n", pindexLast->nBits, bnOld.ToString());
- LogPrintf("After: %08x %s\n", bnNew.GetCompact(), bnNew.ToString());
-
- return bnNew.GetCompact();
-}
-
-bool CheckProofOfWork(uint256 hash, unsigned int nBits)
-{
- bool fNegative;
- bool fOverflow;
- uint256 bnTarget;
- bnTarget.SetCompact(nBits, &fNegative, &fOverflow);
-
- // Check range
- if (fNegative || bnTarget == 0 || fOverflow || bnTarget > Params().ProofOfWorkLimit())
- return error("CheckProofOfWork() : nBits below minimum work");
-
- // Check proof of work matches claimed amount
- if (hash > bnTarget)
- return error("CheckProofOfWork() : hash doesn't match nBits");
-
- return true;
-}
-
bool IsInitialBlockDownload()
{
LOCK(cs_main);
@@ -1468,7 +1474,7 @@ void UpdateTime(CBlockHeader& block, const CBlockIndex* pindexPrev)
block.nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
// Updating time can change work required on testnet:
- if (TestNet())
+ if (Params().AllowMinDifficultyBlocks())
block.nBits = GetNextWorkRequired(pindexPrev, &block);
}
@@ -1482,7 +1488,7 @@ void UpdateTime(CBlockHeader& block, const CBlockIndex* pindexPrev)
-void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCache &inputs, CTxUndo &txundo, int nHeight, const uint256 &txhash)
+void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCache &inputs, CTxUndo &txundo, int nHeight)
{
bool ret;
// mark inputs spent
@@ -1497,7 +1503,7 @@ void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCach
}
// add outputs
- ret = inputs.SetCoins(txhash, CCoins(tx, nHeight));
+ ret = inputs.SetCoins(tx.GetHash(), CCoins(tx, nHeight));
assert(ret);
}
@@ -1770,8 +1776,8 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C
!((pindex->nHeight==91842 && pindex->GetBlockHash() == uint256("0x00000000000a4d0a398161ffc163c503763b1f4360639393e0e4c8e300e0caec")) ||
(pindex->nHeight==91880 && pindex->GetBlockHash() == uint256("0x00000000000743f190a18c5577a3c2d2a1f610ae9601ac046a38084ccb7cd721")));
if (fEnforceBIP30) {
- for (unsigned int i = 0; i < block.vtx.size(); i++) {
- uint256 hash = block.GetTxHash(i);
+ BOOST_FOREACH(const CTransaction& tx, block.vtx) {
+ const uint256& hash = tx.GetHash();
if (view.HaveCoins(hash) && !view.GetCoins(hash).IsPruned())
return state.DoS(100, error("ConnectBlock() : tried to overwrite transaction"),
REJECT_INVALID, "bad-txns-BIP30");
@@ -1780,7 +1786,7 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C
// BIP16 didn't become active until Apr 1 2012
int64_t nBIP16SwitchTime = 1333238400;
- bool fStrictPayToScriptHash = (pindex->nTime >= nBIP16SwitchTime);
+ bool fStrictPayToScriptHash = (pindex->GetBlockTime() >= nBIP16SwitchTime);
unsigned int flags = SCRIPT_VERIFY_NOCACHE |
(fStrictPayToScriptHash ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE);
@@ -1832,11 +1838,11 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C
}
CTxUndo txundo;
- UpdateCoins(tx, state, view, txundo, pindex->nHeight, block.GetTxHash(i));
+ UpdateCoins(tx, state, view, txundo, pindex->nHeight);
if (!tx.IsCoinBase())
blockundo.vtxundo.push_back(txundo);
- vPos.push_back(std::make_pair(block.GetTxHash(i), pos));
+ vPos.push_back(std::make_pair(tx.GetHash(), pos));
pos.nTxOffset += ::GetSerializeSize(tx, SER_DISK, CLIENT_VERSION);
}
int64_t nTime = GetTimeMicros() - nStart;
@@ -1895,8 +1901,13 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C
assert(ret);
// Watch for transactions paying to me
- for (unsigned int i = 0; i < block.vtx.size(); i++)
- g_signals.SyncTransaction(block.GetTxHash(i), block.vtx[i], &block);
+ BOOST_FOREACH(const CTransaction& tx, block.vtx)
+ g_signals.SyncTransaction(tx, &block);
+
+ // Watch for changes to the previous coinbase transaction.
+ static uint256 hashPrevBestCoinBase;
+ g_signals.UpdatedTransaction(hashPrevBestCoinBase);
+ hashPrevBestCoinBase = block.vtx[0].GetHash();
return true;
}
@@ -1983,7 +1994,7 @@ bool static DisconnectTip(CValidationState &state) {
BOOST_FOREACH(const CTransaction &tx, block.vtx) {
// ignore validation errors in resurrected transactions
list<CTransaction> removed;
- CValidationState stateDummy;
+ CValidationState stateDummy;
if (!tx.IsCoinBase())
if (!AcceptToMemoryPool(mempool, stateDummy, tx, false, NULL))
mempool.remove(tx, removed, true);
@@ -1994,7 +2005,7 @@ bool static DisconnectTip(CValidationState &state) {
// Let wallets know transactions went from 1-confirmed to
// 0-confirmed or conflicted:
BOOST_FOREACH(const CTransaction &tx, block.vtx) {
- SyncWithWallets(tx.GetHash(), tx, NULL);
+ SyncWithWallets(tx, NULL);
}
return true;
}
@@ -2027,43 +2038,33 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew) {
return false;
// Remove conflicting transactions from the mempool.
list<CTransaction> txConflicted;
- BOOST_FOREACH(const CTransaction &tx, block.vtx) {
- list<CTransaction> unused;
- mempool.remove(tx, unused);
- mempool.removeConflicts(tx, txConflicted);
- }
+ mempool.removeForBlock(block.vtx, pindexNew->nHeight, txConflicted);
mempool.check(pcoinsTip);
// Update chainActive & related variables.
UpdateTip(pindexNew);
// Tell wallet about transactions that went from mempool
// to conflicted:
BOOST_FOREACH(const CTransaction &tx, txConflicted) {
- SyncWithWallets(tx.GetHash(), tx, NULL);
+ SyncWithWallets(tx, NULL);
}
// ... and about transactions that got confirmed:
BOOST_FOREACH(const CTransaction &tx, block.vtx) {
- SyncWithWallets(tx.GetHash(), tx, &block);
+ SyncWithWallets(tx, &block);
}
return true;
}
-// Make chainMostWork correspond to the chain with the most work in it, that isn't
+// Return the tip of the chain with the most work in it, that isn't
// known to be invalid (it's however far from certain to be valid).
-void static FindMostWorkChain() {
- CBlockIndex *pindexNew = NULL;
-
- // In case the current best is invalid, do not consider it.
- while (chainMostWork.Tip() && (chainMostWork.Tip()->nStatus & BLOCK_FAILED_MASK)) {
- setBlockIndexValid.erase(chainMostWork.Tip());
- chainMostWork.SetTip(chainMostWork.Tip()->pprev);
- }
-
+static CBlockIndex* FindMostWorkChain() {
do {
+ CBlockIndex *pindexNew = NULL;
+
// Find the best candidate header.
{
std::set<CBlockIndex*, CBlockIndexWorkComparator>::reverse_iterator it = setBlockIndexValid.rbegin();
if (it == setBlockIndexValid.rend())
- return;
+ return NULL;
pindexNew = *it;
}
@@ -2087,70 +2088,111 @@ void static FindMostWorkChain() {
}
pindexTest = pindexTest->pprev;
}
- if (fInvalidAncestor)
- continue;
-
- break;
+ if (!fInvalidAncestor)
+ return pindexNew;
} while(true);
-
- // Check whether it's actually an improvement.
- if (chainMostWork.Tip() && !CBlockIndexWorkComparator()(chainMostWork.Tip(), pindexNew))
- return;
-
- // We have a new best.
- chainMostWork.SetTip(pindexNew);
}
-// Try to activate to the most-work chain (thereby connecting it).
-bool ActivateBestChain(CValidationState &state) {
- LOCK(cs_main);
+// Try to make some progress towards making pindexMostWork the active block.
+static bool ActivateBestChainStep(CValidationState &state, CBlockIndex *pindexMostWork) {
+ AssertLockHeld(cs_main);
+ bool fInvalidFound = false;
CBlockIndex *pindexOldTip = chainActive.Tip();
- bool fComplete = false;
- while (!fComplete) {
- FindMostWorkChain();
- fComplete = true;
+ CBlockIndex *pindexFork = chainActive.FindFork(pindexMostWork);
- // Check whether we have something to do.
- if (chainMostWork.Tip() == NULL) break;
+ // Disconnect active blocks which are no longer in the best chain.
+ while (chainActive.Tip() && chainActive.Tip() != pindexFork) {
+ if (!DisconnectTip(state))
+ return false;
+ }
- // Disconnect active blocks which are no longer in the best chain.
- while (chainActive.Tip() && !chainMostWork.Contains(chainActive.Tip())) {
- if (!DisconnectTip(state))
- return false;
- }
+ // Build list of new blocks to connect.
+ std::vector<CBlockIndex*> vpindexToConnect;
+ vpindexToConnect.reserve(pindexMostWork->nHeight - (pindexFork ? pindexFork->nHeight : -1));
+ while (pindexMostWork && pindexMostWork != pindexFork) {
+ vpindexToConnect.push_back(pindexMostWork);
+ pindexMostWork = pindexMostWork->pprev;
+ }
- // Connect new blocks.
- while (!chainActive.Contains(chainMostWork.Tip())) {
- CBlockIndex *pindexConnect = chainMostWork[chainActive.Height() + 1];
- if (!ConnectTip(state, pindexConnect)) {
- if (state.IsInvalid()) {
- // The block violates a consensus rule.
- if (!state.CorruptionPossible())
- InvalidChainFound(chainMostWork.Tip());
- fComplete = false;
- state = CValidationState();
- break;
- } else {
- // A system error occurred (disk space, database error, ...).
- return false;
- }
+ // Connect new blocks.
+ BOOST_REVERSE_FOREACH(CBlockIndex *pindexConnect, vpindexToConnect) {
+ if (!ConnectTip(state, pindexConnect)) {
+ if (state.IsInvalid()) {
+ // The block violates a consensus rule.
+ if (!state.CorruptionPossible())
+ InvalidChainFound(vpindexToConnect.back());
+ state = CValidationState();
+ fInvalidFound = true;
+ break;
+ } else {
+ // A system error occurred (disk space, database error, ...).
+ return false;
+ }
+ } else {
+ if (!pindexOldTip || chainActive.Tip()->nChainWork > pindexOldTip->nChainWork) {
+ // We're in a better position than we were. Return temporarily to release the lock.
+ break;
}
}
}
- if (chainActive.Tip() != pindexOldTip) {
- std::string strCmd = GetArg("-blocknotify", "");
- if (!IsInitialBlockDownload() && !strCmd.empty())
+ // Callbacks/notifications for a new best chain.
+ if (fInvalidFound)
+ CheckForkWarningConditionsOnNewFork(vpindexToConnect.back());
+ else
+ CheckForkWarningConditions();
+
+ if (!pblocktree->Flush())
+ return state.Abort(_("Failed to sync block index"));
+
+ return true;
+}
+
+bool ActivateBestChain(CValidationState &state) {
+ CBlockIndex *pindexNewTip = NULL;
+ CBlockIndex *pindexMostWork = NULL;
+ do {
+ boost::this_thread::interruption_point();
+
+ bool fInitialDownload;
{
- boost::replace_all(strCmd, "%s", chainActive.Tip()->GetBlockHash().GetHex());
- boost::thread t(runCommand, strCmd); // thread runs free
+ LOCK(cs_main);
+ pindexMostWork = FindMostWorkChain();
+
+ // Whether we have anything to do at all.
+ if (pindexMostWork == NULL || pindexMostWork == chainActive.Tip())
+ return true;
+
+ if (!ActivateBestChainStep(state, pindexMostWork))
+ return false;
+
+ pindexNewTip = chainActive.Tip();
+ fInitialDownload = IsInitialBlockDownload();
}
- }
+ // When we reach this point, we switched to a new tip (stored in pindexNewTip).
+
+ // Notifications/callbacks that can run without cs_main
+ if (!fInitialDownload) {
+ uint256 hashNewTip = pindexNewTip->GetBlockHash();
+ // Relay inventory, but don't relay old inventory during initial block download.
+ int nBlockEstimate = Checkpoints::GetTotalBlocksEstimate();
+ LOCK(cs_vNodes);
+ BOOST_FOREACH(CNode* pnode, vNodes)
+ if (chainActive.Height() > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : nBlockEstimate))
+ pnode->PushInventory(CInv(MSG_BLOCK, hashNewTip));
+
+ std::string strCmd = GetArg("-blocknotify", "");
+ if (!strCmd.empty()) {
+ boost::replace_all(strCmd, "%s", hashNewTip.GetHex());
+ boost::thread t(runCommand, strCmd); // thread runs free
+ }
+ }
+ uiInterface.NotifyBlocksChanged();
+ } while(pindexMostWork != chainActive.Tip());
return true;
}
-
CBlockIndex* AddToBlockIndex(CBlockHeader& block)
{
// Check for duplicate
@@ -2173,6 +2215,7 @@ CBlockIndex* AddToBlockIndex(CBlockHeader& block)
{
pindexNew->pprev = (*miPrev).second;
pindexNew->nHeight = pindexNew->pprev->nHeight + 1;
+ pindexNew->BuildSkip();
}
pindexNew->nChainWork = (pindexNew->pprev ? pindexNew->pprev->nChainWork : 0) + pindexNew->GetBlockWork();
pindexNew->RaiseValidity(BLOCK_VALID_TREE);
@@ -2180,7 +2223,6 @@ CBlockIndex* AddToBlockIndex(CBlockHeader& block)
return pindexNew;
}
-
// Mark a block as having its data received and checked (up to BLOCK_VALID_TRANSACTIONS).
bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBlockIndex *pindexNew, const CDiskBlockPos& pos)
{
@@ -2210,30 +2252,9 @@ bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBl
if (!pblocktree->WriteBlockIndex(CDiskBlockIndex(pindexNew)))
return state.Abort(_("Failed to write block index"));
- // New best?
- if (!ActivateBestChain(state))
- return false;
-
- LOCK(cs_main);
- if (pindexNew == chainActive.Tip())
- {
- // Clear fork warning if its no longer applicable
- CheckForkWarningConditions();
- // Notify UI to display prev block's coinbase if it was ours
- static uint256 hashPrevBestCoinBase;
- g_signals.UpdatedTransaction(hashPrevBestCoinBase);
- hashPrevBestCoinBase = block.GetTxHash(0);
- } else
- CheckForkWarningConditionsOnNewFork(pindexNew);
-
- if (!pblocktree->Flush())
- return state.Abort(_("Failed to sync block index"));
-
- uiInterface.NotifyBlocksChanged();
return true;
}
-
bool FindBlockPos(CValidationState &state, CDiskBlockPos &pos, unsigned int nAddSize, unsigned int nHeight, uint64_t nTime, bool fKnown = false)
{
bool fUpdatedLast = false;
@@ -2328,7 +2349,6 @@ bool FindUndoPos(CValidationState &state, int nFile, CDiskBlockPos &pos, unsigne
return true;
}
-
bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, bool fCheckPOW)
{
// Check proof of work matches claimed amount
@@ -2341,28 +2361,6 @@ bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, bool f
return state.Invalid(error("CheckBlockHeader() : block timestamp too far in the future"),
REJECT_INVALID, "time-too-new");
- CBlockIndex* pcheckpoint = Checkpoints::GetLastCheckpoint(mapBlockIndex);
- if (pcheckpoint && block.hashPrevBlock != (chainActive.Tip() ? chainActive.Tip()->GetBlockHash() : uint256(0)))
- {
- // Extra checks to prevent "fill up memory by spamming with bogus blocks"
- int64_t deltaTime = block.GetBlockTime() - pcheckpoint->nTime;
- if (deltaTime < 0)
- {
- return state.DoS(100, error("CheckBlockHeader() : block with timestamp before last checkpoint"),
- REJECT_CHECKPOINT, "time-too-old");
- }
- bool fOverflow = false;
- uint256 bnNewBlock;
- bnNewBlock.SetCompact(block.nBits, NULL, &fOverflow);
- uint256 bnRequired;
- bnRequired.SetCompact(ComputeMinWork(pcheckpoint->nBits, deltaTime));
- if (fOverflow || bnNewBlock > bnRequired)
- {
- return state.DoS(100, error("CheckBlockHeader() : block with too little proof-of-work"),
- REJECT_INVALID, "bad-diffbits");
- }
- }
-
return true;
}
@@ -2393,16 +2391,11 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo
if (!CheckTransaction(tx, state))
return error("CheckBlock() : CheckTransaction failed");
- // Build the merkle tree already. We need it anyway later, and it makes the
- // block cache the transaction hashes, which means they don't need to be
- // recalculated many times during this block's validation.
- block.BuildMerkleTree();
-
// Check for duplicate txids. This is caught by ConnectInputs(),
// but catching it earlier avoids a potential DoS attack:
set<uint256> uniqueTx;
- for (unsigned int i = 0; i < block.vtx.size(); i++) {
- uniqueTx.insert(block.GetTxHash(i));
+ BOOST_FOREACH(const CTransaction &tx, block.vtx) {
+ uniqueTx.insert(tx.GetHash());
}
if (uniqueTx.size() != block.vtx.size())
return state.DoS(100, error("CheckBlock() : duplicate transaction"),
@@ -2418,7 +2411,7 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo
REJECT_INVALID, "bad-blk-sigops", true);
// Check merkle root
- if (fCheckMerkleRoot && block.hashMerkleRoot != block.vMerkleTree.back())
+ if (fCheckMerkleRoot && block.hashMerkleRoot != block.BuildMerkleTree())
return state.DoS(100, error("CheckBlock() : hashMerkleRoot mismatch"),
REJECT_INVALID, "bad-txnmrklroot", true);
@@ -2438,6 +2431,28 @@ bool AcceptBlockHeader(CBlockHeader& block, CValidationState& state, CBlockIndex
return state.Invalid(error("AcceptBlock() : block is marked invalid"), 0, "duplicate");
}
+ CBlockIndex* pcheckpoint = Checkpoints::GetLastCheckpoint(mapBlockIndex);
+ if (pcheckpoint && block.hashPrevBlock != (chainActive.Tip() ? chainActive.Tip()->GetBlockHash() : uint256(0)))
+ {
+ // Extra checks to prevent "fill up memory by spamming with bogus blocks"
+ int64_t deltaTime = block.GetBlockTime() - pcheckpoint->GetBlockTime();
+ if (deltaTime < 0)
+ {
+ return state.DoS(100, error("CheckBlockHeader() : block with timestamp before last checkpoint"),
+ REJECT_CHECKPOINT, "time-too-old");
+ }
+ bool fOverflow = false;
+ uint256 bnNewBlock;
+ bnNewBlock.SetCompact(block.nBits, NULL, &fOverflow);
+ uint256 bnRequired;
+ bnRequired.SetCompact(ComputeMinWork(pcheckpoint->nBits, deltaTime));
+ if (fOverflow || bnNewBlock > bnRequired)
+ {
+ return state.DoS(100, error("CheckBlockHeader() : block with too little proof-of-work"),
+ REJECT_INVALID, "bad-diffbits");
+ }
+ }
+
// Get prev block index
CBlockIndex* pindexPrev = NULL;
int nHeight = 0;
@@ -2469,14 +2484,11 @@ bool AcceptBlockHeader(CBlockHeader& block, CValidationState& state, CBlockIndex
return state.DoS(100, error("AcceptBlock() : forked chain older than last checkpoint (height %d)", nHeight));
// Reject block.nVersion=1 blocks when 95% (75% on testnet) of the network has upgraded:
- if (block.nVersion < 2)
+ if (block.nVersion < 2 &&
+ CBlockIndex::IsSuperMajority(2, pindexPrev, Params().RejectBlockOutdatedMajority()))
{
- if ((!TestNet() && CBlockIndex::IsSuperMajority(2, pindexPrev, 950, 1000)) ||
- (TestNet() && CBlockIndex::IsSuperMajority(2, pindexPrev, 75, 100)))
- {
- return state.Invalid(error("AcceptBlock() : rejected nVersion=1 block"),
- REJECT_OBSOLETE, "bad-version");
- }
+ return state.Invalid(error("AcceptBlock() : rejected nVersion=1 block"),
+ REJECT_OBSOLETE, "bad-version");
}
}
@@ -2506,7 +2518,6 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex,
}
int nHeight = pindex->nHeight;
- uint256 hash = pindex->GetBlockHash();
// Check that all transactions are finalized
BOOST_FOREACH(const CTransaction& tx, block.vtx)
@@ -2517,19 +2528,15 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex,
}
// Enforce block.nVersion=2 rule that the coinbase starts with serialized block height
- if (block.nVersion >= 2)
+ // if 750 of the last 1,000 blocks are version 2 or greater (51/100 if testnet):
+ if (block.nVersion >= 2 &&
+ CBlockIndex::IsSuperMajority(2, pindex->pprev, Params().EnforceBlockUpgradeMajority()))
{
- // if 750 of the last 1,000 blocks are version 2 or greater (51/100 if testnet):
- if ((!TestNet() && CBlockIndex::IsSuperMajority(2, pindex->pprev, 750, 1000)) ||
- (TestNet() && CBlockIndex::IsSuperMajority(2, pindex->pprev, 51, 100)))
- {
- CScript expect = CScript() << nHeight;
- if (block.vtx[0].vin[0].scriptSig.size() < expect.size() ||
- !std::equal(expect.begin(), expect.end(), block.vtx[0].vin[0].scriptSig.begin())) {
- pindex->nStatus |= BLOCK_FAILED_VALID;
- return state.DoS(100, error("AcceptBlock() : block height mismatch in coinbase"),
- REJECT_INVALID, "bad-cb-height");
- }
+ CScript expect = CScript() << nHeight;
+ if (block.vtx[0].vin[0].scriptSig.size() < expect.size() ||
+ !std::equal(expect.begin(), expect.end(), block.vtx[0].vin[0].scriptSig.begin())) {
+ pindex->nStatus |= BLOCK_FAILED_VALID;
+ return state.DoS(100, error("AcceptBlock() : block height mismatch in coinbase"), REJECT_INVALID, "bad-cb-height");
}
}
@@ -2539,7 +2546,7 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex,
CDiskBlockPos blockPos;
if (dbp != NULL)
blockPos = *dbp;
- if (!FindBlockPos(state, blockPos, nBlockSize+8, nHeight, block.nTime, dbp != NULL))
+ if (!FindBlockPos(state, blockPos, nBlockSize+8, nHeight, block.GetBlockTime(), dbp != NULL))
return error("AcceptBlock() : FindBlockPos failed");
if (dbp == NULL)
if (!WriteBlockToDisk(block, blockPos))
@@ -2550,21 +2557,12 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex,
return state.Abort(_("System error: ") + e.what());
}
- // Relay inventory, but don't relay old inventory during initial block download
- int nBlockEstimate = Checkpoints::GetTotalBlocksEstimate();
- if (chainActive.Tip()->GetBlockHash() == hash)
- {
- LOCK(cs_vNodes);
- BOOST_FOREACH(CNode* pnode, vNodes)
- if (chainActive.Height() > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : nBlockEstimate))
- pnode->PushInventory(CInv(MSG_BLOCK, hash));
- }
-
return true;
}
-bool CBlockIndex::IsSuperMajority(int minVersion, const CBlockIndex* pstart, unsigned int nRequired, unsigned int nToCheck)
+bool CBlockIndex::IsSuperMajority(int minVersion, const CBlockIndex* pstart, unsigned int nRequired)
{
+ unsigned int nToCheck = Params().ToCheckBlockUpgradeMajority();
unsigned int nFound = 0;
for (unsigned int i = 0; i < nToCheck && nFound < nRequired && pstart != NULL; i++)
{
@@ -2575,17 +2573,53 @@ bool CBlockIndex::IsSuperMajority(int minVersion, const CBlockIndex* pstart, uns
return (nFound >= nRequired);
}
-int64_t CBlockIndex::GetMedianTime() const
+/** Turn the lowest '1' bit in the binary representation of a number into a '0'. */
+int static inline InvertLowestOne(int n) { return n & (n - 1); }
+
+/** Compute what height to jump back to with the CBlockIndex::pskip pointer. */
+int static inline GetSkipHeight(int height) {
+ if (height < 2)
+ return 0;
+
+ // Determine which height to jump back to. Any number strictly lower than height is acceptable,
+ // but the following expression seems to perform well in simulations (max 110 steps to go back
+ // up to 2**18 blocks).
+ return (height & 1) ? InvertLowestOne(InvertLowestOne(height - 1)) + 1 : InvertLowestOne(height);
+}
+
+CBlockIndex* CBlockIndex::GetAncestor(int height)
{
- AssertLockHeld(cs_main);
- const CBlockIndex* pindex = this;
- for (int i = 0; i < nMedianTimeSpan/2; i++)
- {
- if (!chainActive.Next(pindex))
- return GetBlockTime();
- pindex = chainActive.Next(pindex);
+ if (height > nHeight || height < 0)
+ return NULL;
+
+ CBlockIndex* pindexWalk = this;
+ int heightWalk = nHeight;
+ while (heightWalk > height) {
+ int heightSkip = GetSkipHeight(heightWalk);
+ int heightSkipPrev = GetSkipHeight(heightWalk - 1);
+ if (heightSkip == height ||
+ (heightSkip > height && !(heightSkipPrev < heightSkip - 2 &&
+ heightSkipPrev >= height))) {
+ // Only follow pskip if pprev->pskip isn't better than pskip->pprev.
+ pindexWalk = pindexWalk->pskip;
+ heightWalk = heightSkip;
+ } else {
+ pindexWalk = pindexWalk->pprev;
+ heightWalk--;
+ }
}
- return pindex->GetMedianTimePast();
+ return pindexWalk;
+}
+
+const CBlockIndex* CBlockIndex::GetAncestor(int height) const
+{
+ return const_cast<CBlockIndex*>(this)->GetAncestor(height);
+}
+
+void CBlockIndex::BuildSkip()
+{
+ if (pprev)
+ pskip = pprev->GetAncestor(GetSkipHeight(nHeight));
}
void PushGetBlocks(CNode* pnode, CBlockIndex* pindexBegin, uint256 hashEnd)
@@ -2602,10 +2636,11 @@ void PushGetBlocks(CNode* pnode, CBlockIndex* pindexBegin, uint256 hashEnd)
bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBlockPos *dbp)
{
- AssertLockHeld(cs_main);
-
// Check for duplicate
uint256 hash = pblock->GetHash();
+
+ {
+ LOCK(cs_main);
if (mapBlockIndex.count(hash))
return state.Invalid(error("ProcessBlock() : already have block %d %s", mapBlockIndex[hash]->nHeight, hash.ToString()), 0, "duplicate");
if (mapOrphanBlocks.count(hash))
@@ -2674,7 +2709,11 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl
mapOrphanBlocksByPrev.erase(hashPrev);
}
- LogPrintf("ProcessBlock: ACCEPTED\n");
+ }
+
+ if (!ActivateBestChain(state))
+ return error("ProcessBlock() : ActivateBestChain failed");
+
return true;
}
@@ -2697,8 +2736,8 @@ CMerkleBlock::CMerkleBlock(const CBlock& block, CBloomFilter& filter)
for (unsigned int i = 0; i < block.vtx.size(); i++)
{
- uint256 hash = block.vtx[i].GetHash();
- if (filter.IsRelevantAndUpdate(block.vtx[i], hash))
+ const uint256& hash = block.vtx[i].GetHash();
+ if (filter.IsRelevantAndUpdate(block.vtx[i]))
{
vMatch.push_back(true);
vMatchedTxn.push_back(make_pair(i, hash));
@@ -2933,6 +2972,8 @@ bool static LoadBlockIndexDB()
setBlockIndexValid.insert(pindex);
if (pindex->nStatus & BLOCK_FAILED_MASK && (!pindexBestInvalid || pindex->nChainWork > pindexBestInvalid->nChainWork))
pindexBestInvalid = pindex;
+ if (pindex->pprev)
+ pindex->BuildSkip();
}
// Load block file info
@@ -2981,7 +3022,17 @@ bool static LoadBlockIndexDB()
return true;
}
-bool VerifyDB(int nCheckLevel, int nCheckDepth)
+CVerifyDB::CVerifyDB()
+{
+ uiInterface.ShowProgress(_("Verifying blocks..."), 0);
+}
+
+CVerifyDB::~CVerifyDB()
+{
+ uiInterface.ShowProgress("", 100);
+}
+
+bool CVerifyDB::VerifyDB(int nCheckLevel, int nCheckDepth)
{
LOCK(cs_main);
if (chainActive.Tip() == NULL || chainActive.Tip()->pprev == NULL)
@@ -3002,6 +3053,7 @@ bool VerifyDB(int nCheckLevel, int nCheckDepth)
for (CBlockIndex* pindex = chainActive.Tip(); pindex && pindex->pprev; pindex = pindex->pprev)
{
boost::this_thread::interruption_point();
+ uiInterface.ShowProgress(_("Verifying blocks..."), std::max(1, std::min(99, (int)(((double)(chainActive.Height() - pindex->nHeight)) / (double)nCheckDepth * (nCheckLevel >= 4 ? 50 : 100)))));
if (pindex->nHeight < chainActive.Height()-nCheckDepth)
break;
CBlock block;
@@ -3041,6 +3093,7 @@ bool VerifyDB(int nCheckLevel, int nCheckDepth)
CBlockIndex *pindex = pindexState;
while (pindex != chainActive.Tip()) {
boost::this_thread::interruption_point();
+ uiInterface.ShowProgress(_("Verifying blocks..."), std::max(1, std::min(99, 100 - (int)(((double)(chainActive.Height() - pindex->nHeight)) / (double)nCheckDepth * 50))));
pindex = chainActive.Next(pindex);
CBlock block;
if (!ReadBlockFromDisk(block, pindex))
@@ -3091,13 +3144,15 @@ bool InitBlockIndex() {
unsigned int nBlockSize = ::GetSerializeSize(block, SER_DISK, CLIENT_VERSION);
CDiskBlockPos blockPos;
CValidationState state;
- if (!FindBlockPos(state, blockPos, nBlockSize+8, 0, block.nTime))
+ if (!FindBlockPos(state, blockPos, nBlockSize+8, 0, block.GetBlockTime()))
return error("LoadBlockIndex() : FindBlockPos failed");
if (!WriteBlockToDisk(block, blockPos))
return error("LoadBlockIndex() : writing genesis block to disk failed");
CBlockIndex *pindex = AddToBlockIndex(block);
if (!ReceivedBlockTransactions(block, state, pindex, blockPos))
return error("LoadBlockIndex() : genesis block not accepted");
+ if (!ActivateBestChain(state))
+ return error("LoadBlockIndex() : genesis block cannot be activated");
} catch(std::runtime_error &e) {
return error("LoadBlockIndex() : failed to initialize block database: %s", e.what());
}
@@ -3227,7 +3282,6 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp)
// process block
if (nBlockPos >= nStartByte) {
- LOCK(cs_main);
if (dbp)
dbp->nPos = nBlockPos;
CValidationState state;
@@ -3391,7 +3445,8 @@ void static ProcessGetData(CNode* pfrom)
{
// Send block from disk
CBlock block;
- assert(ReadBlockFromDisk(block, (*mi).second));
+ if (!ReadBlockFromDisk(block, (*mi).second))
+ assert(!"cannot load block from disk");
if (inv.type == MSG_BLOCK)
pfrom->PushMessage("block", block);
else // MSG_FILTERED_BLOCK)
@@ -3478,10 +3533,10 @@ void static ProcessGetData(CNode* pfrom)
}
}
-bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
+bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, int64_t nTimeReceived)
{
RandAddSeedPerfmon();
- LogPrint("net", "received: %s (%u bytes)\n", strCommand, vRecv.size());
+ LogPrint("net", "received: %s (%u bytes) peer=%d\n", strCommand, vRecv.size(), pfrom->id);
if (mapArgs.count("-dropmessagestest") && GetRand(atoi(mapArgs["-dropmessagestest"])) == 0)
{
LogPrintf("dropmessagestest DROPPING RECV MESSAGE\n");
@@ -3513,7 +3568,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
if (pfrom->nVersion < MIN_PEER_PROTO_VERSION)
{
// disconnect from peers older than this proto version
- LogPrintf("partner %s using obsolete version %i; disconnecting\n", pfrom->addr.ToString(), pfrom->nVersion);
+ LogPrintf("peer=%d using obsolete version %i; disconnecting\n", pfrom->id, pfrom->nVersion);
pfrom->PushMessage("reject", strCommand, REJECT_OBSOLETE,
strprintf("Version must be %d or greater", MIN_PEER_PROTO_VERSION));
pfrom->fDisconnect = true;
@@ -3563,7 +3618,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
if (!pfrom->fInbound)
{
// Advertise our address
- if (!fNoListen && !IsInitialBlockDownload())
+ if (fListen && !IsInitialBlockDownload())
{
CAddress addr = GetLocalAddress(&pfrom->addr);
if (addr.IsRoutable())
@@ -3594,7 +3649,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
pfrom->fSuccessfullyConnected = true;
- LogPrintf("receive version message: %s: version %d, blocks=%d, us=%s, them=%s, peer=%s\n", pfrom->cleanSubVer, pfrom->nVersion, pfrom->nStartingHeight, addrMe.ToString(), addrFrom.ToString(), pfrom->addr.ToString());
+ LogPrintf("receive version message: %s: version %d, blocks=%d, us=%s, peer=%d\n", pfrom->cleanSubVer, pfrom->nVersion, pfrom->nStartingHeight, addrMe.ToString(), pfrom->id);
AddTimeData(pfrom->addr, nTime);
}
@@ -3701,7 +3756,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
pfrom->AddInventoryKnown(inv);
bool fAlreadyHave = AlreadyHave(inv);
- LogPrint("net", " got inventory: %s %s\n", inv.ToString(), fAlreadyHave ? "have" : "new");
+ LogPrint("net", "got inv: %s %s peer=%d\n", inv.ToString(), fAlreadyHave ? "have" : "new", pfrom->id);
if (!fAlreadyHave) {
if (!fImporting && !fReindex) {
@@ -3714,6 +3769,9 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
PushGetBlocks(pfrom, chainActive.Tip(), GetOrphanRoot(inv.hash));
}
+ if (inv.type == MSG_BLOCK)
+ UpdateBlockAvailability(pfrom->GetId(), inv.hash);
+
// Track requests for our stuff
g_signals.Inventory(inv.hash);
}
@@ -3731,10 +3789,10 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
}
if (fDebug || (vInv.size() != 1))
- LogPrint("net", "received getdata (%u invsz)\n", vInv.size());
+ LogPrint("net", "received getdata (%u invsz) peer=%d\n", vInv.size(), pfrom->id);
if ((fDebug && vInv.size() > 0) || (vInv.size() == 1))
- LogPrint("net", "received getdata for: %s\n", vInv[0].ToString());
+ LogPrint("net", "received getdata for: %s peer=%d\n", vInv[0].ToString(), pfrom->id);
pfrom->vRecvGetData.insert(pfrom->vRecvGetData.end(), vInv.begin(), vInv.end());
ProcessGetData(pfrom);
@@ -3756,7 +3814,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
if (pindex)
pindex = chainActive.Next(pindex);
int nLimit = 500;
- LogPrint("net", "getblocks %d to %s limit %d\n", (pindex ? pindex->nHeight : -1), hashStop.ToString(), nLimit);
+ LogPrint("net", "getblocks %d to %s limit %d from peer=%d\n", (pindex ? pindex->nHeight : -1), hashStop==uint256(0) ? "end" : hashStop.ToString(), nLimit, pfrom->id);
for (; pindex; pindex = chainActive.Next(pindex))
{
if (pindex->GetBlockHash() == hashStop)
@@ -3833,14 +3891,14 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
if (AcceptToMemoryPool(mempool, state, tx, true, &fMissingInputs))
{
mempool.check(pcoinsTip);
- RelayTransaction(tx, inv.hash);
+ RelayTransaction(tx);
mapAlreadyAskedFor.erase(inv);
vWorkQueue.push_back(inv.hash);
vEraseQueue.push_back(inv.hash);
- LogPrint("mempool", "AcceptToMemoryPool: %s %s : accepted %s (poolsz %u)\n",
- pfrom->addr.ToString(), pfrom->cleanSubVer,
+ LogPrint("mempool", "AcceptToMemoryPool: peer=%d %s : accepted %s (poolsz %u)\n",
+ pfrom->id, pfrom->cleanSubVer,
tx.GetHash().ToString(),
mempool.mapTx.size());
@@ -3863,7 +3921,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
if (AcceptToMemoryPool(mempool, stateDummy, orphanTx, true, &fMissingInputs2))
{
LogPrint("mempool", " accepted orphan tx %s\n", orphanHash.ToString());
- RelayTransaction(orphanTx, orphanHash);
+ RelayTransaction(orphanTx);
mapAlreadyAskedFor.erase(CInv(MSG_TX, orphanHash));
vWorkQueue.push_back(orphanHash);
vEraseQueue.push_back(orphanHash);
@@ -3893,8 +3951,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
int nDoS = 0;
if (state.IsInvalid(nDoS))
{
- LogPrint("mempool", "%s from %s %s was not accepted into the memory pool: %s\n", tx.GetHash().ToString(),
- pfrom->addr.ToString(), pfrom->cleanSubVer,
+ LogPrint("mempool", "%s from peer=%d %s was not accepted into the memory pool: %s\n", tx.GetHash().ToString(),
+ pfrom->id, pfrom->cleanSubVer,
state.GetRejectReason());
pfrom->PushMessage("reject", strCommand, state.GetRejectCode(),
state.GetRejectReason(), inv.hash);
@@ -3909,19 +3967,31 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
CBlock block;
vRecv >> block;
- LogPrint("net", "received block %s\n", block.GetHash().ToString());
+ LogPrint("net", "received block %s peer=%d\n", block.GetHash().ToString(), pfrom->id);
// block.print();
CInv inv(MSG_BLOCK, block.GetHash());
pfrom->AddInventoryKnown(inv);
- LOCK(cs_main);
- // Remember who we got this block from.
- mapBlockSource[inv.hash] = pfrom->GetId();
- MarkBlockAsReceived(inv.hash, pfrom->GetId());
+ {
+ LOCK(cs_main);
+ // Remember who we got this block from.
+ mapBlockSource[inv.hash] = pfrom->GetId();
+ MarkBlockAsReceived(inv.hash, pfrom->GetId());
+ }
CValidationState state;
ProcessBlock(state, pfrom, &block);
+ int nDoS;
+ if (state.IsInvalid(nDoS)) {
+ pfrom->PushMessage("reject", strCommand, state.GetRejectCode(),
+ state.GetRejectReason(), inv.hash);
+ if (nDoS > 0) {
+ LOCK(cs_main);
+ Misbehaving(pfrom->GetId(), nDoS);
+ }
+ }
+
}
@@ -3946,7 +4016,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
CTransaction tx;
bool fInMemPool = mempool.lookup(hash, tx);
if (!fInMemPool) continue; // another thread removed since queryHashes, maybe...
- if ((pfrom->pfilter && pfrom->pfilter->IsRelevantAndUpdate(tx, hash)) ||
+ if ((pfrom->pfilter && pfrom->pfilter->IsRelevantAndUpdate(tx)) ||
(!pfrom->pfilter))
vInv.push_back(inv);
if (vInv.size() == MAX_INV_SZ) {
@@ -3983,7 +4053,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
else if (strCommand == "pong")
{
- int64_t pingUsecEnd = GetTimeMicros();
+ int64_t pingUsecEnd = nTimeReceived;
uint64_t nonce = 0;
size_t nAvail = vRecv.in_avail();
bool bPingFinished = false;
@@ -4024,8 +4094,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
}
if (!(sProblem.empty())) {
- LogPrint("net", "pong %s %s: %s, %x expected, %x received, %u bytes\n",
- pfrom->addr.ToString(),
+ LogPrint("net", "pong peer=%d %s: %s, %x expected, %x received, %u bytes\n",
+ pfrom->id,
pfrom->cleanSubVer,
sProblem,
pfrom->nPingNonceSent,
@@ -4143,6 +4213,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
else
{
// Ignore unknown commands for extensibility
+ LogPrint("net", "Unknown command \"%s\" from peer=%d\n", SanitizeString(strCommand), pfrom->id);
}
@@ -4233,7 +4304,7 @@ bool ProcessMessages(CNode* pfrom)
bool fRet = false;
try
{
- fRet = ProcessMessage(pfrom, strCommand, vRecv);
+ fRet = ProcessMessage(pfrom, strCommand, vRecv, msg.nTime);
boost::this_thread::interruption_point();
}
catch (std::ios_base::failure& e)
@@ -4264,7 +4335,7 @@ bool ProcessMessages(CNode* pfrom)
}
if (!fRet)
- LogPrintf("ProcessMessage(%s, %u bytes) FAILED\n", strCommand, nMessageSize);
+ LogPrintf("ProcessMessage(%s, %u bytes) FAILED peer=%d\n", strCommand, nMessageSize, pfrom->id);
break;
}
@@ -4292,8 +4363,8 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
// RPC ping request by user
pingSend = true;
}
- if (pto->nLastSend && GetTime() - pto->nLastSend > 30 * 60 && pto->vSendMsg.empty()) {
- // Ping automatically sent as a keepalive
+ if (pto->nPingNonceSent == 0 && pto->nPingUsecStart + PING_INTERVAL * 1000000 < GetTimeMicros()) {
+ // Ping automatically sent as a latency probe & keepalive.
pingSend = true;
}
if (pingSend) {
@@ -4301,15 +4372,14 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
while (nonce == 0) {
RAND_bytes((unsigned char*)&nonce, sizeof(nonce));
}
- pto->nPingNonceSent = nonce;
pto->fPingQueued = false;
+ pto->nPingUsecStart = GetTimeMicros();
if (pto->nVersion > BIP0031_VERSION) {
- // Take timestamp as close as possible before transmitting ping
- pto->nPingUsecStart = GetTimeMicros();
+ pto->nPingNonceSent = nonce;
pto->PushMessage("ping", nonce);
} else {
- // Peer is too old to support ping command with nonce, pong will never arrive, disable timing
- pto->nPingUsecStart = 0;
+ // Peer is too old to support ping command with nonce, pong will never arrive.
+ pto->nPingNonceSent = 0;
pto->PushMessage("ping");
}
}
@@ -4331,7 +4401,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
pnode->setAddrKnown.clear();
// Rebroadcast our address
- if (!fNoListen)
+ if (fListen)
{
CAddress addr = GetLocalAddress(&pnode->addr);
if (addr.IsRoutable())
@@ -4451,13 +4521,16 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
// in flight for over two minutes, since we first had a chance to
// process an incoming block.
int64_t nNow = GetTimeMicros();
- if (!pto->fDisconnect && state.nBlocksInFlight &&
- state.nLastBlockReceive < state.nLastBlockProcess - BLOCK_DOWNLOAD_TIMEOUT*1000000 &&
+ if (!pto->fDisconnect && state.nBlocksInFlight &&
+ state.nLastBlockReceive < state.nLastBlockProcess - BLOCK_DOWNLOAD_TIMEOUT*1000000 &&
state.vBlocksInFlight.front().nTime < state.nLastBlockProcess - 2*BLOCK_DOWNLOAD_TIMEOUT*1000000) {
LogPrintf("Peer %s is stalling block download, disconnecting\n", state.name.c_str());
pto->fDisconnect = true;
}
+ // Update knowledge of peer's block availability.
+ ProcessBlockAvailability(pto->GetId());
+
//
// Message: getdata (blocks)
//
@@ -4466,7 +4539,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
uint256 hash = state.vBlocksToDownload.front();
vGetData.push_back(CInv(MSG_BLOCK, hash));
MarkBlockAsInFlight(pto->GetId(), hash);
- LogPrint("net", "Requesting block %s from %s\n", hash.ToString(), state.name);
+ LogPrint("net", "Requesting block %s peer=%d\n", hash.ToString(), pto->id);
if (vGetData.size() >= 1000)
{
pto->PushMessage("getdata", vGetData);
@@ -4483,7 +4556,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
if (!AlreadyHave(inv))
{
if (fDebug)
- LogPrint("net", "sending getdata: %s\n", inv.ToString());
+ LogPrint("net", "Requesting %s peer=%d\n", inv.ToString(), pto->id);
vGetData.push_back(inv);
if (vGetData.size() >= 1000)
{
diff --git a/src/main.h b/src/main.h
index f47c9ee825..f6bac889be 100644
--- a/src/main.h
+++ b/src/main.h
@@ -7,7 +7,7 @@
#define BITCOIN_MAIN_H
#if defined(HAVE_CONFIG_H)
-#include "bitcoin-config.h"
+#include "config/bitcoin-config.h"
#endif
#include "chainparams.h"
@@ -43,10 +43,12 @@ static const unsigned int DEFAULT_BLOCK_PRIORITY_SIZE = 50000;
static const unsigned int MAX_STANDARD_TX_SIZE = 100000;
/** The maximum allowed number of signature check operations in a block (network rule) */
static const unsigned int MAX_BLOCK_SIGOPS = MAX_BLOCK_SIZE/50;
+/** Maxiumum number of signature check operations in an IsStandard() P2SH script */
+static const unsigned int MAX_P2SH_SIGOPS = 15;
/** The maximum number of orphan transactions kept in memory */
static const unsigned int MAX_ORPHAN_TRANSACTIONS = MAX_BLOCK_SIZE/100;
-/** The maximum number of orphan blocks kept in memory */
-static const unsigned int MAX_ORPHAN_BLOCKS = 750;
+/** Default for -maxorphanblocks, maximum number of orphan blocks kept in memory */
+static const unsigned int DEFAULT_MAX_ORPHAN_BLOCKS = 750;
/** The maximum size of a blk?????.dat file (since 0.8) */
static const unsigned int MAX_BLOCKFILE_SIZE = 0x8000000; // 128 MiB
/** The pre-allocation chunk size for blk?????.dat files (since 0.8) */
@@ -66,12 +68,6 @@ static const int MAX_BLOCKS_IN_TRANSIT_PER_PEER = 128;
/** Timeout in seconds before considering a block download peer unresponsive. */
static const unsigned int BLOCK_DOWNLOAD_TIMEOUT = 60;
-#ifdef USE_UPNP
-static const int fHaveUPnP = true;
-#else
-static const int fHaveUPnP = false;
-#endif
-
/** "reject" message codes **/
static const unsigned char REJECT_MALFORMED = 0x01;
static const unsigned char REJECT_INVALID = 0x10;
@@ -97,12 +93,12 @@ extern bool fBenchmark;
extern int nScriptCheckThreads;
extern bool fTxIndex;
extern unsigned int nCoinCacheSize;
+extern CFeeRate minRelayTxFee;
// Minimum disk space required - used in CheckDiskSpace()
static const uint64_t nMinDiskSpace = 52428800;
-class CCoinsDB;
class CBlockTreeDB;
struct CDiskBlockPos;
class CTxUndo;
@@ -113,6 +109,9 @@ struct CNodeStateStats;
struct CBlockTemplate;
+/** Initialize respend bloom filter **/
+void InitRespendFilter();
+
/** Register a wallet to receive updates from core */
void RegisterWallet(CWalletInterface* pwalletIn);
/** Unregister a wallet from core */
@@ -120,7 +119,7 @@ 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);
+void SyncWithWallets(const CTransaction& tx, const CBlock* pblock = NULL);
/** Register with a network node to receive its signals */
void RegisterNodeSignals(CNodeSignals& nodeSignals);
@@ -145,8 +144,6 @@ bool InitBlockIndex();
bool LoadBlockIndex();
/** Unload database information */
void UnloadBlockIndex();
-/** Verify consistency of the block and coin databases */
-bool VerifyDB(int nCheckLevel, int nCheckDepth);
/** Print the loaded block tree */
void PrintBlockTree();
/** Process protocol messages received from a given node */
@@ -155,10 +152,6 @@ bool ProcessMessages(CNode* pfrom);
bool SendMessages(CNode* pto, bool fSendTrickle);
/** Run an instance of the script checking thread */
void ThreadScriptCheck();
-/** Check whether a block hash satisfies the proof-of-work requirement specified by nBits */
-bool CheckProofOfWork(uint256 hash, unsigned int nBits);
-/** Calculate the minimum amount of work a received block needs, without knowing its direct parent */
-unsigned int ComputeMinWork(unsigned int nBase, int64_t nTime);
/** Check whether we are doing an initial block download (synchronizing from disk or network) */
bool IsInitialBlockDownload();
/** Format a string that describes several potential problems detected by the core */
@@ -168,7 +161,6 @@ bool GetTransaction(const uint256 &hash, CTransaction &tx, uint256 &hashBlock, b
/** Find the best known block, and make it the tip of the block chain */
bool ActivateBestChain(CValidationState &state);
int64_t GetBlockValue(int nHeight, int64_t nFees);
-unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock);
void UpdateTime(CBlockHeader& block, const CBlockIndex* pindexPrev);
@@ -197,6 +189,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
struct CNodeStateStats {
int nMisbehavior;
+ int nSyncHeight;
};
struct CDiskBlockPos
@@ -253,14 +246,7 @@ struct CDiskTxPos : public CDiskBlockPos
};
-
-enum GetMinFee_mode
-{
- GMF_RELAY,
- GMF_SEND,
-};
-
-int64_t GetMinFee(const CTransaction& tx, unsigned int nBytes, bool fAllowFree, enum GetMinFee_mode mode);
+int64_t GetMinRelayFee(const CTransaction& tx, unsigned int nBytes, bool fAllowFree);
//
// Check transaction inputs, and make sure any
@@ -295,13 +281,6 @@ unsigned int GetLegacySigOpCount(const CTransaction& tx);
unsigned int GetP2SHSigOpCount(const CTransaction& tx, CCoinsViewCache& mapInputs);
-inline bool AllowFree(double dPriority)
-{
- // Large (in bytes) low-priority (new, small-coin) transactions
- // need a fee.
- return dPriority > COIN * 144 / 250;
-}
-
// Check whether all inputs of this transaction are valid (no double spends, scripts & sigs, amounts)
// This does not modify the UTXO set. If pvChecks is not NULL, script checks are pushed onto it
// instead of being performed inline.
@@ -310,7 +289,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, CCoinsViewCach
std::vector<CScriptCheck> *pvChecks = NULL);
// Apply the effects of this transaction on the UTXO set represented by view
-void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCache &inputs, CTxUndo &txundo, int nHeight, const uint256 &txhash);
+void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCache &inputs, CTxUndo &txundo, int nHeight);
// Context-independent validity checks
bool CheckTransaction(const CTransaction& tx, CValidationState& state);
@@ -474,7 +453,7 @@ public:
int GetDepthInMainChain() const { CBlockIndex *pindexRet; return GetDepthInMainChain(pindexRet); }
bool IsInMainChain() const { CBlockIndex *pindexRet; return GetDepthInMainChainINTERNAL(pindexRet) > 0; }
int GetBlocksToMaturity() const;
- bool AcceptToMemoryPool(bool fLimitFree=true);
+ bool AcceptToMemoryPool(bool fLimitFree=true, bool fRejectInsaneFee=true);
};
@@ -695,6 +674,9 @@ public:
// pointer to the index of the predecessor of this block
CBlockIndex* pprev;
+ // pointer to the index of some further predecessor of this block
+ CBlockIndex* pskip;
+
// height of the entry in the chain. The genesis block has height 0
int nHeight;
@@ -730,10 +712,11 @@ public:
// (memory only) Sequencial id assigned to distinguish order in which blocks are received.
uint32_t nSequenceId;
- CBlockIndex()
+ void SetNull()
{
phashBlock = NULL;
pprev = NULL;
+ pskip = NULL;
nHeight = 0;
nFile = 0;
nDataPos = 0;
@@ -751,19 +734,14 @@ public:
nNonce = 0;
}
+ CBlockIndex()
+ {
+ SetNull();
+ }
+
CBlockIndex(CBlockHeader& block)
{
- phashBlock = NULL;
- pprev = NULL;
- nHeight = 0;
- nFile = 0;
- nDataPos = 0;
- nUndoPos = 0;
- nChainWork = 0;
- nTx = 0;
- nChainTx = 0;
- nStatus = 0;
- nSequenceId = 0;
+ SetNull();
nVersion = block.nVersion;
hashMerkleRoot = block.hashMerkleRoot;
@@ -828,11 +806,6 @@ public:
return (~bnTarget / (bnTarget + 1)) + 1;
}
- bool CheckIndex() const
- {
- return CheckProofOfWork(GetBlockHash(), nBits);
- }
-
enum { nMedianTimeSpan=11 };
int64_t GetMedianTimePast() const
@@ -849,26 +822,25 @@ public:
return pbegin[(pend - pbegin)/2];
}
- int64_t GetMedianTime() const;
-
/**
* Returns true if there are nRequired or more blocks of minVersion or above
- * in the last nToCheck blocks, starting at pstart and going backwards.
+ * in the last Params().ToCheckBlockUpgradeMajority() blocks, starting at pstart
+ * and going backwards.
*/
static bool IsSuperMajority(int minVersion, const CBlockIndex* pstart,
- unsigned int nRequired, unsigned int nToCheck);
+ unsigned int nRequired);
std::string ToString() const
{
return strprintf("CBlockIndex(pprev=%p, nHeight=%d, merkle=%s, hashBlock=%s)",
pprev, nHeight,
- hashMerkleRoot.ToString().c_str(),
- GetBlockHash().ToString().c_str());
+ hashMerkleRoot.ToString(),
+ GetBlockHash().ToString());
}
void print() const
{
- LogPrintf("%s\n", ToString().c_str());
+ LogPrintf("%s\n", ToString());
}
// Check whether this block index entry is valid up to the passed validity level.
@@ -893,9 +865,14 @@ public:
}
return false;
}
-};
+ // Build the skiplist pointer for this entry.
+ void BuildSkip();
+ // Efficiently find an ancestor of this block.
+ CBlockIndex* GetAncestor(int height);
+ const CBlockIndex* GetAncestor(int height) const;
+};
/** Used to marshal pointers into hashes for db storage. */
class CDiskBlockIndex : public CBlockIndex
@@ -953,14 +930,14 @@ public:
std::string str = "CDiskBlockIndex(";
str += CBlockIndex::ToString();
str += strprintf("\n hashBlock=%s, hashPrev=%s)",
- GetBlockHash().ToString().c_str(),
- hashPrev.ToString().c_str());
+ GetBlockHash().ToString(),
+ hashPrev.ToString());
return str;
}
void print() const
{
- LogPrintf("%s\n", ToString().c_str());
+ LogPrintf("%s\n", ToString());
}
};
@@ -1027,6 +1004,14 @@ public:
std::string GetRejectReason() const { return strRejectReason; }
};
+/** RAII wrapper for VerifyDB: Verify consistency of the block and coin databases */
+class CVerifyDB {
+public:
+ CVerifyDB();
+ ~CVerifyDB();
+ bool VerifyDB(int nCheckLevel, int nCheckDepth);
+};
+
/** An in-memory indexed chain of blocks. */
class CChain {
private:
@@ -1082,14 +1067,14 @@ public:
/** Find the last common block between this chain and a locator. */
CBlockIndex *FindFork(const CBlockLocator &locator) const;
+
+ /** Find the last common block between this chain and a block index entry. */
+ CBlockIndex *FindFork(CBlockIndex *pindex) const;
};
/** The currently-connected chain of blocks. */
extern CChain chainActive;
-/** The currently best known chain of headers (some of which may be invalid). */
-extern CChain chainMostWork;
-
/** Global variable that points to the active CCoinsView (protected by cs_main) */
extern CCoinsViewCache *pcoinsTip;
@@ -1138,7 +1123,7 @@ public:
class CWalletInterface {
protected:
- virtual void SyncTransaction(const uint256 &hash, const CTransaction &tx, const CBlock *pblock) =0;
+ virtual void SyncTransaction(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;
diff --git a/src/miner.cpp b/src/miner.cpp
index 94fc8e3888..17918a1280 100644
--- a/src/miner.cpp
+++ b/src/miner.cpp
@@ -3,90 +3,67 @@
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include <inttypes.h>
+
#include "miner.h"
#include "core.h"
+#include "hash.h"
#include "main.h"
#include "net.h"
+#include "pow.h"
#ifdef ENABLE_WALLET
#include "wallet.h"
#endif
+
+using namespace std;
+
//////////////////////////////////////////////////////////////////////////////
//
// BitcoinMiner
//
-int static FormatHashBlocks(void* pbuffer, unsigned int len)
-{
- unsigned char* pdata = (unsigned char*)pbuffer;
- unsigned int blocks = 1 + ((len + 8) / 64);
- unsigned char* pend = pdata + 64 * blocks;
- memset(pdata + len, 0, 64 * blocks - len);
- pdata[len] = 0x80;
- unsigned int bits = len * 8;
- pend[-1] = (bits >> 0) & 0xff;
- pend[-2] = (bits >> 8) & 0xff;
- pend[-3] = (bits >> 16) & 0xff;
- pend[-4] = (bits >> 24) & 0xff;
- return blocks;
-}
-
-static const unsigned int pSHA256InitState[8] =
-{0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19};
-
-void SHA256Transform(void* pstate, void* pinput, const void* pinit)
-{
- SHA256_CTX ctx;
- unsigned char data[64];
-
- SHA256_Init(&ctx);
-
- for (int i = 0; i < 16; i++)
- ((uint32_t*)data)[i] = ByteReverse(((uint32_t*)pinput)[i]);
-
- for (int i = 0; i < 8; i++)
- ctx.h[i] = ((uint32_t*)pinit)[i];
-
- SHA256_Update(&ctx, data, sizeof(data));
- for (int i = 0; i < 8; i++)
- ((uint32_t*)pstate)[i] = ctx.h[i];
-}
-
-// Some explaining would be appreciated
+//
+// Unconfirmed transactions in the memory pool often depend on other
+// transactions in the memory pool. When we select transactions from the
+// pool, we select by highest priority or fee rate, so we might consider
+// transactions that depend on transactions that aren't yet in the block.
+// The COrphan class keeps track of these 'temporary orphans' while
+// CreateBlock is figuring out which transactions to include.
+//
class COrphan
{
public:
const CTransaction* ptx;
set<uint256> setDependsOn;
+ CFeeRate feeRate;
double dPriority;
- double dFeePerKb;
- COrphan(const CTransaction* ptxIn)
+ COrphan(const CTransaction* ptxIn) : ptx(ptxIn), feeRate(0), dPriority(0)
{
- ptx = ptxIn;
- dPriority = dFeePerKb = 0;
}
void print() const
{
- LogPrintf("COrphan(hash=%s, dPriority=%.1f, dFeePerKb=%.1f)\n",
- ptx->GetHash().ToString(), dPriority, dFeePerKb);
+ LogPrintf("COrphan(hash=%s, dPriority=%.1f, fee=%s)\n",
+ ptx->GetHash().ToString(), dPriority, feeRate.ToString());
BOOST_FOREACH(uint256 hash, setDependsOn)
LogPrintf(" setDependsOn %s\n", hash.ToString());
}
};
-
uint64_t nLastBlockTx = 0;
uint64_t nLastBlockSize = 0;
-// We want to sort transactions by priority and fee, so:
-typedef boost::tuple<double, double, const CTransaction*> TxPriority;
+// We want to sort transactions by priority and fee rate, so:
+typedef boost::tuple<double, CFeeRate, const CTransaction*> TxPriority;
class TxPriorityCompare
{
bool byFee;
+
public:
TxPriorityCompare(bool _byFee) : byFee(_byFee) { }
+
bool operator()(const TxPriority& a, const TxPriority& b)
{
if (byFee)
@@ -113,14 +90,14 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
CBlock *pblock = &pblocktemplate->block; // pointer for convenience
// Create coinbase tx
- CTransaction txNew;
+ CMutableTransaction txNew;
txNew.vin.resize(1);
txNew.vin[0].prevout.SetNull();
txNew.vout.resize(1);
txNew.vout[0].scriptPubKey = scriptPubKeyIn;
- // Add our coinbase tx as first transaction
- pblock->vtx.push_back(txNew);
+ // Add dummy coinbase tx as first transaction
+ pblock->vtx.push_back(CTransaction());
pblocktemplate->vTxFees.push_back(-1); // updated at end
pblocktemplate->vTxSigOps.push_back(-1); // updated at end
@@ -141,6 +118,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
// Collect memory pool transactions into the block
int64_t nFees = 0;
+
{
LOCK2(cs_main, mempool.cs);
CBlockIndex* pindexPrev = chainActive.Tip();
@@ -210,18 +188,18 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
unsigned int nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);
dPriority = tx.ComputePriority(dPriority, nTxSize);
- // This is a more accurate fee-per-kilobyte than is used by the client code, because the
- // client code rounds up the size to the nearest 1K. That's good, because it gives an
- // incentive to create smaller transactions.
- double dFeePerKb = double(nTotalIn-tx.GetValueOut()) / (double(nTxSize)/1000.0);
+ uint256 hash = tx.GetHash();
+ mempool.ApplyDeltas(hash, dPriority, nTotalIn);
+
+ CFeeRate feeRate(nTotalIn-tx.GetValueOut(), nTxSize);
if (porphan)
{
porphan->dPriority = dPriority;
- porphan->dFeePerKb = dFeePerKb;
+ porphan->feeRate = feeRate;
}
else
- vecPriority.push_back(TxPriority(dPriority, dFeePerKb, &mi->second.GetTx()));
+ vecPriority.push_back(TxPriority(dPriority, feeRate, &mi->second.GetTx()));
}
// Collect transactions into block
@@ -237,7 +215,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
{
// Take highest priority transaction off the priority queue:
double dPriority = vecPriority.front().get<0>();
- double dFeePerKb = vecPriority.front().get<1>();
+ CFeeRate feeRate = vecPriority.front().get<1>();
const CTransaction& tx = *(vecPriority.front().get<2>());
std::pop_heap(vecPriority.begin(), vecPriority.end(), comparer);
@@ -254,10 +232,14 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
continue;
// Skip free transactions if we're past the minimum block size:
- if (fSortedByFee && (dFeePerKb < CTransaction::nMinRelayTxFee) && (nBlockSize + nTxSize >= nBlockMinSize))
+ const uint256& hash = tx.GetHash();
+ double dPriorityDelta = 0;
+ int64_t nFeeDelta = 0;
+ mempool.ApplyDeltas(hash, dPriorityDelta, nFeeDelta);
+ if (fSortedByFee && (dPriorityDelta <= 0) && (nFeeDelta <= 0) && (feeRate < ::minRelayTxFee) && (nBlockSize + nTxSize >= nBlockMinSize))
continue;
- // Prioritize by fee once past the priority size or we run out of high-priority
+ // Prioritise by fee once past the priority size or we run out of high-priority
// transactions:
if (!fSortedByFee &&
((nBlockSize + nTxSize >= nBlockPrioritySize) || !AllowFree(dPriority)))
@@ -284,8 +266,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
continue;
CTxUndo txundo;
- uint256 hash = tx.GetHash();
- UpdateCoins(tx, state, view, txundo, pindexPrev->nHeight+1, hash);
+ UpdateCoins(tx, state, view, txundo, pindexPrev->nHeight+1);
// Added
pblock->vtx.push_back(tx);
@@ -298,8 +279,8 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
if (fPrintPriority)
{
- LogPrintf("priority %.1f feeperkb %.1f txid %s\n",
- dPriority, dFeePerKb, tx.GetHash().ToString());
+ LogPrintf("priority %.1f fee %s txid %s\n",
+ dPriority, feeRate.ToString(), tx.GetHash().ToString());
}
// Add transactions that depend on this one to the priority queue
@@ -312,7 +293,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
porphan->setDependsOn.erase(hash);
if (porphan->setDependsOn.empty())
{
- vecPriority.push_back(TxPriority(porphan->dPriority, porphan->dFeePerKb, porphan->ptx));
+ vecPriority.push_back(TxPriority(porphan->dPriority, porphan->feeRate, porphan->ptx));
std::push_heap(vecPriority.begin(), vecPriority.end(), comparer);
}
}
@@ -324,7 +305,10 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
nLastBlockSize = nBlockSize;
LogPrintf("CreateNewBlock(): total size %u\n", nBlockSize);
- pblock->vtx[0].vout[0].nValue = GetBlockValue(pindexPrev->nHeight+1, nFees);
+ // Compute final coinbase transaction.
+ txNew.vout[0].nValue = GetBlockValue(pindexPrev->nHeight+1, nFees);
+ txNew.vin[0].scriptSig = CScript() << OP_0 << OP_0;
+ pblock->vtx[0] = txNew;
pblocktemplate->vTxFees[0] = -nFees;
// Fill in header
@@ -332,7 +316,6 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
UpdateTime(*pblock, pindexPrev);
pblock->nBits = GetNextWorkRequired(pindexPrev, pblock);
pblock->nNonce = 0;
- pblock->vtx[0].vin[0].scriptSig = CScript() << OP_0 << OP_0;
pblocktemplate->vTxSigOps[0] = GetLegacySigOpCount(pblock->vtx[0]);
CBlockIndex indexDummy(*pblock);
@@ -358,58 +341,14 @@ void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int&
}
++nExtraNonce;
unsigned int nHeight = pindexPrev->nHeight+1; // Height first in coinbase required for block.version=2
- pblock->vtx[0].vin[0].scriptSig = (CScript() << nHeight << CScriptNum(nExtraNonce)) + COINBASE_FLAGS;
- assert(pblock->vtx[0].vin[0].scriptSig.size() <= 100);
+ CMutableTransaction txCoinbase(pblock->vtx[0]);
+ txCoinbase.vin[0].scriptSig = (CScript() << nHeight << CScriptNum(nExtraNonce)) + COINBASE_FLAGS;
+ assert(txCoinbase.vin[0].scriptSig.size() <= 100);
+ pblock->vtx[0] = txCoinbase;
pblock->hashMerkleRoot = pblock->BuildMerkleTree();
}
-
-void FormatHashBuffers(CBlock* pblock, char* pmidstate, char* pdata, char* phash1)
-{
- //
- // Pre-build hash buffers
- //
- struct
- {
- struct unnamed2
- {
- int nVersion;
- uint256 hashPrevBlock;
- uint256 hashMerkleRoot;
- unsigned int nTime;
- unsigned int nBits;
- unsigned int nNonce;
- }
- block;
- unsigned char pchPadding0[64];
- uint256 hash1;
- unsigned char pchPadding1[64];
- }
- tmp;
- memset(&tmp, 0, sizeof(tmp));
-
- tmp.block.nVersion = pblock->nVersion;
- tmp.block.hashPrevBlock = pblock->hashPrevBlock;
- tmp.block.hashMerkleRoot = pblock->hashMerkleRoot;
- tmp.block.nTime = pblock->nTime;
- tmp.block.nBits = pblock->nBits;
- tmp.block.nNonce = pblock->nNonce;
-
- FormatHashBlocks(&tmp.block, sizeof(tmp.block));
- FormatHashBlocks(&tmp.hash1, sizeof(tmp.hash1));
-
- // Byte swap all the input buffer
- for (unsigned int i = 0; i < sizeof(tmp)/4; i++)
- ((unsigned int*)&tmp)[i] = ByteReverse(((unsigned int*)&tmp)[i]);
-
- // Precalc the first half of the first hash, which stays constant
- SHA256Transform(pmidstate, &tmp.block, pSHA256InitState);
-
- memcpy(pdata, &tmp.block, 128);
- memcpy(phash1, &tmp.hash1, 64);
-}
-
#ifdef ENABLE_WALLET
//////////////////////////////////////////////////////////////////////////////
//
@@ -420,34 +359,34 @@ int64_t nHPSTimerStart = 0;
//
// ScanHash scans nonces looking for a hash with at least some zero bits.
-// It operates on big endian data. Caller does the byte reversing.
-// All input buffers are 16-byte aligned. nNonce is usually preserved
-// between calls, but periodically or if nNonce is 0xffff0000 or above,
-// the block is rebuilt and nNonce starts over at zero.
+// The nonce is usually preserved between calls, but periodically or if the
+// nonce is 0xffff0000 or above, the block is rebuilt and nNonce starts over at
+// zero.
//
-unsigned int static ScanHash_CryptoPP(char* pmidstate, char* pdata, char* phash1, char* phash, unsigned int& nHashesDone)
+bool static ScanHash(const CBlockHeader *pblock, uint32_t& nNonce, uint256 *phash)
{
- unsigned int& nNonce = *(unsigned int*)(pdata + 12);
- for (;;)
- {
- // Crypto++ SHA256
- // Hash pdata using pmidstate as the starting state into
- // pre-formatted buffer phash1, then hash phash1 into phash
+ // Write the first 76 bytes of the block header to a double-SHA256 state.
+ CHash256 hasher;
+ CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
+ ss << *pblock;
+ assert(ss.size() == 80);
+ hasher.Write((unsigned char*)&ss[0], 76);
+
+ while (true) {
nNonce++;
- SHA256Transform(phash1, pdata, pmidstate);
- SHA256Transform(phash, phash1, pSHA256InitState);
+
+ // Write the last 4 bytes of the block header (the nonce) to a copy of
+ // the double-SHA256 state, and compute the result.
+ CHash256(hasher).Write((unsigned char*)&nNonce, 4).Finalize((unsigned char*)phash);
// Return the nonce if the hash has at least some zero bits,
// caller will check if it has enough to reach the target
- if (((unsigned short*)phash)[14] == 0)
- return nNonce;
+ if (((uint16_t*)phash)[15] == 0)
+ return true;
// If nothing found after trying for a while, return -1
if ((nNonce & 0xffff) == 0)
- {
- nHashesDone = 0xffff+1;
- return (unsigned int) -1;
- }
+ return false;
if ((nNonce & 0xfff) == 0)
boost::this_thread::interruption_point();
}
@@ -482,22 +421,22 @@ bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey)
LOCK(cs_main);
if (pblock->hashPrevBlock != chainActive.Tip()->GetBlockHash())
return error("BitcoinMiner : generated block is stale");
+ }
- // Remove key from key pool
- reservekey.KeepKey();
+ // Remove key from key pool
+ reservekey.KeepKey();
- // Track how many getdata requests this block gets
- {
- LOCK(wallet.cs_wallet);
- wallet.mapRequestCount[pblock->GetHash()] = 0;
- }
-
- // Process this block the same as if we had received it from another node
- CValidationState state;
- if (!ProcessBlock(state, NULL, pblock))
- return error("BitcoinMiner : ProcessBlock, block not accepted");
+ // Track how many getdata requests this block gets
+ {
+ LOCK(wallet.cs_wallet);
+ wallet.mapRequestCount[pblock->GetHash()] = 0;
}
+ // Process this block the same as if we had received it from another node
+ CValidationState state;
+ if (!ProcessBlock(state, NULL, pblock))
+ return error("BitcoinMiner : ProcessBlock, block not accepted");
+
return true;
}
@@ -511,135 +450,115 @@ void static BitcoinMiner(CWallet *pwallet)
CReserveKey reservekey(pwallet);
unsigned int nExtraNonce = 0;
- try { while (true) {
- if (Params().NetworkID() != CChainParams::REGTEST) {
- // Busy-wait for the network to come online so we don't waste time mining
- // on an obsolete chain. In regtest mode we expect to fly solo.
- while (vNodes.empty())
- MilliSleep(1000);
- }
-
- //
- // Create new block
- //
- unsigned int nTransactionsUpdatedLast = mempool.GetTransactionsUpdated();
- CBlockIndex* pindexPrev = chainActive.Tip();
-
- auto_ptr<CBlockTemplate> pblocktemplate(CreateNewBlockWithKey(reservekey));
- if (!pblocktemplate.get())
- return;
- CBlock *pblock = &pblocktemplate->block;
- IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
-
- LogPrintf("Running BitcoinMiner with %u transactions in block (%u bytes)\n", pblock->vtx.size(),
- ::GetSerializeSize(*pblock, SER_NETWORK, PROTOCOL_VERSION));
-
- //
- // Pre-build hash buffers
- //
- char pmidstatebuf[32+16]; char* pmidstate = alignup<16>(pmidstatebuf);
- char pdatabuf[128+16]; char* pdata = alignup<16>(pdatabuf);
- char phash1buf[64+16]; char* phash1 = alignup<16>(phash1buf);
-
- FormatHashBuffers(pblock, pmidstate, pdata, phash1);
-
- unsigned int& nBlockTime = *(unsigned int*)(pdata + 64 + 4);
- unsigned int& nBlockBits = *(unsigned int*)(pdata + 64 + 8);
- unsigned int& nBlockNonce = *(unsigned int*)(pdata + 64 + 12);
-
-
- //
- // Search
- //
- int64_t nStart = GetTime();
- uint256 hashTarget = uint256().SetCompact(pblock->nBits);
- uint256 hashbuf[2];
- uint256& hash = *alignup<16>(hashbuf);
- while (true)
- {
- unsigned int nHashesDone = 0;
- unsigned int nNonceFound;
-
- // Crypto++ SHA256
- nNonceFound = ScanHash_CryptoPP(pmidstate, pdata + 64, phash1,
- (char*)&hash, nHashesDone);
-
- // Check if something found
- if (nNonceFound != (unsigned int) -1)
- {
- for (unsigned int i = 0; i < sizeof(hash)/4; i++)
- ((unsigned int*)&hash)[i] = ByteReverse(((unsigned int*)&hash)[i]);
+ try {
+ while (true) {
+ if (Params().MiningRequiresPeers()) {
+ // Busy-wait for the network to come online so we don't waste time mining
+ // on an obsolete chain. In regtest mode we expect to fly solo.
+ while (vNodes.empty())
+ MilliSleep(1000);
+ }
- if (hash <= hashTarget)
+ //
+ // Create new block
+ //
+ unsigned int nTransactionsUpdatedLast = mempool.GetTransactionsUpdated();
+ CBlockIndex* pindexPrev = chainActive.Tip();
+
+ auto_ptr<CBlockTemplate> pblocktemplate(CreateNewBlockWithKey(reservekey));
+ if (!pblocktemplate.get())
+ return;
+ CBlock *pblock = &pblocktemplate->block;
+ IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
+
+ LogPrintf("Running BitcoinMiner with %u transactions in block (%u bytes)\n", pblock->vtx.size(),
+ ::GetSerializeSize(*pblock, SER_NETWORK, PROTOCOL_VERSION));
+
+ //
+ // Search
+ //
+ int64_t nStart = GetTime();
+ uint256 hashTarget = uint256().SetCompact(pblock->nBits);
+ uint256 hash;
+ uint32_t nNonce = 0;
+ uint32_t nOldNonce = 0;
+ while (true) {
+ bool fFound = ScanHash(pblock, nNonce, &hash);
+ uint32_t nHashesDone = nNonce - nOldNonce;
+ nOldNonce = nNonce;
+
+ // Check if something found
+ if (fFound)
{
- // Found a solution
- pblock->nNonce = ByteReverse(nNonceFound);
- assert(hash == pblock->GetHash());
+ if (hash <= hashTarget)
+ {
+ // Found a solution
+ pblock->nNonce = nNonce;
+ assert(hash == pblock->GetHash());
- SetThreadPriority(THREAD_PRIORITY_NORMAL);
- CheckWork(pblock, *pwallet, reservekey);
- SetThreadPriority(THREAD_PRIORITY_LOWEST);
+ SetThreadPriority(THREAD_PRIORITY_NORMAL);
+ CheckWork(pblock, *pwallet, reservekey);
+ SetThreadPriority(THREAD_PRIORITY_LOWEST);
- // In regression test mode, stop mining after a block is found. This
- // allows developers to controllably generate a block on demand.
- if (Params().NetworkID() == CChainParams::REGTEST)
- throw boost::thread_interrupted();
+ // In regression test mode, stop mining after a block is found.
+ if (Params().MineBlocksOnDemand())
+ throw boost::thread_interrupted();
- break;
+ break;
+ }
}
- }
- // Meter hashes/sec
- static int64_t nHashCounter;
- if (nHPSTimerStart == 0)
- {
- nHPSTimerStart = GetTimeMillis();
- nHashCounter = 0;
- }
- else
- nHashCounter += nHashesDone;
- if (GetTimeMillis() - nHPSTimerStart > 4000)
- {
- static CCriticalSection cs;
+ // Meter hashes/sec
+ static int64_t nHashCounter;
+ if (nHPSTimerStart == 0)
{
- LOCK(cs);
- if (GetTimeMillis() - nHPSTimerStart > 4000)
+ nHPSTimerStart = GetTimeMillis();
+ nHashCounter = 0;
+ }
+ else
+ nHashCounter += nHashesDone;
+ if (GetTimeMillis() - nHPSTimerStart > 4000)
+ {
+ static CCriticalSection cs;
{
- dHashesPerSec = 1000.0 * nHashCounter / (GetTimeMillis() - nHPSTimerStart);
- nHPSTimerStart = GetTimeMillis();
- nHashCounter = 0;
- static int64_t nLogTime;
- if (GetTime() - nLogTime > 30 * 60)
+ LOCK(cs);
+ if (GetTimeMillis() - nHPSTimerStart > 4000)
{
- nLogTime = GetTime();
- LogPrintf("hashmeter %6.0f khash/s\n", dHashesPerSec/1000.0);
+ dHashesPerSec = 1000.0 * nHashCounter / (GetTimeMillis() - nHPSTimerStart);
+ nHPSTimerStart = GetTimeMillis();
+ nHashCounter = 0;
+ static int64_t nLogTime;
+ if (GetTime() - nLogTime > 30 * 60)
+ {
+ nLogTime = GetTime();
+ LogPrintf("hashmeter %6.0f khash/s\n", dHashesPerSec/1000.0);
+ }
}
}
}
- }
- // Check for stop or if block needs to be rebuilt
- boost::this_thread::interruption_point();
- if (vNodes.empty() && Params().NetworkID() != CChainParams::REGTEST)
- break;
- if (nBlockNonce >= 0xffff0000)
- break;
- if (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 60)
- break;
- if (pindexPrev != chainActive.Tip())
- break;
-
- // Update nTime every few seconds
- UpdateTime(*pblock, pindexPrev);
- nBlockTime = ByteReverse(pblock->nTime);
- if (TestNet())
- {
- // Changing pblock->nTime can change work required on testnet:
- nBlockBits = ByteReverse(pblock->nBits);
- hashTarget.SetCompact(pblock->nBits);
+ // Check for stop or if block needs to be rebuilt
+ boost::this_thread::interruption_point();
+ // Regtest mode doesn't require peers
+ if (vNodes.empty() && Params().MiningRequiresPeers())
+ break;
+ if (nNonce >= 0xffff0000)
+ break;
+ if (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 60)
+ break;
+ if (pindexPrev != chainActive.Tip())
+ break;
+
+ // Update nTime every few seconds
+ UpdateTime(*pblock, pindexPrev);
+ if (Params().AllowMinDifficultyBlocks())
+ {
+ // Changing pblock->nTime can change work required on testnet:
+ hashTarget.SetCompact(pblock->nBits);
+ }
}
}
- } }
+ }
catch (boost::thread_interrupted)
{
LogPrintf("BitcoinMiner terminated\n");
@@ -652,8 +571,9 @@ void GenerateBitcoins(bool fGenerate, CWallet* pwallet, int nThreads)
static boost::thread_group* minerThreads = NULL;
if (nThreads < 0) {
- if (Params().NetworkID() == CChainParams::REGTEST)
- nThreads = 1;
+ // In regtest threads defaults to 1
+ if (Params().DefaultMinerThreads())
+ nThreads = Params().DefaultMinerThreads();
else
nThreads = boost::thread::hardware_concurrency();
}
@@ -673,5 +593,4 @@ void GenerateBitcoins(bool fGenerate, CWallet* pwallet, int nThreads)
minerThreads->create_thread(boost::bind(&BitcoinMiner, pwallet));
}
-#endif
-
+#endif // ENABLE_WALLET
diff --git a/src/miner.h b/src/miner.h
index 26151f6cd5..1fa499dc5b 100644
--- a/src/miner.h
+++ b/src/miner.h
@@ -10,11 +10,12 @@
class CBlock;
class CBlockIndex;
-struct CBlockTemplate;
class CReserveKey;
class CScript;
class CWallet;
+struct CBlockTemplate;
+
/** Run the miner threads */
void GenerateBitcoins(bool fGenerate, CWallet* pwallet, int nThreads);
/** Generate a new block, without valid proof-of-work */
@@ -22,12 +23,8 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn);
CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey);
/** Modify the extranonce in a block */
void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& nExtraNonce);
-/** Do mining precalculation */
-void FormatHashBuffers(CBlock* pblock, char* pmidstate, char* pdata, char* phash1);
/** Check mined block */
bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey);
-/** Base sha256 mining transform */
-void SHA256Transform(void* pstate, void* pinput, const void* pinit);
extern double dHashesPerSec;
extern int64_t nHPSTimerStart;
diff --git a/src/mruset.h b/src/mruset.h
index c36a0c8f37..c1c08b0288 100644
--- a/src/mruset.h
+++ b/src/mruset.h
@@ -32,6 +32,7 @@ public:
bool empty() const { return set.empty(); }
iterator find(const key_type& k) const { return set.find(k); }
size_type count(const key_type& k) const { return set.count(k); }
+ void clear() { set.clear(); queue.clear(); }
bool inline friend operator==(const mruset<T>& a, const mruset<T>& b) { return a.set == b.set; }
bool inline friend operator==(const mruset<T>& a, const std::set<T>& b) { return a.set == b; }
bool inline friend operator<(const mruset<T>& a, const mruset<T>& b) { return a.set < b.set; }
diff --git a/src/net.cpp b/src/net.cpp
index 4cbd26a563..6a660dc9bd 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -4,7 +4,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#if defined(HAVE_CONFIG_H)
-#include "bitcoin-config.h"
+#include "config/bitcoin-config.h"
#endif
#include "net.h"
@@ -36,18 +36,27 @@
#define MSG_NOSIGNAL 0
#endif
+// Fix for ancient MinGW versions, that don't have defined these in ws2tcpip.h.
+// Todo: Can be removed when our pull-tester is upgraded to a modern MinGW version.
+#ifdef WIN32
+#ifndef PROTECTION_LEVEL_UNRESTRICTED
+#define PROTECTION_LEVEL_UNRESTRICTED 10
+#endif
+#ifndef IPV6_PROTECTION_LEVEL
+#define IPV6_PROTECTION_LEVEL 23
+#endif
+#endif
+
using namespace std;
using namespace boost;
static const int MAX_OUTBOUND_CONNECTIONS = 8;
-bool OpenNetworkConnection(const CAddress& addrConnect, CSemaphoreGrant *grantOutbound = NULL, const char *strDest = NULL, bool fOneShot = false);
-
-
//
// Global state variables
//
bool fDiscover = true;
+bool fListen = true;
uint64_t nLocalServices = NODE_NETWORK;
CCriticalSection cs_mapLocalHost;
map<CNetAddr, LocalServiceInfo> mapLocalHost;
@@ -99,7 +108,7 @@ unsigned short GetListenPort()
// find 'best' local address for a particular peer
bool GetLocal(CService& addr, const CNetAddr *paddrPeer)
{
- if (fNoListen)
+ if (!fListen)
return false;
int nBestScore = -1;
@@ -471,11 +480,10 @@ CNode* ConnectNode(CAddress addrConnect, const char *pszDest)
}
}
-
/// debug print
LogPrint("net", "trying connection %s lastseen=%.1fhrs\n",
pszDest ? pszDest : addrConnect.ToString(),
- pszDest ? 0 : (double)(GetAdjustedTime() - addrConnect.nTime)/3600.0);
+ pszDest ? 0.0 : (double)(GetAdjustedTime() - addrConnect.nTime)/3600.0);
// Connect
SOCKET hSocket;
@@ -483,8 +491,6 @@ CNode* ConnectNode(CAddress addrConnect, const char *pszDest)
{
addrman.Attempt(addrConnect);
- LogPrint("net", "connected %s\n", pszDest ? pszDest : addrConnect.ToString());
-
// Set to non-blocking
#ifdef WIN32
u_long nOne = 1;
@@ -505,12 +511,11 @@ CNode* ConnectNode(CAddress addrConnect, const char *pszDest)
}
pnode->nTimeConnected = GetTime();
+
return pnode;
}
- else
- {
- return NULL;
- }
+
+ return NULL;
}
void CNode::CloseSocketDisconnect()
@@ -518,7 +523,7 @@ void CNode::CloseSocketDisconnect()
fDisconnect = true;
if (hSocket != INVALID_SOCKET)
{
- LogPrint("net", "disconnecting node %s\n", addrName);
+ LogPrint("net", "disconnecting peer=%d\n", id);
closesocket(hSocket);
hSocket = INVALID_SOCKET;
}
@@ -533,11 +538,6 @@ void CNode::CloseSocketDisconnect()
pnodeSync = NULL;
}
-void CNode::Cleanup()
-{
-}
-
-
void CNode::PushVersion()
{
int nBestHeight = g_signals.GetHeight().get_value_or(0);
@@ -547,7 +547,10 @@ void CNode::PushVersion()
CAddress addrYou = (addr.IsRoutable() && !IsProxy(addr) ? addr : CAddress(CService("0.0.0.0",0)));
CAddress addrMe = GetLocalAddress(&addr);
RAND_bytes((unsigned char*)&nLocalHostNonce, sizeof(nLocalHostNonce));
- LogPrint("net", "send version message: version %d, blocks=%d, us=%s, them=%s, peer=%s\n", PROTOCOL_VERSION, nBestHeight, addrMe.ToString(), addrYou.ToString(), addr.ToString());
+ if (fLogIPs)
+ LogPrint("net", "send version message: version %d, blocks=%d, us=%s, them=%s, peer=%d\n", PROTOCOL_VERSION, nBestHeight, addrMe.ToString(), addrYou.ToString(), id);
+ else
+ LogPrint("net", "send version message: version %d, blocks=%d, us=%s, peer=%d\n", PROTOCOL_VERSION, nBestHeight, addrMe.ToString(), id);
PushMessage("version", PROTOCOL_VERSION, nLocalServices, nTime, addrYou, addrMe,
nLocalHostNonce, FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, std::vector<string>()), nBestHeight, true);
}
@@ -652,6 +655,9 @@ bool CNode::ReceiveMsgBytes(const char *pch, unsigned int nBytes)
pch += handled;
nBytes -= handled;
+
+ if (msg.complete())
+ msg.nTime = GetTimeMicros();
}
return true;
@@ -684,7 +690,6 @@ int CNetMessage::readHeader(const char *pch, unsigned int nBytes)
// switch state to reading message data
in_data = true;
- vRecv.resize(hdr.nMessageSize);
return nCopy;
}
@@ -694,6 +699,11 @@ int CNetMessage::readData(const char *pch, unsigned int nBytes)
unsigned int nRemaining = hdr.nMessageSize - nDataPos;
unsigned int nCopy = std::min(nRemaining, nBytes);
+ if (vRecv.size() < nDataPos + nCopy) {
+ // Allocate up to 256 KiB ahead, but never more than the total message size.
+ vRecv.resize(std::min(hdr.nMessageSize, nDataPos + nCopy + 256 * 1024));
+ }
+
memcpy(&vRecv[nDataPos], pch, nCopy);
nDataPos += nCopy;
@@ -779,7 +789,6 @@ void ThreadSocketHandler()
// close socket and cleanup
pnode->CloseSocketDisconnect();
- pnode->Cleanup();
// hold in disconnected pool until all refs are released
if (pnode->fNetworkNode || pnode->fInbound)
@@ -823,7 +832,6 @@ void ThreadSocketHandler()
uiInterface.NotifyNumConnectionsChanged(nPrevNodeCount);
}
-
//
// Find which sockets have data to receive
//
@@ -845,6 +853,7 @@ void ThreadSocketHandler()
hSocketMax = max(hSocketMax, hListenSocket);
have_fds = true;
}
+
{
LOCK(cs_vNodes);
BOOST_FOREACH(CNode* pnode, vNodes)
@@ -905,58 +914,58 @@ void ThreadSocketHandler()
MilliSleep(timeout.tv_usec/1000);
}
-
//
// Accept new connections
//
BOOST_FOREACH(SOCKET hListenSocket, vhListenSocket)
- if (hListenSocket != INVALID_SOCKET && FD_ISSET(hListenSocket, &fdsetRecv))
{
- struct sockaddr_storage sockaddr;
- socklen_t len = sizeof(sockaddr);
- SOCKET hSocket = accept(hListenSocket, (struct sockaddr*)&sockaddr, &len);
- CAddress addr;
- int nInbound = 0;
-
- if (hSocket != INVALID_SOCKET)
- if (!addr.SetSockAddr((const struct sockaddr*)&sockaddr))
- LogPrintf("Warning: Unknown socket family\n");
-
+ if (hListenSocket != INVALID_SOCKET && FD_ISSET(hListenSocket, &fdsetRecv))
{
- LOCK(cs_vNodes);
- BOOST_FOREACH(CNode* pnode, vNodes)
- if (pnode->fInbound)
- nInbound++;
- }
+ struct sockaddr_storage sockaddr;
+ socklen_t len = sizeof(sockaddr);
+ SOCKET hSocket = accept(hListenSocket, (struct sockaddr*)&sockaddr, &len);
+ CAddress addr;
+ int nInbound = 0;
+
+ if (hSocket != INVALID_SOCKET)
+ if (!addr.SetSockAddr((const struct sockaddr*)&sockaddr))
+ LogPrintf("Warning: Unknown socket family\n");
- if (hSocket == INVALID_SOCKET)
- {
- int nErr = WSAGetLastError();
- if (nErr != WSAEWOULDBLOCK)
- LogPrintf("socket error accept failed: %s\n", NetworkErrorString(nErr));
- }
- else if (nInbound >= nMaxConnections - MAX_OUTBOUND_CONNECTIONS)
- {
- closesocket(hSocket);
- }
- else if (CNode::IsBanned(addr))
- {
- LogPrintf("connection from %s dropped (banned)\n", addr.ToString());
- closesocket(hSocket);
- }
- else
- {
- LogPrint("net", "accepted connection %s\n", addr.ToString());
- CNode* pnode = new CNode(hSocket, addr, "", true);
- pnode->AddRef();
{
LOCK(cs_vNodes);
- vNodes.push_back(pnode);
+ BOOST_FOREACH(CNode* pnode, vNodes)
+ if (pnode->fInbound)
+ nInbound++;
+ }
+
+ if (hSocket == INVALID_SOCKET)
+ {
+ int nErr = WSAGetLastError();
+ if (nErr != WSAEWOULDBLOCK)
+ LogPrintf("socket error accept failed: %s\n", NetworkErrorString(nErr));
+ }
+ else if (nInbound >= nMaxConnections - MAX_OUTBOUND_CONNECTIONS)
+ {
+ closesocket(hSocket);
+ }
+ else if (CNode::IsBanned(addr))
+ {
+ LogPrintf("connection from %s dropped (banned)\n", addr.ToString());
+ closesocket(hSocket);
+ }
+ else
+ {
+ CNode* pnode = new CNode(hSocket, addr, "", true);
+ pnode->AddRef();
+
+ {
+ LOCK(cs_vNodes);
+ vNodes.push_back(pnode);
+ }
}
}
}
-
//
// Service each socket
//
@@ -1030,23 +1039,27 @@ void ThreadSocketHandler()
//
// Inactivity checking
//
- if (pnode->vSendMsg.empty())
- pnode->nLastSendEmpty = GetTime();
- if (GetTime() - pnode->nTimeConnected > 60)
+ int64_t nTime = GetTime();
+ if (nTime - pnode->nTimeConnected > 60)
{
if (pnode->nLastRecv == 0 || pnode->nLastSend == 0)
{
- LogPrint("net", "socket no message in first 60 seconds, %d %d\n", pnode->nLastRecv != 0, pnode->nLastSend != 0);
+ LogPrint("net", "socket no message in first 60 seconds, %d %d from %d\n", pnode->nLastRecv != 0, pnode->nLastSend != 0, pnode->id);
pnode->fDisconnect = true;
}
- else if (GetTime() - pnode->nLastSend > 90*60 && GetTime() - pnode->nLastSendEmpty > 90*60)
+ else if (nTime - pnode->nLastSend > TIMEOUT_INTERVAL)
{
- LogPrintf("socket not sending\n");
+ LogPrintf("socket sending timeout: %is\n", nTime - pnode->nLastSend);
pnode->fDisconnect = true;
}
- else if (GetTime() - pnode->nLastRecv > 90*60)
+ else if (nTime - pnode->nLastRecv > (pnode->nVersion > BIP0031_VERSION ? TIMEOUT_INTERVAL : 90*60))
{
- LogPrintf("socket inactivity timeout\n");
+ LogPrintf("socket receive timeout: %is\n", nTime - pnode->nLastRecv);
+ pnode->fDisconnect = true;
+ }
+ else if (pnode->nPingNonceSent && pnode->nPingUsecStart + TIMEOUT_INTERVAL * 1000000 < GetTimeMicros())
+ {
+ LogPrintf("ping timeout: %fs\n", 0.000001 * (GetTimeMicros() - pnode->nPingUsecStart));
pnode->fDisconnect = true;
}
}
@@ -1427,21 +1440,21 @@ void ThreadOpenAddedConnections()
}
// if successful, this moves the passed grant to the constructed node
-bool OpenNetworkConnection(const CAddress& addrConnect, CSemaphoreGrant *grantOutbound, const char *strDest, bool fOneShot)
+bool OpenNetworkConnection(const CAddress& addrConnect, CSemaphoreGrant *grantOutbound, const char *pszDest, bool fOneShot)
{
//
// Initiate outbound network connection
//
boost::this_thread::interruption_point();
- if (!strDest)
+ if (!pszDest) {
if (IsLocal(addrConnect) ||
FindNode((CNetAddr)addrConnect) || CNode::IsBanned(addrConnect) ||
FindNode(addrConnect.ToStringIPPort().c_str()))
return false;
- if (strDest && FindNode(strDest))
+ } else if (FindNode(pszDest))
return false;
- CNode* pnode = ConnectNode(addrConnect, strDest);
+ CNode* pnode = ConnectNode(addrConnect, pszDest);
boost::this_thread::interruption_point();
if (!pnode)
@@ -1458,13 +1471,13 @@ bool OpenNetworkConnection(const CAddress& addrConnect, CSemaphoreGrant *grantOu
// for now, use a very simple selection metric: the node from which we received
// most recently
-double static NodeSyncScore(const CNode *pnode) {
- return -pnode->nLastRecv;
+static int64_t NodeSyncScore(const CNode *pnode) {
+ return pnode->nLastRecv;
}
void static StartSync(const vector<CNode*> &vNodes) {
CNode *pnodeNewSync = NULL;
- double dBestScore = 0;
+ int64_t nBestScore = 0;
int nBestHeight = g_signals.GetHeight().get_value_or(0);
@@ -1476,10 +1489,10 @@ void static StartSync(const vector<CNode*> &vNodes) {
(pnode->nStartingHeight > (nBestHeight - 144)) &&
(pnode->nVersion < NOBLKS_VERSION_START || pnode->nVersion >= NOBLKS_VERSION_END)) {
// if ok, compare node's score with the best so far
- double dScore = NodeSyncScore(pnode);
- if (pnodeNewSync == NULL || dScore > dBestScore) {
+ int64_t nScore = NodeSyncScore(pnode);
+ if (pnodeNewSync == NULL || nScore > nBestScore) {
pnodeNewSync = pnode;
- dBestScore = dScore;
+ nBestScore = nScore;
}
}
}
@@ -1577,7 +1590,7 @@ bool BindListenPort(const CService &addrBind, string& strError)
socklen_t len = sizeof(sockaddr);
if (!addrBind.GetSockAddr((struct sockaddr*)&sockaddr, &len))
{
- strError = strprintf("Error: bind address family for %s not supported", addrBind.ToString());
+ strError = strprintf("Error: Bind address family for %s not supported", addrBind.ToString());
LogPrintf("%s\n", strError);
return false;
}
@@ -1590,18 +1603,16 @@ bool BindListenPort(const CService &addrBind, string& strError)
return false;
}
+#ifndef WIN32
#ifdef SO_NOSIGPIPE
// Different way of disabling SIGPIPE on BSD
setsockopt(hListenSocket, SOL_SOCKET, SO_NOSIGPIPE, (void*)&nOne, sizeof(int));
#endif
-
-#ifndef WIN32
// Allow binding if the port is still in TIME_WAIT state after
- // the program was closed and restarted. Not an issue on windows.
+ // the program was closed and restarted. Not an issue on windows!
setsockopt(hListenSocket, SOL_SOCKET, SO_REUSEADDR, (void*)&nOne, sizeof(int));
#endif
-
#ifdef WIN32
// Set to non-blocking, incoming connections will also inherit this
if (ioctlsocket(hListenSocket, FIONBIO, (u_long*)&nOne) == SOCKET_ERROR)
@@ -1625,10 +1636,8 @@ bool BindListenPort(const CService &addrBind, string& strError)
#endif
#endif
#ifdef WIN32
- int nProtLevel = 10 /* PROTECTION_LEVEL_UNRESTRICTED */;
- int nParameterId = 23 /* IPV6_PROTECTION_LEVEl */;
- // this call is allowed to fail
- setsockopt(hListenSocket, IPPROTO_IPV6, nParameterId, (const char*)&nProtLevel, sizeof(int));
+ int nProtLevel = PROTECTION_LEVEL_UNRESTRICTED;
+ setsockopt(hListenSocket, IPPROTO_IPV6, IPV6_PROTECTION_LEVEL, (const char*)&nProtLevel, sizeof(int));
#endif
}
@@ -1736,10 +1745,8 @@ void StartNode(boost::thread_group& threadGroup)
else
threadGroup.create_thread(boost::bind(&TraceThread<void (*)()>, "dnsseed", &ThreadDNSAddressSeed));
-#ifdef USE_UPNP
// Map ports with UPnP
- MapPort(GetBoolArg("-upnp", USE_UPNP));
-#endif
+ MapPort(GetBoolArg("-upnp", DEFAULT_UPNP));
// Send and receive from sockets, accept connections
threadGroup.create_thread(boost::bind(&TraceThread<void (*)()>, "net", &ThreadSocketHandler));
@@ -1773,9 +1780,8 @@ bool StopNode()
class CNetCleanup
{
public:
- CNetCleanup()
- {
- }
+ CNetCleanup() {}
+
~CNetCleanup()
{
// Close sockets
@@ -1794,6 +1800,7 @@ public:
delete pnode;
vNodes.clear();
vNodesDisconnected.clear();
+ vhListenSocket.clear();
delete semOutbound;
semOutbound = NULL;
delete pnodeLocalHost;
@@ -1813,17 +1820,17 @@ instance_of_cnetcleanup;
-void RelayTransaction(const CTransaction& tx, const uint256& hash)
+void RelayTransaction(const CTransaction& tx)
{
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
ss.reserve(10000);
ss << tx;
- RelayTransaction(tx, hash, ss);
+ RelayTransaction(tx, ss);
}
-void RelayTransaction(const CTransaction& tx, const uint256& hash, const CDataStream& ss)
+void RelayTransaction(const CTransaction& tx, const CDataStream& ss)
{
- CInv inv(MSG_TX, hash);
+ CInv inv(MSG_TX, tx.GetHash());
{
LOCK(cs_mapRelay);
// Expire old relay messages
@@ -1845,7 +1852,7 @@ void RelayTransaction(const CTransaction& tx, const uint256& hash, const CDataSt
LOCK(pnode->cs_filter);
if (pnode->pfilter)
{
- if (pnode->pfilter->IsRelevantAndUpdate(tx, hash))
+ if (pnode->pfilter->IsRelevantAndUpdate(tx))
pnode->PushInventory(inv);
} else
pnode->PushInventory(inv);
diff --git a/src/net.h b/src/net.h
index 729b1bcd57..c2a0416455 100644
--- a/src/net.h
+++ b/src/net.h
@@ -34,10 +34,22 @@ class CNode;
namespace boost {
class thread_group;
-}
+} // namespace boost
+/** Time between pings automatically sent out for latency probing and keepalive (in seconds). */
+static const int PING_INTERVAL = 2 * 60;
+/** Time after which to disconnect, after waiting for a ping response (or inactivity). */
+static const int TIMEOUT_INTERVAL = 20 * 60;
/** The maximum number of entries in an 'inv' protocol message */
static const unsigned int MAX_INV_SZ = 50000;
+/** -listen default */
+static const bool DEFAULT_LISTEN = true;
+/** -upnp default */
+#ifdef USE_UPNP
+static const bool DEFAULT_UPNP = USE_UPNP;
+#else
+static const bool DEFAULT_UPNP = false;
+#endif
inline unsigned int ReceiveFloodSize() { return 1000*GetArg("-maxreceivebuffer", 5*1000); }
inline unsigned int SendBufferSize() { return 1000*GetArg("-maxsendbuffer", 1*1000); }
@@ -48,10 +60,11 @@ bool GetMyExternalIP(CNetAddr& ipRet);
void AddressCurrentlyConnected(const CService& addr);
CNode* FindNode(const CNetAddr& ip);
CNode* FindNode(const CService& ip);
-CNode* ConnectNode(CAddress addrConnect, const char *strDest = NULL);
+CNode* ConnectNode(CAddress addrConnect, const char *pszDest = NULL);
+bool OpenNetworkConnection(const CAddress& addrConnect, CSemaphoreGrant *grantOutbound = NULL, const char *strDest = NULL, bool fOneShot = false);
void MapPort(bool fUseUPnP);
unsigned short GetListenPort();
-bool BindListenPort(const CService &bindAddr, std::string& strError=REF(std::string()));
+bool BindListenPort(const CService &bindAddr, std::string& strError);
void StartNode(boost::thread_group& threadGroup);
bool StopNode();
void SocketSendData(CNode *pnode);
@@ -98,6 +111,7 @@ CAddress GetLocalAddress(const CNetAddr *paddrPeer = NULL);
extern bool fDiscover;
+extern bool fListen;
extern uint64_t nLocalServices;
extern uint64_t nLocalHostNonce;
extern CAddrMan addrman;
@@ -122,7 +136,7 @@ struct LocalServiceInfo {
};
extern CCriticalSection cs_mapLocalHost;
-extern map<CNetAddr, LocalServiceInfo> mapLocalHost;
+extern std::map<CNetAddr, LocalServiceInfo> mapLocalHost;
class CNodeStats
{
@@ -159,11 +173,14 @@ public:
CDataStream vRecv; // received message data
unsigned int nDataPos;
+ int64_t nTime; // time (in microseconds) of message receipt.
+
CNetMessage(int nTypeIn, int nVersionIn) : hdrbuf(nTypeIn, nVersionIn), vRecv(nTypeIn, nVersionIn) {
hdrbuf.resize(24);
in_data = false;
nHdrPos = 0;
nDataPos = 0;
+ nTime = 0;
}
bool complete() const
@@ -209,7 +226,6 @@ public:
int64_t nLastSend;
int64_t nLastRecv;
- int64_t nLastSendEmpty;
int64_t nTimeConnected;
CAddress addr;
std::string addrName;
@@ -255,7 +271,7 @@ public:
// flood relay
std::vector<CAddress> vAddrToSend;
- std::set<CAddress> setAddrKnown;
+ mruset<CAddress> setAddrKnown;
bool fGetAddr;
std::set<uint256> setKnown;
@@ -265,13 +281,17 @@ public:
CCriticalSection cs_inventory;
std::multimap<int64_t, CInv> mapAskFor;
- // Ping time measurement
+ // Ping time measurement:
+ // The pong reply we're expecting, or 0 if no pong expected.
uint64_t nPingNonceSent;
+ // Time (in usec) the last ping was sent, or 0 if no ping was ever sent.
int64_t nPingUsecStart;
+ // Last measured round-trip time.
int64_t nPingUsecTime;
+ // Whether a ping is requested.
bool fPingQueued;
- CNode(SOCKET hSocketIn, CAddress addrIn, std::string addrNameIn = "", bool fInboundIn=false) : ssSend(SER_NETWORK, INIT_PROTO_VERSION)
+ CNode(SOCKET hSocketIn, CAddress addrIn, std::string addrNameIn = "", bool fInboundIn=false) : ssSend(SER_NETWORK, INIT_PROTO_VERSION), setAddrKnown(5000)
{
nServices = 0;
hSocket = hSocketIn;
@@ -280,7 +300,6 @@ public:
nLastRecv = 0;
nSendBytes = 0;
nRecvBytes = 0;
- nLastSendEmpty = GetTime();
nTimeConnected = GetTime();
addr = addrIn;
addrName = addrNameIn == "" ? addr.ToStringIPPort() : addrNameIn;
@@ -314,6 +333,11 @@ public:
id = nLastNodeId++;
}
+ if (fLogIPs)
+ LogPrint("net", "Added connection to %s peer=%d\n", addrName, id);
+ else
+ LogPrint("net", "Added connection peer=%d\n", id);
+
// Be shy and don't send version until we hear
if (hSocket != INVALID_SOCKET && !fInbound)
PushVersion();
@@ -430,7 +454,7 @@ public:
nRequestTime = it->second;
else
nRequestTime = 0;
- LogPrint("net", "askfor %s %d (%s)\n", inv.ToString().c_str(), nRequestTime, DateTimeStrFormat("%H:%M:%S", nRequestTime/1000000).c_str());
+ LogPrint("net", "askfor %s %d (%s) peer=%d\n", inv.ToString(), nRequestTime, DateTimeStrFormat("%H:%M:%S", nRequestTime/1000000).c_str(), id);
// Make sure not to reuse time indexes to keep things in the same order
int64_t nNow = GetTimeMicros() - 1000000;
@@ -498,7 +522,7 @@ public:
assert(ssSend.size () >= CMessageHeader::CHECKSUM_OFFSET + sizeof(nChecksum));
memcpy((char*)&ssSend[CMessageHeader::CHECKSUM_OFFSET], &nChecksum, sizeof(nChecksum));
- LogPrint("net", "(%d bytes)\n", nSize);
+ LogPrint("net", "(%d bytes) peer=%d\n", nSize, id);
std::deque<CSerializeData>::iterator it = vSendMsg.insert(vSendMsg.end(), CSerializeData());
ssSend.GetAndClear(*it);
@@ -676,8 +700,6 @@ public:
void Subscribe(unsigned int nChannel, unsigned int nHops=0);
void CancelSubscribe(unsigned int nChannel);
void CloseSocketDisconnect();
- void Cleanup();
-
// Denial-of-service detection/prevention
// The idea is to detect peers that are behaving
@@ -709,8 +731,8 @@ public:
class CTransaction;
-void RelayTransaction(const CTransaction& tx, const uint256& hash);
-void RelayTransaction(const CTransaction& tx, const uint256& hash, const CDataStream& ss);
+void RelayTransaction(const CTransaction& tx);
+void RelayTransaction(const CTransaction& tx, const CDataStream& ss);
/** Access to the (IP) address database (peers.dat) */
class CAddrDB
diff --git a/src/netbase.cpp b/src/netbase.cpp
index 40ae89957a..067cfa024b 100644
--- a/src/netbase.cpp
+++ b/src/netbase.cpp
@@ -3,6 +3,14 @@
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#ifdef HAVE_CONFIG_H
+#include "bitcoin-config.h"
+#endif
+
+#ifdef HAVE_GETADDRINFO_A
+#include <netdb.h>
+#endif
+
#include "netbase.h"
#include "hash.h"
@@ -11,6 +19,9 @@
#include "util.h"
#ifndef WIN32
+#if HAVE_INET_PTON
+#include <arpa/inet.h>
+#endif
#include <fcntl.h>
#endif
@@ -25,7 +36,7 @@ using namespace std;
// Settings
static proxyType proxyInfo[NET_MAX];
-static proxyType nameproxyInfo;
+static CService nameProxy;
static CCriticalSection cs_proxyInfos;
int nConnectTimeout = 5000;
bool fNameLookup = false;
@@ -71,9 +82,30 @@ bool static LookupIntern(const char *pszName, std::vector<CNetAddr>& vIP, unsign
}
}
+#ifdef HAVE_GETADDRINFO_A
+ struct in_addr ipv4_addr;
+#ifdef HAVE_INET_PTON
+ if (inet_pton(AF_INET, pszName, &ipv4_addr) > 0) {
+ vIP.push_back(CNetAddr(ipv4_addr));
+ return true;
+ }
+
+ struct in6_addr ipv6_addr;
+ if (inet_pton(AF_INET6, pszName, &ipv6_addr) > 0) {
+ vIP.push_back(CNetAddr(ipv6_addr));
+ return true;
+ }
+#else
+ ipv4_addr.s_addr = inet_addr(pszName);
+ if (ipv4_addr.s_addr != INADDR_NONE) {
+ vIP.push_back(CNetAddr(ipv4_addr));
+ return true;
+ }
+#endif
+#endif
+
struct addrinfo aiHint;
memset(&aiHint, 0, sizeof(struct addrinfo));
-
aiHint.ai_socktype = SOCK_STREAM;
aiHint.ai_protocol = IPPROTO_TCP;
aiHint.ai_family = AF_UNSPEC;
@@ -82,8 +114,33 @@ bool static LookupIntern(const char *pszName, std::vector<CNetAddr>& vIP, unsign
#else
aiHint.ai_flags = fAllowLookup ? AI_ADDRCONFIG : AI_NUMERICHOST;
#endif
+
struct addrinfo *aiRes = NULL;
+#ifdef HAVE_GETADDRINFO_A
+ struct gaicb gcb, *query = &gcb;
+ memset(query, 0, sizeof(struct gaicb));
+ gcb.ar_name = pszName;
+ gcb.ar_request = &aiHint;
+ int nErr = getaddrinfo_a(GAI_NOWAIT, &query, 1, NULL);
+ if (nErr)
+ return false;
+
+ do {
+ // Should set the timeout limit to a resonable value to avoid
+ // generating unnecessary checking call during the polling loop,
+ // while it can still response to stop request quick enough.
+ // 2 seconds looks fine in our situation.
+ struct timespec ts = { 2, 0 };
+ gai_suspend(&query, 1, &ts);
+ boost::this_thread::interruption_point();
+
+ nErr = gai_error(query);
+ if (0 == nErr)
+ aiRes = query->ar_result;
+ } while (nErr == EAI_INPROGRESS);
+#else
int nErr = getaddrinfo(pszName, NULL, &aiHint, &aiRes);
+#endif
if (nErr)
return false;
@@ -123,11 +180,6 @@ bool LookupHost(const char *pszName, std::vector<CNetAddr>& vIP, unsigned int nM
return LookupIntern(strHost.c_str(), vIP, nMaxSolutions, fAllowLookup);
}
-bool LookupHostNumeric(const char *pszName, std::vector<CNetAddr>& vIP, unsigned int nMaxSolutions)
-{
- return LookupHost(pszName, vIP, nMaxSolutions, false);
-}
-
bool Lookup(const char *pszName, std::vector<CService>& vAddr, int portDefault, bool fAllowLookup, unsigned int nMaxSolutions)
{
if (pszName[0] == 0)
@@ -161,50 +213,6 @@ bool LookupNumeric(const char *pszName, CService& addr, int portDefault)
return Lookup(pszName, addr, portDefault, false);
}
-bool static Socks4(const CService &addrDest, SOCKET& hSocket)
-{
- LogPrintf("SOCKS4 connecting %s\n", addrDest.ToString());
- if (!addrDest.IsIPv4())
- {
- closesocket(hSocket);
- return error("Proxy destination is not IPv4");
- }
- char pszSocks4IP[] = "\4\1\0\0\0\0\0\0user";
- struct sockaddr_in addr;
- socklen_t len = sizeof(addr);
- if (!addrDest.GetSockAddr((struct sockaddr*)&addr, &len) || addr.sin_family != AF_INET)
- {
- closesocket(hSocket);
- return error("Cannot get proxy destination address");
- }
- memcpy(pszSocks4IP + 2, &addr.sin_port, 2);
- memcpy(pszSocks4IP + 4, &addr.sin_addr, 4);
- char* pszSocks4 = pszSocks4IP;
- int nSize = sizeof(pszSocks4IP);
-
- int ret = send(hSocket, pszSocks4, nSize, MSG_NOSIGNAL);
- if (ret != nSize)
- {
- closesocket(hSocket);
- return error("Error sending to proxy");
- }
- char pchRet[8];
- if (recv(hSocket, pchRet, 8, 0) != 8)
- {
- closesocket(hSocket);
- return error("Error reading proxy response");
- }
- if (pchRet[1] != 0x5a)
- {
- closesocket(hSocket);
- if (pchRet[1] != 0x5b)
- LogPrintf("ERROR: Proxy returned error %d\n", pchRet[1]);
- return false;
- }
- LogPrintf("SOCKS4 connected %s\n", addrDest.ToString());
- return true;
-}
-
bool static Socks5(string strDest, int port, SOCKET& hSocket)
{
LogPrintf("SOCKS5 connecting %s\n", strDest);
@@ -342,8 +350,9 @@ bool static ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRe
if (connect(hSocket, (struct sockaddr*)&sockaddr, len) == SOCKET_ERROR)
{
+ int nErr = WSAGetLastError();
// WSAEINVAL is here because some legacy version of winsock uses it
- if (WSAGetLastError() == WSAEINPROGRESS || WSAGetLastError() == WSAEWOULDBLOCK || WSAGetLastError() == WSAEINVAL)
+ if (nErr == WSAEINPROGRESS || nErr == WSAEWOULDBLOCK || nErr == WSAEINVAL)
{
struct timeval timeout;
timeout.tv_sec = nTimeout / 1000;
@@ -414,53 +423,49 @@ bool static ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRe
return true;
}
-bool SetProxy(enum Network net, CService addrProxy, int nSocksVersion) {
+bool SetProxy(enum Network net, CService addrProxy) {
assert(net >= 0 && net < NET_MAX);
- if (nSocksVersion != 0 && nSocksVersion != 4 && nSocksVersion != 5)
- return false;
- if (nSocksVersion != 0 && !addrProxy.IsValid())
+ if (!addrProxy.IsValid())
return false;
LOCK(cs_proxyInfos);
- proxyInfo[net] = std::make_pair(addrProxy, nSocksVersion);
+ proxyInfo[net] = addrProxy;
return true;
}
bool GetProxy(enum Network net, proxyType &proxyInfoOut) {
assert(net >= 0 && net < NET_MAX);
LOCK(cs_proxyInfos);
- if (!proxyInfo[net].second)
+ if (!proxyInfo[net].IsValid())
return false;
proxyInfoOut = proxyInfo[net];
return true;
}
-bool SetNameProxy(CService addrProxy, int nSocksVersion) {
- if (nSocksVersion != 0 && nSocksVersion != 5)
- return false;
- if (nSocksVersion != 0 && !addrProxy.IsValid())
+bool SetNameProxy(CService addrProxy) {
+ if (!addrProxy.IsValid())
return false;
LOCK(cs_proxyInfos);
- nameproxyInfo = std::make_pair(addrProxy, nSocksVersion);
+ nameProxy = addrProxy;
return true;
}
-bool GetNameProxy(proxyType &nameproxyInfoOut) {
+bool GetNameProxy(CService &nameProxyOut) {
LOCK(cs_proxyInfos);
- if (!nameproxyInfo.second)
+ if(!nameProxy.IsValid())
return false;
- nameproxyInfoOut = nameproxyInfo;
+ nameProxyOut = nameProxy;
return true;
}
bool HaveNameProxy() {
LOCK(cs_proxyInfos);
- return nameproxyInfo.second != 0;
+ return nameProxy.IsValid();
}
bool IsProxy(const CNetAddr &addr) {
LOCK(cs_proxyInfos);
for (int i = 0; i < NET_MAX; i++) {
- if (proxyInfo[i].second && (addr == (CNetAddr)proxyInfo[i].first))
+ if (addr == (CNetAddr)proxyInfo[i])
return true;
}
return false;
@@ -469,31 +474,18 @@ bool IsProxy(const CNetAddr &addr) {
bool ConnectSocket(const CService &addrDest, SOCKET& hSocketRet, int nTimeout)
{
proxyType proxy;
-
- // no proxy needed
+ // no proxy needed (none set for target network)
if (!GetProxy(addrDest.GetNetwork(), proxy))
return ConnectSocketDirectly(addrDest, hSocketRet, nTimeout);
SOCKET hSocket = INVALID_SOCKET;
// first connect to proxy server
- if (!ConnectSocketDirectly(proxy.first, hSocket, nTimeout))
+ if (!ConnectSocketDirectly(proxy, hSocket, nTimeout))
return false;
-
// do socks negotiation
- switch (proxy.second) {
- case 4:
- if (!Socks4(addrDest, hSocket))
- return false;
- break;
- case 5:
- if (!Socks5(addrDest.ToStringIP(), addrDest.GetPort(), hSocket))
- return false;
- break;
- default:
- closesocket(hSocket);
+ if (!Socks5(addrDest.ToStringIP(), addrDest.GetPort(), hSocket))
return false;
- }
hSocketRet = hSocket;
return true;
@@ -507,30 +499,25 @@ bool ConnectSocketByName(CService &addr, SOCKET& hSocketRet, const char *pszDest
SOCKET hSocket = INVALID_SOCKET;
- proxyType nameproxy;
- GetNameProxy(nameproxy);
+ CService nameProxy;
+ GetNameProxy(nameProxy);
- CService addrResolved(CNetAddr(strDest, fNameLookup && !nameproxy.second), port);
+ CService addrResolved(CNetAddr(strDest, fNameLookup && !HaveNameProxy()), port);
if (addrResolved.IsValid()) {
addr = addrResolved;
return ConnectSocket(addr, hSocketRet, nTimeout);
}
+
addr = CService("0.0.0.0:0");
- if (!nameproxy.second)
+
+ if (!HaveNameProxy())
return false;
- if (!ConnectSocketDirectly(nameproxy.first, hSocket, nTimeout))
+ // first connect to name proxy server
+ if (!ConnectSocketDirectly(nameProxy, hSocket, nTimeout))
+ return false;
+ // do socks negotiation
+ if (!Socks5(strDest, (unsigned short)port, hSocket))
return false;
-
- switch(nameproxy.second) {
- default:
- case 4:
- closesocket(hSocket);
- return false;
- case 5:
- if (!Socks5(strDest, port, hSocket))
- return false;
- break;
- }
hSocketRet = hSocket;
return true;
diff --git a/src/netbase.h b/src/netbase.h
index 5fd8be4aca..ad1e230834 100644
--- a/src/netbase.h
+++ b/src/netbase.h
@@ -6,7 +6,7 @@
#define BITCOIN_NETBASE_H
#if defined(HAVE_CONFIG_H)
-#include "bitcoin-config.h"
+#include "config/bitcoin-config.h"
#endif
#include "compat.h"
@@ -17,6 +17,7 @@
#include <vector>
extern int nConnectTimeout;
+extern bool fNameLookup;
#ifdef WIN32
// In MSVC, this is defined as a macro, undefine it to prevent a compile and link error
@@ -33,9 +34,6 @@ enum Network
NET_MAX,
};
-extern int nConnectTimeout;
-extern bool fNameLookup;
-
/** IP address (IPv6, or IPv4 using mapped IPv6 range (::FFFF:0:0/96)) */
class CNetAddr
{
@@ -163,17 +161,16 @@ class CService : public CNetAddr
)
};
-typedef std::pair<CService, int> proxyType;
+typedef CService proxyType;
enum Network ParseNetwork(std::string net);
void SplitHostPort(std::string in, int &portOut, std::string &hostOut);
-bool SetProxy(enum Network net, CService addrProxy, int nSocksVersion = 5);
+bool SetProxy(enum Network net, CService addrProxy);
bool GetProxy(enum Network net, proxyType &proxyInfoOut);
bool IsProxy(const CNetAddr &addr);
-bool SetNameProxy(CService addrProxy, int nSocksVersion = 5);
+bool SetNameProxy(CService addrProxy);
bool HaveNameProxy();
bool LookupHost(const char *pszName, std::vector<CNetAddr>& vIP, unsigned int nMaxSolutions = 0, bool fAllowLookup = true);
-bool LookupHostNumeric(const char *pszName, std::vector<CNetAddr>& vIP, unsigned int nMaxSolutions = 0);
bool Lookup(const char *pszName, CService& addr, int portDefault = 0, bool fAllowLookup = true);
bool Lookup(const char *pszName, std::vector<CService>& vAddr, int portDefault = 0, bool fAllowLookup = true, unsigned int nMaxSolutions = 0);
bool LookupNumeric(const char *pszName, CService& addr, int portDefault = 0);
diff --git a/src/pow.cpp b/src/pow.cpp
new file mode 100644
index 0000000000..c0d0a7ca20
--- /dev/null
+++ b/src/pow.cpp
@@ -0,0 +1,119 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2014 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 "pow.h"
+
+#include "chainparams.h"
+#include "core.h"
+#include "main.h"
+#include "uint256.h"
+
+unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock)
+{
+ unsigned int nProofOfWorkLimit = Params().ProofOfWorkLimit().GetCompact();
+
+ // Genesis block
+ if (pindexLast == NULL)
+ return nProofOfWorkLimit;
+
+ // Only change once per interval
+ if ((pindexLast->nHeight+1) % Params().Interval() != 0)
+ {
+ if (Params().AllowMinDifficultyBlocks())
+ {
+ // Special difficulty rule for testnet:
+ // If the new block's timestamp is more than 2* 10 minutes
+ // then allow mining of a min-difficulty block.
+ if (pblock->GetBlockTime() > pindexLast->GetBlockTime() + Params().TargetSpacing()*2)
+ return nProofOfWorkLimit;
+ else
+ {
+ // Return the last non-special-min-difficulty-rules-block
+ const CBlockIndex* pindex = pindexLast;
+ while (pindex->pprev && pindex->nHeight % Params().Interval() != 0 && pindex->nBits == nProofOfWorkLimit)
+ pindex = pindex->pprev;
+ return pindex->nBits;
+ }
+ }
+ return pindexLast->nBits;
+ }
+
+ // Go back by what we want to be 14 days worth of blocks
+ const CBlockIndex* pindexFirst = pindexLast;
+ for (int i = 0; pindexFirst && i < Params().Interval()-1; i++)
+ pindexFirst = pindexFirst->pprev;
+ assert(pindexFirst);
+
+ // Limit adjustment step
+ int64_t nActualTimespan = pindexLast->GetBlockTime() - pindexFirst->GetBlockTime();
+ LogPrintf(" nActualTimespan = %d before bounds\n", nActualTimespan);
+ if (nActualTimespan < Params().TargetTimespan()/4)
+ nActualTimespan = Params().TargetTimespan()/4;
+ if (nActualTimespan > Params().TargetTimespan()*4)
+ nActualTimespan = Params().TargetTimespan()*4;
+
+ // Retarget
+ uint256 bnNew;
+ uint256 bnOld;
+ bnNew.SetCompact(pindexLast->nBits);
+ bnOld = bnNew;
+ bnNew *= nActualTimespan;
+ bnNew /= Params().TargetTimespan();
+
+ if (bnNew > Params().ProofOfWorkLimit())
+ bnNew = Params().ProofOfWorkLimit();
+
+ /// debug print
+ LogPrintf("GetNextWorkRequired RETARGET\n");
+ LogPrintf("Params().TargetTimespan() = %d nActualTimespan = %d\n", Params().TargetTimespan(), nActualTimespan);
+ LogPrintf("Before: %08x %s\n", pindexLast->nBits, bnOld.ToString());
+ LogPrintf("After: %08x %s\n", bnNew.GetCompact(), bnNew.ToString());
+
+ return bnNew.GetCompact();
+}
+
+bool CheckProofOfWork(uint256 hash, unsigned int nBits)
+{
+ bool fNegative;
+ bool fOverflow;
+ uint256 bnTarget;
+ bnTarget.SetCompact(nBits, &fNegative, &fOverflow);
+
+ // Check range
+ if (fNegative || bnTarget == 0 || fOverflow || bnTarget > Params().ProofOfWorkLimit())
+ return error("CheckProofOfWork() : nBits below minimum work");
+
+ // Check proof of work matches claimed amount
+ if (hash > bnTarget)
+ return error("CheckProofOfWork() : hash doesn't match nBits");
+
+ return true;
+}
+
+//
+// minimum amount of work that could possibly be required nTime after
+// minimum work required was nBase
+//
+unsigned int ComputeMinWork(unsigned int nBase, int64_t nTime)
+{
+ const uint256 &bnLimit = Params().ProofOfWorkLimit();
+ // Testnet has min-difficulty blocks
+ // after Params().TargetSpacing()*2 time between blocks:
+ if (Params().AllowMinDifficultyBlocks() && nTime > Params().TargetSpacing()*2)
+ return bnLimit.GetCompact();
+
+ uint256 bnResult;
+ bnResult.SetCompact(nBase);
+ while (nTime > 0 && bnResult < bnLimit)
+ {
+ // Maximum 400% adjustment...
+ bnResult *= 4;
+ // ... in best-case exactly 4-times-normal target time
+ nTime -= Params().TargetTimespan()*4;
+ }
+ if (bnResult > bnLimit)
+ bnResult = bnLimit;
+ return bnResult.GetCompact();
+}
diff --git a/src/pow.h b/src/pow.h
new file mode 100644
index 0000000000..0ce5b48766
--- /dev/null
+++ b/src/pow.h
@@ -0,0 +1,23 @@
+
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2014 The Bitcoin developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_POW_H
+#define BITCOIN_POW_H
+
+#include <stdint.h>
+
+class CBlockIndex;
+class CBlockHeader;
+class uint256;
+
+unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock);
+
+/** Check whether a block hash satisfies the proof-of-work requirement specified by nBits */
+bool CheckProofOfWork(uint256 hash, unsigned int nBits);
+/** Calculate the minimum amount of work a received block needs, without knowing its direct parent */
+unsigned int ComputeMinWork(unsigned int nBase, int64_t nTime);
+
+#endif
diff --git a/src/protocol.cpp b/src/protocol.cpp
index c77a92f020..87b2f23873 100644
--- a/src/protocol.cpp
+++ b/src/protocol.cpp
@@ -5,6 +5,7 @@
#include "protocol.h"
+#include "chainparams.h"
#include "util.h"
#ifndef WIN32
diff --git a/src/protocol.h b/src/protocol.h
index e6f105fe5c..1f23274299 100644
--- a/src/protocol.h
+++ b/src/protocol.h
@@ -10,7 +10,6 @@
#ifndef __INCLUDED_PROTOCOL_H__
#define __INCLUDED_PROTOCOL_H__
-#include "chainparams.h"
#include "netbase.h"
#include "serialize.h"
#include "uint256.h"
@@ -19,6 +18,8 @@
#include <stdint.h>
#include <string>
+#define MESSAGE_START_SIZE 4
+
/** Message header.
* (4) message start.
* (12) command.
@@ -63,6 +64,14 @@ class CMessageHeader
enum
{
NODE_NETWORK = (1 << 0),
+
+ // Bits 24-31 are reserved for temporary experiments. Just pick a bit that
+ // isn't getting used, or one not being used much, and notify the
+ // bitcoin-development mailing list. Remember that service bits are just
+ // unauthenticated advertisements, so your code must be robust against
+ // collisions and other cases where nodes may be advertising a service they
+ // do not actually support. Other service bits should be allocated via the
+ // BIP process.
};
/** A CService with information about it as peer */
diff --git a/src/qt/Makefile b/src/qt/Makefile
new file mode 100644
index 0000000000..b9dcf0c599
--- /dev/null
+++ b/src/qt/Makefile
@@ -0,0 +1,9 @@
+.PHONY: FORCE
+all: FORCE
+ $(MAKE) -C .. bitcoin_qt test_bitcoin_qt
+clean: FORCE
+ $(MAKE) -C .. bitcoin_qt_clean test_bitcoin_qt_clean
+check: FORCE
+ $(MAKE) -C .. test_bitcoin_qt_check
+bitcoin-qt bitcoin-qt.exe: FORCE
+ $(MAKE) -C .. bitcoin_qt
diff --git a/src/qt/Makefile.am b/src/qt/Makefile.am
deleted file mode 100644
index 648971bd8f..0000000000
--- a/src/qt/Makefile.am
+++ /dev/null
@@ -1,379 +0,0 @@
-include $(top_srcdir)/src/Makefile.include
-
-AM_CPPFLAGS += -I$(top_srcdir)/src \
- -I$(top_builddir)/src/qt \
- -I$(top_builddir)/src/qt/forms \
- $(PROTOBUF_CFLAGS) \
- $(QR_CFLAGS)
-bin_PROGRAMS = bitcoin-qt
-noinst_LIBRARIES = libbitcoinqt.a
-SUBDIRS = . $(BUILD_TEST_QT)
-DIST_SUBDIRS = . test
-
-# bitcoin qt core #
-QT_TS = \
- locale/bitcoin_ach.ts \
- locale/bitcoin_af_ZA.ts \
- locale/bitcoin_ar.ts \
- locale/bitcoin_be_BY.ts \
- locale/bitcoin_bg.ts \
- locale/bitcoin_bs.ts \
- locale/bitcoin_ca_ES.ts \
- locale/bitcoin_ca.ts \
- locale/bitcoin_ca@valencia.ts \
- locale/bitcoin_cmn.ts \
- locale/bitcoin_cs.ts \
- locale/bitcoin_cy.ts \
- locale/bitcoin_da.ts \
- locale/bitcoin_de.ts \
- locale/bitcoin_el_GR.ts \
- locale/bitcoin_en.ts \
- locale/bitcoin_eo.ts \
- locale/bitcoin_es_CL.ts \
- locale/bitcoin_es_DO.ts \
- locale/bitcoin_es_MX.ts \
- locale/bitcoin_es.ts \
- locale/bitcoin_es_UY.ts \
- locale/bitcoin_et.ts \
- locale/bitcoin_eu_ES.ts \
- locale/bitcoin_fa_IR.ts \
- locale/bitcoin_fa.ts \
- locale/bitcoin_fi.ts \
- locale/bitcoin_fr_CA.ts \
- locale/bitcoin_fr.ts \
- locale/bitcoin_gl.ts \
- locale/bitcoin_gu_IN.ts \
- locale/bitcoin_he.ts \
- locale/bitcoin_hi_IN.ts \
- locale/bitcoin_hr.ts \
- locale/bitcoin_hu.ts \
- locale/bitcoin_id_ID.ts \
- locale/bitcoin_it.ts \
- locale/bitcoin_ja.ts \
- locale/bitcoin_ka.ts \
- locale/bitcoin_kk_KZ.ts \
- locale/bitcoin_ko_KR.ts \
- locale/bitcoin_ky.ts \
- locale/bitcoin_la.ts \
- locale/bitcoin_lt.ts \
- locale/bitcoin_lv_LV.ts \
- locale/bitcoin_mn.ts \
- locale/bitcoin_ms_MY.ts \
- locale/bitcoin_nb.ts \
- locale/bitcoin_nl.ts \
- locale/bitcoin_pam.ts \
- locale/bitcoin_pl.ts \
- locale/bitcoin_pt_BR.ts \
- locale/bitcoin_pt_PT.ts \
- locale/bitcoin_ro_RO.ts \
- locale/bitcoin_ru.ts \
- locale/bitcoin_sah.ts \
- locale/bitcoin_sk.ts \
- locale/bitcoin_sl_SI.ts \
- locale/bitcoin_sq.ts \
- locale/bitcoin_sr.ts \
- locale/bitcoin_sv.ts \
- locale/bitcoin_th_TH.ts \
- locale/bitcoin_tr.ts \
- locale/bitcoin_uk.ts \
- locale/bitcoin_ur_PK.ts \
- locale/bitcoin_uz@Cyrl.ts \
- locale/bitcoin_vi.ts \
- locale/bitcoin_vi_VN.ts \
- locale/bitcoin_zh_CN.ts \
- locale/bitcoin_zh_HK.ts \
- locale/bitcoin_zh_TW.ts
-
-QT_FORMS_UI = \
- forms/aboutdialog.ui \
- forms/addressbookpage.ui \
- forms/askpassphrasedialog.ui \
- forms/coincontroldialog.ui \
- forms/editaddressdialog.ui \
- forms/helpmessagedialog.ui \
- forms/intro.ui \
- forms/openuridialog.ui \
- forms/optionsdialog.ui \
- forms/overviewpage.ui \
- forms/receivecoinsdialog.ui \
- forms/receiverequestdialog.ui \
- forms/rpcconsole.ui \
- forms/sendcoinsdialog.ui \
- forms/sendcoinsentry.ui \
- forms/signverifymessagedialog.ui \
- forms/transactiondescdialog.ui
-
-QT_MOC_CPP = \
- moc_addressbookpage.cpp \
- moc_addresstablemodel.cpp \
- moc_askpassphrasedialog.cpp \
- moc_bitcoinaddressvalidator.cpp \
- moc_bitcoinamountfield.cpp \
- moc_bitcoingui.cpp \
- moc_bitcoinunits.cpp \
- moc_clientmodel.cpp \
- moc_coincontroldialog.cpp \
- moc_coincontroltreewidget.cpp \
- moc_csvmodelwriter.cpp \
- moc_editaddressdialog.cpp \
- moc_guiutil.cpp \
- moc_intro.cpp \
- moc_macdockiconhandler.cpp \
- moc_macnotificationhandler.cpp \
- moc_monitoreddatamapper.cpp \
- moc_notificator.cpp \
- moc_openuridialog.cpp \
- moc_optionsdialog.cpp \
- moc_optionsmodel.cpp \
- moc_overviewpage.cpp \
- moc_paymentserver.cpp \
- moc_qvalidatedlineedit.cpp \
- moc_qvaluecombobox.cpp \
- moc_receivecoinsdialog.cpp \
- moc_receiverequestdialog.cpp \
- moc_recentrequeststablemodel.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 \
- moc_transactiontablemodel.cpp \
- moc_transactionview.cpp \
- moc_utilitydialog.cpp \
- moc_walletframe.cpp \
- moc_walletmodel.cpp \
- moc_walletview.cpp
-
-BITCOIN_MM = \
- macdockiconhandler.mm \
- macnotificationhandler.mm
-
-QT_MOC = \
- bitcoin.moc \
- intro.moc \
- overviewpage.moc \
- rpcconsole.moc
-
-QT_QRC_CPP = qrc_bitcoin.cpp
-QT_QRC = bitcoin.qrc
-
-PROTOBUF_CC = paymentrequest.pb.cc
-PROTOBUF_H = paymentrequest.pb.h
-PROTOBUF_PROTO = paymentrequest.proto
-
-BITCOIN_QT_H = \
- addressbookpage.h \
- addresstablemodel.h \
- askpassphrasedialog.h \
- bitcoinaddressvalidator.h \
- bitcoinamountfield.h \
- bitcoingui.h \
- bitcoinunits.h \
- clientmodel.h \
- coincontroldialog.h \
- coincontroltreewidget.h \
- csvmodelwriter.h \
- editaddressdialog.h \
- guiconstants.h \
- guiutil.h \
- intro.h \
- macdockiconhandler.h \
- macnotificationhandler.h \
- monitoreddatamapper.h \
- notificator.h \
- openuridialog.h \
- optionsdialog.h \
- optionsmodel.h \
- overviewpage.h \
- paymentrequestplus.h \
- paymentserver.h \
- qvalidatedlineedit.h \
- qvaluecombobox.h \
- receivecoinsdialog.h \
- receiverequestdialog.h \
- recentrequeststablemodel.h \
- rpcconsole.h \
- sendcoinsdialog.h \
- sendcoinsentry.h \
- signverifymessagedialog.h \
- splashscreen.h \
- trafficgraphwidget.h \
- transactiondesc.h \
- transactiondescdialog.h \
- transactionfilterproxy.h \
- transactionrecord.h \
- transactiontablemodel.h \
- transactionview.h \
- utilitydialog.h \
- walletframe.h \
- walletmodel.h \
- walletmodeltransaction.h \
- walletview.h \
- winshutdownmonitor.h
-
-RES_ICONS = \
- res/icons/add.png \
- res/icons/address-book.png \
- res/icons/bitcoin.ico \
- res/icons/bitcoin.png \
- res/icons/bitcoin_testnet.ico \
- res/icons/bitcoin_testnet.png \
- res/icons/clock1.png \
- res/icons/clock2.png \
- res/icons/clock3.png \
- res/icons/clock4.png \
- res/icons/clock5.png \
- res/icons/configure.png \
- res/icons/connect0_16.png \
- res/icons/connect1_16.png \
- res/icons/connect2_16.png \
- res/icons/connect3_16.png \
- res/icons/connect4_16.png \
- res/icons/debugwindow.png \
- res/icons/edit.png \
- res/icons/editcopy.png \
- res/icons/editpaste.png \
- res/icons/export.png \
- res/icons/filesave.png \
- res/icons/history.png \
- res/icons/key.png \
- res/icons/lock_closed.png \
- res/icons/lock_open.png \
- res/icons/overview.png \
- res/icons/qrcode.png \
- res/icons/quit.png \
- res/icons/receive.png \
- res/icons/remove.png \
- res/icons/send.png \
- res/icons/synced.png \
- res/icons/toolbar.png \
- res/icons/toolbar_testnet.png \
- res/icons/transaction0.png \
- res/icons/transaction2.png \
- res/icons/transaction_conflicted.png \
- res/icons/tx_inout.png \
- res/icons/tx_input.png \
- res/icons/tx_output.png \
- res/icons/tx_mined.png
-
-BITCOIN_QT_CPP = \
- bitcoin.cpp \
- bitcoinaddressvalidator.cpp \
- bitcoinamountfield.cpp \
- bitcoingui.cpp \
- bitcoinunits.cpp \
- clientmodel.cpp \
- csvmodelwriter.cpp \
- guiutil.cpp \
- intro.cpp \
- monitoreddatamapper.cpp \
- notificator.cpp \
- optionsdialog.cpp \
- optionsmodel.cpp \
- qvalidatedlineedit.cpp \
- qvaluecombobox.cpp \
- rpcconsole.cpp \
- splashscreen.cpp \
- trafficgraphwidget.cpp \
- utilitydialog.cpp \
- winshutdownmonitor.cpp
-
-if ENABLE_WALLET
-BITCOIN_QT_CPP += \
- addressbookpage.cpp \
- addresstablemodel.cpp \
- askpassphrasedialog.cpp \
- coincontroldialog.cpp \
- coincontroltreewidget.cpp \
- editaddressdialog.cpp \
- openuridialog.cpp \
- overviewpage.cpp \
- paymentrequestplus.cpp \
- paymentserver.cpp \
- receivecoinsdialog.cpp \
- receiverequestdialog.cpp \
- recentrequeststablemodel.cpp \
- sendcoinsdialog.cpp \
- sendcoinsentry.cpp \
- signverifymessagedialog.cpp \
- transactiondesc.cpp \
- transactiondescdialog.cpp \
- transactionfilterproxy.cpp \
- transactionrecord.cpp \
- transactiontablemodel.cpp \
- transactionview.cpp \
- walletframe.cpp \
- walletmodel.cpp \
- walletmodeltransaction.cpp \
- walletview.cpp
-endif
-
-RES_IMAGES = \
- res/images/about.png \
- res/images/splash.png \
- res/images/splash_testnet.png
-
-RES_MOVIES = $(wildcard res/movies/spinner-*.png)
-
-BITCOIN_RC = res/bitcoin-qt-res.rc
-
-libbitcoinqt_a_CPPFLAGS = $(AM_CPPFLAGS) $(QT_INCLUDES) \
- -I$(top_srcdir)/src/qt/forms $(QT_DBUS_INCLUDES)
-libbitcoinqt_a_SOURCES = $(BITCOIN_QT_CPP) $(BITCOIN_QT_H) $(QT_FORMS_UI) \
- $(QT_QRC) $(QT_TS) $(PROTOBUF_PROTO) $(RES_ICONS) $(RES_IMAGES) $(RES_MOVIES)
-
-nodist_libbitcoinqt_a_SOURCES = $(QT_MOC_CPP) $(QT_MOC) $(PROTOBUF_CC) \
- $(PROTOBUF_H) $(QT_QRC_CPP)
-
-BUILT_SOURCES = $(nodist_libbitcoinqt_a_SOURCES)
-
-#Generating these with a half-written protobuf header leads to wacky results.
-#This makes sure it's done.
-$(QT_MOC): $(PROTOBUF_H)
-$(QT_MOC_CPP): $(PROTOBUF_H)
-
-# bitcoin-qt binary #
-bitcoin_qt_CPPFLAGS = $(AM_CPPFLAGS) $(QT_INCLUDES) \
- -I$(top_srcdir)/src/qt/forms
-bitcoin_qt_SOURCES = bitcoin.cpp
-if TARGET_DARWIN
- bitcoin_qt_SOURCES += $(BITCOIN_MM)
-endif
-if TARGET_WINDOWS
- bitcoin_qt_SOURCES += $(BITCOIN_RC)
-endif
-bitcoin_qt_LDADD = libbitcoinqt.a $(LIBBITCOIN_SERVER)
-if ENABLE_WALLET
-bitcoin_qt_LDADD += $(LIBBITCOIN_WALLET)
-endif
-bitcoin_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBLEVELDB) $(LIBMEMENV) \
- $(BOOST_LIBS) $(QT_LIBS) $(QT_DBUS_LIBS) $(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS)
-bitcoin_qt_LDFLAGS = $(QT_LDFLAGS)
-
-# forms/foo.h -> forms/ui_foo.h
-QT_FORMS_H=$(join $(dir $(QT_FORMS_UI)),$(addprefix ui_, $(notdir $(QT_FORMS_UI:.ui=.h))))
-
-#locale/foo.ts -> locale/foo.qm
-QT_QM=$(QT_TS:.ts=.qm)
-
-.PHONY: FORCE
-.SECONDARY: $(QT_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)
- @test -n $(LUPDATE) || echo "lupdate is required for updating translations"
- @QT_SELECT=$(QT_SELECT) $(LUPDATE) $^ -locations relative -no-obsolete -ts locale/bitcoin_en.ts
-
-$(QT_QRC_CPP): $(QT_QRC) $(QT_QM) $(QT_FORMS_H) $(RES_ICONS) $(RES_IMAGES) $(RES_MOVIES) $(PROTOBUF_H)
- @cd $(abs_srcdir); test -f $(RCC) && QT_SELECT=$(QT_SELECT) $(RCC) -name bitcoin -o $(abs_builddir)/$@ $< || \
- echo error: could not build $@
- $(SED) -e '/^\*\*.*Created:/d' $@ > $@.n && mv $@{.n,}
- $(SED) -e '/^\*\*.*by:/d' $@ > $@.n && mv $@{.n,}
-
-CLEANFILES = $(BUILT_SOURCES) $(QT_QM) $(QT_FORMS_H) *.gcda *.gcno
diff --git a/src/qt/addressbookpage.cpp b/src/qt/addressbookpage.cpp
index 2dc56a5107..5df8f19729 100644
--- a/src/qt/addressbookpage.cpp
+++ b/src/qt/addressbookpage.cpp
@@ -3,7 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#if defined(HAVE_CONFIG_H)
-#include "bitcoin-config.h"
+#include "config/bitcoin-config.h"
#endif
#include "addressbookpage.h"
diff --git a/src/qt/addresstablemodel.cpp b/src/qt/addresstablemodel.cpp
index dfbd445ce3..8d5284d5e9 100644
--- a/src/qt/addresstablemodel.cpp
+++ b/src/qt/addresstablemodel.cpp
@@ -114,7 +114,7 @@ public:
case CT_NEW:
if(inModel)
{
- qDebug() << "AddressTablePriv::updateEntry : Warning: Got CT_NEW, but entry is already in model";
+ qWarning() << "AddressTablePriv::updateEntry : Warning: Got CT_NEW, but entry is already in model";
break;
}
parent->beginInsertRows(QModelIndex(), lowerIndex, lowerIndex);
@@ -124,7 +124,7 @@ public:
case CT_UPDATED:
if(!inModel)
{
- qDebug() << "AddressTablePriv::updateEntry : Warning: Got CT_UPDATED, but entry is not in model";
+ qWarning() << "AddressTablePriv::updateEntry : Warning: Got CT_UPDATED, but entry is not in model";
break;
}
lower->type = newEntryType;
@@ -134,7 +134,7 @@ public:
case CT_DELETED:
if(!inModel)
{
- qDebug() << "AddressTablePriv::updateEntry : Warning: Got CT_DELETED, but entry is not in model";
+ qWarning() << "AddressTablePriv::updateEntry : Warning: Got CT_DELETED, but entry is not in model";
break;
}
parent->beginRemoveRows(QModelIndex(), lowerIndex, upperIndex-1);
diff --git a/src/qt/askpassphrasedialog.cpp b/src/qt/askpassphrasedialog.cpp
index 2a6d6abc35..a448d5a9a0 100644
--- a/src/qt/askpassphrasedialog.cpp
+++ b/src/qt/askpassphrasedialog.cpp
@@ -37,7 +37,7 @@ AskPassphraseDialog::AskPassphraseDialog(Mode mode, QWidget *parent) :
case Encrypt: // Ask passphrase x2
ui->passLabel1->hide();
ui->passEdit1->hide();
- ui->warningLabel->setText(tr("Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>10 or more random characters</b>, or <b>eight or more words</b>."));
+ ui->warningLabel->setText(tr("Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>ten or more random characters</b>, or <b>eight or more words</b>."));
setWindowTitle(tr("Encrypt wallet"));
break;
case Unlock: // Ask passphrase
diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp
index 45d7a52889..7c4af25edf 100644
--- a/src/qt/bitcoin.cpp
+++ b/src/qt/bitcoin.cpp
@@ -3,7 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#if defined(HAVE_CONFIG_H)
-#include "bitcoin-config.h"
+#include "config/bitcoin-config.h"
#endif
#include "bitcoingui.h"
@@ -126,15 +126,15 @@ static void initTranslations(QTranslator &qtTranslatorBase, QTranslator &qtTrans
#if QT_VERSION < 0x050000
void DebugMessageHandler(QtMsgType type, const char *msg)
{
- Q_UNUSED(type);
- LogPrint("qt", "GUI: %s\n", msg);
+ const char *category = (type == QtDebugMsg) ? "qt" : NULL;
+ LogPrint(category, "GUI: %s\n", msg);
}
#else
void DebugMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString &msg)
{
- Q_UNUSED(type);
Q_UNUSED(context);
- LogPrint("qt", "GUI: %s\n", qPrintable(msg));
+ const char *category = (type == QtDebugMsg) ? "qt" : NULL;
+ LogPrint(category, "GUI: %s\n", msg.toStdString());
}
#endif
@@ -475,6 +475,7 @@ int main(int argc, char *argv[])
#endif
Q_INIT_RESOURCE(bitcoin);
+ Q_INIT_RESOURCE(bitcoin_locale);
BitcoinApplication app(argc, argv);
#if QT_VERSION > 0x050100
// Generate high-dpi pixmaps
@@ -502,9 +503,9 @@ int main(int argc, char *argv[])
// Show help message immediately after parsing command-line options (for "-lang") and setting locale,
// but before showing splash screen.
- if (mapArgs.count("-?") || mapArgs.count("--help"))
+ if (mapArgs.count("-?") || mapArgs.count("-help") || mapArgs.count("-version"))
{
- HelpMessageDialog help(NULL);
+ HelpMessageDialog help(NULL, mapArgs.count("-version"));
help.showOrPrint();
return 1;
}
@@ -545,7 +546,7 @@ int main(int argc, char *argv[])
if (!PaymentServer::ipcParseCommandLine(argc, argv))
exit(0);
#endif
- bool isaTestNet = Params().NetworkID() != CChainParams::MAIN;
+ bool isaTestNet = Params().NetworkID() != CBaseChainParams::MAIN;
// Allow for separate UI settings for testnets
if (isaTestNet)
QApplication::setApplicationName(QAPP_APP_NAME_TESTNET);
diff --git a/src/qt/bitcoin.qrc b/src/qt/bitcoin.qrc
index e1c739b022..357c6470d3 100644
--- a/src/qt/bitcoin.qrc
+++ b/src/qt/bitcoin.qrc
@@ -35,6 +35,9 @@
<file alias="tx_input">res/icons/tx_input.png</file>
<file alias="tx_output">res/icons/tx_output.png</file>
<file alias="tx_inout">res/icons/tx_inout.png</file>
+ <file alias="unit_btc">res/icons/unit_btc.png</file>
+ <file alias="unit_mbtc">res/icons/unit_mbtc.png</file>
+ <file alias="unit_ubtc">res/icons/unit_ubtc.png</file>
<file alias="lock_closed">res/icons/lock_closed.png</file>
<file alias="lock_open">res/icons/lock_open.png</file>
<file alias="key">res/icons/key.png</file>
@@ -84,77 +87,4 @@
<file alias="spinner-033">res/movies/spinner-033.png</file>
<file alias="spinner-034">res/movies/spinner-034.png</file>
</qresource>
- <qresource prefix="/translations">
- <file alias="ach">locale/bitcoin_ach.qm</file>
- <file alias="af_ZA">locale/bitcoin_af_ZA.qm</file>
- <file alias="ar">locale/bitcoin_ar.qm</file>
- <file alias="be_BY">locale/bitcoin_be_BY.qm</file>
- <file alias="bg">locale/bitcoin_bg.qm</file>
- <file alias="bs">locale/bitcoin_bs.qm</file>
- <file alias="ca_ES">locale/bitcoin_ca_ES.qm</file>
- <file alias="ca">locale/bitcoin_ca.qm</file>
- <file alias="ca@valencia">locale/bitcoin_ca@valencia.qm</file>
- <file alias="cmn">locale/bitcoin_cmn.qm</file>
- <file alias="cs">locale/bitcoin_cs.qm</file>
- <file alias="cy">locale/bitcoin_cy.qm</file>
- <file alias="da">locale/bitcoin_da.qm</file>
- <file alias="de">locale/bitcoin_de.qm</file>
- <file alias="el_GR">locale/bitcoin_el_GR.qm</file>
- <file alias="en">locale/bitcoin_en.qm</file>
- <file alias="eo">locale/bitcoin_eo.qm</file>
- <file alias="es_CL">locale/bitcoin_es_CL.qm</file>
- <file alias="es_DO">locale/bitcoin_es_DO.qm</file>
- <file alias="es_MX">locale/bitcoin_es_MX.qm</file>
- <file alias="es">locale/bitcoin_es.qm</file>
- <file alias="es_UY">locale/bitcoin_es_UY.qm</file>
- <file alias="et">locale/bitcoin_et.qm</file>
- <file alias="eu_ES">locale/bitcoin_eu_ES.qm</file>
- <file alias="fa_IR">locale/bitcoin_fa_IR.qm</file>
- <file alias="fa">locale/bitcoin_fa.qm</file>
- <file alias="fi">locale/bitcoin_fi.qm</file>
- <file alias="fr_CA">locale/bitcoin_fr_CA.qm</file>
- <file alias="fr">locale/bitcoin_fr.qm</file>
- <file alias="gl">locale/bitcoin_gl.qm</file>
- <file alias="gu_IN">locale/bitcoin_gu_IN.qm</file>
- <file alias="he">locale/bitcoin_he.qm</file>
- <file alias="hi_IN">locale/bitcoin_hi_IN.qm</file>
- <file alias="hr">locale/bitcoin_hr.qm</file>
- <file alias="hu">locale/bitcoin_hu.qm</file>
- <file alias="id_ID">locale/bitcoin_id_ID.qm</file>
- <file alias="it">locale/bitcoin_it.qm</file>
- <file alias="ja">locale/bitcoin_ja.qm</file>
- <file alias="ka">locale/bitcoin_ka.qm</file>
- <file alias="kk_KZ">locale/bitcoin_kk_KZ.qm</file>
- <file alias="ko_KR">locale/bitcoin_ko_KR.qm</file>
- <file alias="ky">locale/bitcoin_ky.qm</file>
- <file alias="la">locale/bitcoin_la.qm</file>
- <file alias="lt">locale/bitcoin_lt.qm</file>
- <file alias="lv_LV">locale/bitcoin_lv_LV.qm</file>
- <file alias="mn">locale/bitcoin_mn.qm</file>
- <file alias="ms_MY">locale/bitcoin_ms_MY.qm</file>
- <file alias="nb">locale/bitcoin_nb.qm</file>
- <file alias="nl">locale/bitcoin_nl.qm</file>
- <file alias="pam">locale/bitcoin_pam.qm</file>
- <file alias="pl">locale/bitcoin_pl.qm</file>
- <file alias="pt_BR">locale/bitcoin_pt_BR.qm</file>
- <file alias="pt_PT">locale/bitcoin_pt_PT.qm</file>
- <file alias="ro_RO">locale/bitcoin_ro_RO.qm</file>
- <file alias="ru">locale/bitcoin_ru.qm</file>
- <file alias="sah">locale/bitcoin_sah.qm</file>
- <file alias="sk">locale/bitcoin_sk.qm</file>
- <file alias="sl_SI">locale/bitcoin_sl_SI.qm</file>
- <file alias="sq">locale/bitcoin_sq.qm</file>
- <file alias="sr">locale/bitcoin_sr.qm</file>
- <file alias="sv">locale/bitcoin_sv.qm</file>
- <file alias="th_TH">locale/bitcoin_th_TH.qm</file>
- <file alias="tr">locale/bitcoin_tr.qm</file>
- <file alias="uk">locale/bitcoin_uk.qm</file>
- <file alias="ur_PK">locale/bitcoin_ur_PK.qm</file>
- <file alias="uz@Cyrl">locale/bitcoin_uz@Cyrl.qm</file>
- <file alias="vi">locale/bitcoin_vi.qm</file>
- <file alias="vi_VN">locale/bitcoin_vi_VN.qm</file>
- <file alias="zh_CN">locale/bitcoin_zh_CN.qm</file>
- <file alias="zh_HK">locale/bitcoin_zh_HK.qm</file>
- <file alias="zh_TW">locale/bitcoin_zh_TW.qm</file>
- </qresource>
</RCC>
diff --git a/src/qt/bitcoin_locale.qrc b/src/qt/bitcoin_locale.qrc
new file mode 100644
index 0000000000..b70a107397
--- /dev/null
+++ b/src/qt/bitcoin_locale.qrc
@@ -0,0 +1,75 @@
+<!DOCTYPE RCC><RCC version="1.0">
+ <qresource prefix="/translations">
+ <file alias="ach">locale/bitcoin_ach.qm</file>
+ <file alias="af_ZA">locale/bitcoin_af_ZA.qm</file>
+ <file alias="ar">locale/bitcoin_ar.qm</file>
+ <file alias="be_BY">locale/bitcoin_be_BY.qm</file>
+ <file alias="bg">locale/bitcoin_bg.qm</file>
+ <file alias="bs">locale/bitcoin_bs.qm</file>
+ <file alias="ca_ES">locale/bitcoin_ca_ES.qm</file>
+ <file alias="ca">locale/bitcoin_ca.qm</file>
+ <file alias="ca@valencia">locale/bitcoin_ca@valencia.qm</file>
+ <file alias="cmn">locale/bitcoin_cmn.qm</file>
+ <file alias="cs">locale/bitcoin_cs.qm</file>
+ <file alias="cy">locale/bitcoin_cy.qm</file>
+ <file alias="da">locale/bitcoin_da.qm</file>
+ <file alias="de">locale/bitcoin_de.qm</file>
+ <file alias="el_GR">locale/bitcoin_el_GR.qm</file>
+ <file alias="en">locale/bitcoin_en.qm</file>
+ <file alias="eo">locale/bitcoin_eo.qm</file>
+ <file alias="es_CL">locale/bitcoin_es_CL.qm</file>
+ <file alias="es_DO">locale/bitcoin_es_DO.qm</file>
+ <file alias="es_MX">locale/bitcoin_es_MX.qm</file>
+ <file alias="es">locale/bitcoin_es.qm</file>
+ <file alias="es_UY">locale/bitcoin_es_UY.qm</file>
+ <file alias="et">locale/bitcoin_et.qm</file>
+ <file alias="eu_ES">locale/bitcoin_eu_ES.qm</file>
+ <file alias="fa_IR">locale/bitcoin_fa_IR.qm</file>
+ <file alias="fa">locale/bitcoin_fa.qm</file>
+ <file alias="fi">locale/bitcoin_fi.qm</file>
+ <file alias="fr_CA">locale/bitcoin_fr_CA.qm</file>
+ <file alias="fr">locale/bitcoin_fr.qm</file>
+ <file alias="gl">locale/bitcoin_gl.qm</file>
+ <file alias="gu_IN">locale/bitcoin_gu_IN.qm</file>
+ <file alias="he">locale/bitcoin_he.qm</file>
+ <file alias="hi_IN">locale/bitcoin_hi_IN.qm</file>
+ <file alias="hr">locale/bitcoin_hr.qm</file>
+ <file alias="hu">locale/bitcoin_hu.qm</file>
+ <file alias="id_ID">locale/bitcoin_id_ID.qm</file>
+ <file alias="it">locale/bitcoin_it.qm</file>
+ <file alias="ja">locale/bitcoin_ja.qm</file>
+ <file alias="ka">locale/bitcoin_ka.qm</file>
+ <file alias="kk_KZ">locale/bitcoin_kk_KZ.qm</file>
+ <file alias="ko_KR">locale/bitcoin_ko_KR.qm</file>
+ <file alias="ky">locale/bitcoin_ky.qm</file>
+ <file alias="la">locale/bitcoin_la.qm</file>
+ <file alias="lt">locale/bitcoin_lt.qm</file>
+ <file alias="lv_LV">locale/bitcoin_lv_LV.qm</file>
+ <file alias="mn">locale/bitcoin_mn.qm</file>
+ <file alias="ms_MY">locale/bitcoin_ms_MY.qm</file>
+ <file alias="nb">locale/bitcoin_nb.qm</file>
+ <file alias="nl">locale/bitcoin_nl.qm</file>
+ <file alias="pam">locale/bitcoin_pam.qm</file>
+ <file alias="pl">locale/bitcoin_pl.qm</file>
+ <file alias="pt_BR">locale/bitcoin_pt_BR.qm</file>
+ <file alias="pt_PT">locale/bitcoin_pt_PT.qm</file>
+ <file alias="ro_RO">locale/bitcoin_ro_RO.qm</file>
+ <file alias="ru">locale/bitcoin_ru.qm</file>
+ <file alias="sah">locale/bitcoin_sah.qm</file>
+ <file alias="sk">locale/bitcoin_sk.qm</file>
+ <file alias="sl_SI">locale/bitcoin_sl_SI.qm</file>
+ <file alias="sq">locale/bitcoin_sq.qm</file>
+ <file alias="sr">locale/bitcoin_sr.qm</file>
+ <file alias="sv">locale/bitcoin_sv.qm</file>
+ <file alias="th_TH">locale/bitcoin_th_TH.qm</file>
+ <file alias="tr">locale/bitcoin_tr.qm</file>
+ <file alias="uk">locale/bitcoin_uk.qm</file>
+ <file alias="ur_PK">locale/bitcoin_ur_PK.qm</file>
+ <file alias="uz@Cyrl">locale/bitcoin_uz@Cyrl.qm</file>
+ <file alias="vi">locale/bitcoin_vi.qm</file>
+ <file alias="vi_VN">locale/bitcoin_vi_VN.qm</file>
+ <file alias="zh_CN">locale/bitcoin_zh_CN.qm</file>
+ <file alias="zh_HK">locale/bitcoin_zh_HK.qm</file>
+ <file alias="zh_TW">locale/bitcoin_zh_TW.qm</file>
+ </qresource>
+</RCC>
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index e6190aec13..6b3aa2a2df 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -28,18 +28,18 @@
#include <iostream>
+#include <QAction>
#include <QApplication>
#include <QDateTime>
#include <QDesktopWidget>
#include <QDragEnterEvent>
#include <QIcon>
-#include <QLabel>
#include <QListWidget>
-#include <QMenu>
#include <QMenuBar>
#include <QMessageBox>
#include <QMimeData>
#include <QProgressBar>
+#include <QProgressDialog>
#include <QSettings>
#include <QStackedWidget>
#include <QStatusBar>
@@ -155,10 +155,13 @@ BitcoinGUI::BitcoinGUI(bool fIsTestnet, QWidget *parent) :
QHBoxLayout *frameBlocksLayout = new QHBoxLayout(frameBlocks);
frameBlocksLayout->setContentsMargins(3,0,3,0);
frameBlocksLayout->setSpacing(3);
+ unitDisplayControl = new UnitDisplayStatusBarControl();
labelEncryptionIcon = new QLabel();
labelConnectionsIcon = new QLabel();
labelBlocksIcon = new QLabel();
frameBlocksLayout->addStretch();
+ frameBlocksLayout->addWidget(unitDisplayControl);
+ frameBlocksLayout->addStretch();
frameBlocksLayout->addWidget(labelEncryptionIcon);
frameBlocksLayout->addStretch();
frameBlocksLayout->addWidget(labelConnectionsIcon);
@@ -188,7 +191,7 @@ BitcoinGUI::BitcoinGUI(bool fIsTestnet, QWidget *parent) :
connect(openRPCConsoleAction, SIGNAL(triggered()), rpcConsole, SLOT(show()));
- // prevents an oben debug window from becoming stuck/unusable on client shutdown
+ // prevents an open debug window from becoming stuck/unusable on client shutdown
connect(quitAction, SIGNAL(triggered()), rpcConsole, SLOT(hide()));
// Install event filter to be able to catch status tip events (QEvent::StatusTip)
@@ -409,6 +412,9 @@ void BitcoinGUI::setClientModel(ClientModel *clientModel)
// Receive and report messages from client model
connect(clientModel, SIGNAL(message(QString,QString,unsigned int)), this, SLOT(message(QString,QString,unsigned int)));
+ // Show progress dialog
+ connect(clientModel, SIGNAL(showProgress(QString,int)), this, SLOT(showProgress(QString,int)));
+
rpcConsole->setClientModel(clientModel);
#ifdef ENABLE_WALLET
if(walletFrame)
@@ -416,6 +422,8 @@ void BitcoinGUI::setClientModel(ClientModel *clientModel)
walletFrame->setClientModel(clientModel);
}
#endif
+
+ this->unitDisplayControl->setOptionsModel(clientModel->getOptionsModel());
}
}
@@ -545,14 +553,13 @@ void BitcoinGUI::aboutClicked()
if(!clientModel)
return;
- AboutDialog dlg(this);
- dlg.setModel(clientModel);
+ HelpMessageDialog dlg(this, true);
dlg.exec();
}
void BitcoinGUI::showHelpMessageClicked()
{
- HelpMessageDialog *help = new HelpMessageDialog(this);
+ HelpMessageDialog *help = new HelpMessageDialog(this, false);
help->setAttribute(Qt::WA_DeleteOnClose);
help->show();
}
@@ -949,6 +956,29 @@ void BitcoinGUI::detectShutdown()
}
}
+void BitcoinGUI::showProgress(const QString &title, int nProgress)
+{
+ if (nProgress == 0)
+ {
+ progressDialog = new QProgressDialog(title, "", 0, 100);
+ progressDialog->setWindowModality(Qt::ApplicationModal);
+ progressDialog->setMinimumDuration(0);
+ progressDialog->setCancelButton(0);
+ progressDialog->setAutoClose(false);
+ progressDialog->setValue(0);
+ }
+ else if (nProgress == 100)
+ {
+ if (progressDialog)
+ {
+ progressDialog->close();
+ progressDialog->deleteLater();
+ }
+ }
+ else if (progressDialog)
+ progressDialog->setValue(nProgress);
+}
+
static bool ThreadSafeMessageBox(BitcoinGUI *gui, const std::string& message, const std::string& caption, unsigned int style)
{
bool modal = (style & CClientUIInterface::MODAL);
@@ -974,3 +1004,71 @@ void BitcoinGUI::unsubscribeFromCoreSignals()
// Disconnect signals from client
uiInterface.ThreadSafeMessageBox.disconnect(boost::bind(ThreadSafeMessageBox, this, _1, _2, _3));
}
+
+UnitDisplayStatusBarControl::UnitDisplayStatusBarControl():QLabel()
+{
+ optionsModel = 0;
+ createContextMenu();
+ setToolTip(tr("Unit to show amounts in. Click to select another unit."));
+}
+
+/** So that it responds to left-button clicks */
+void UnitDisplayStatusBarControl::mousePressEvent(QMouseEvent *event)
+{
+ onDisplayUnitsClicked(event->pos());
+}
+
+/** Creates context menu, its actions, and wires up all the relevant signals for mouse events. */
+void UnitDisplayStatusBarControl::createContextMenu()
+{
+ menu = new QMenu();
+ foreach(BitcoinUnits::Unit u, BitcoinUnits::availableUnits())
+ {
+ QAction *menuAction = new QAction(QString(BitcoinUnits::name(u)), this);
+ menuAction->setData(QVariant(u));
+ menu->addAction(menuAction);
+ }
+ connect(menu,SIGNAL(triggered(QAction*)),this,SLOT(onMenuSelection(QAction*)));
+
+ // what happens on right click.
+ setContextMenuPolicy(Qt::CustomContextMenu);
+ connect(this,SIGNAL(customContextMenuRequested(const QPoint&)),this,SLOT(onDisplayUnitsClicked(const QPoint&)));
+}
+
+/** Lets the control know about the Options Model (and its signals) */
+void UnitDisplayStatusBarControl::setOptionsModel(OptionsModel *optionsModel)
+{
+ if (optionsModel)
+ {
+ this->optionsModel = optionsModel;
+
+ // be aware of a display unit change reported by the OptionsModel object.
+ connect(optionsModel,SIGNAL(displayUnitChanged(int)),this,SLOT(updateDisplayUnit(int)));
+
+ // initialize the display units label with the current value in the model.
+ updateDisplayUnit(optionsModel->getDisplayUnit());
+ }
+}
+
+/** When Display Units are changed on OptionsModel it will refresh the display text of the control on the status bar */
+void UnitDisplayStatusBarControl::updateDisplayUnit(int newUnits)
+{
+ setPixmap(QIcon(":/icons/unit_" + BitcoinUnits::id(newUnits)).pixmap(31,STATUSBAR_ICONSIZE));
+}
+
+/** Shows context menu with Display Unit options by the mouse coordinates */
+void UnitDisplayStatusBarControl::onDisplayUnitsClicked(const QPoint& point)
+{
+ QPoint globalPos = mapToGlobal(point);
+ menu->exec(globalPos);
+}
+
+/** Tells underlying optionsModel to update its current display unit. */
+void UnitDisplayStatusBarControl::onMenuSelection(QAction* action)
+{
+ if (action)
+ {
+ optionsModel->setDisplayUnit(action->data());
+ }
+}
+
diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h
index b4675b95ac..30dd7ae317 100644
--- a/src/qt/bitcoingui.h
+++ b/src/qt/bitcoingui.h
@@ -6,17 +6,22 @@
#define BITCOINGUI_H
#if defined(HAVE_CONFIG_H)
-#include "bitcoin-config.h"
+#include "config/bitcoin-config.h"
#endif
+#include <QLabel>
#include <QMainWindow>
#include <QMap>
+#include <QMenu>
+#include <QPoint>
#include <QSystemTrayIcon>
class ClientModel;
class Notificator;
+class OptionsModel;
class RPCConsole;
class SendCoinsRecipient;
+class UnitDisplayStatusBarControl;
class WalletFrame;
class WalletModel;
@@ -24,8 +29,8 @@ class CWallet;
QT_BEGIN_NAMESPACE
class QAction;
-class QLabel;
class QProgressBar;
+class QProgressDialog;
QT_END_NAMESPACE
/**
@@ -68,11 +73,13 @@ private:
ClientModel *clientModel;
WalletFrame *walletFrame;
+ UnitDisplayStatusBarControl *unitDisplayControl;
QLabel *labelEncryptionIcon;
QLabel *labelConnectionsIcon;
QLabel *labelBlocksIcon;
QLabel *progressBarLabel;
QProgressBar *progressBar;
+ QProgressDialog *progressDialog;
QMenuBar *appMenuBar;
QAction *overviewAction;
@@ -191,6 +198,37 @@ private slots:
/** called by a timer to check if fRequestShutdown has been set **/
void detectShutdown();
+
+ /** Show progress dialog e.g. for verifychain */
+ void showProgress(const QString &title, int nProgress);
+};
+
+class UnitDisplayStatusBarControl : public QLabel
+{
+ Q_OBJECT
+
+public:
+ explicit UnitDisplayStatusBarControl();
+ /** Lets the control know about the Options Model (and its signals) */
+ void setOptionsModel(OptionsModel *optionsModel);
+
+protected:
+ /** So that it responds to left-button clicks */
+ void mousePressEvent(QMouseEvent *event);
+
+private:
+ OptionsModel *optionsModel;
+ QMenu* menu;
+ /** Shows context menu with Display Unit options by the mouse coordinates */
+ void onDisplayUnitsClicked(const QPoint& point);
+ /** Creates context menu, its actions, and wires up all the relevant signals for mouse events. */
+ void createContextMenu();
+
+private slots:
+ /** When Display Units are changed on OptionsModel it will refresh the display text of the control on the status bar */
+ void updateDisplayUnit(int newUnits);
+ /** Tells underlying optionsModel to update its current display unit. */
+ void onMenuSelection(QAction* action);
};
#endif // BITCOINGUI_H
diff --git a/src/qt/bitcoinstrings.cpp b/src/qt/bitcoinstrings.cpp
index 10b44bbc3f..e852c468a8 100644
--- a/src/qt/bitcoinstrings.cpp
+++ b/src/qt/bitcoinstrings.cpp
@@ -22,31 +22,42 @@ 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", ""
+"(default: 1, 1 = keep tx meta data e.g. account owner and payment request "
+"information, 2 = drop tx meta data)"),
+QT_TRANSLATE_NOOP("bitcoin-core", ""
"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"),
+"Allow JSON-RPC connections from specified source. Valid for <ip> are a "
+"single IP (e.g. 1.2.3.4), a network/netmask (e.g. 1.2.3.4/255.255.255.0) or "
+"a network/CIDR (e.g. 1.2.3.4/24). This option can be specified multiple times"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
-"An error occurred while setting up the RPC port %u for listening on IPv6, "
-"falling back to IPv4: %s"),
+"An error occurred while setting up the RPC address %s port %u for listening: "
+"%s"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Bind to given address and always listen on it. Use [host]:port notation for "
"IPv6"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
+"Bind to given address to listen for JSON-RPC connections. Use [host]:port "
+"notation for IPv6. This option can be specified multiple times (default: "
+"bind to all interfaces)"),
+QT_TRANSLATE_NOOP("bitcoin-core", ""
"Cannot obtain a lock on data directory %s. Bitcoin Core is probably already "
"running."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Continuously rate-limit free transactions to <n>*1000 bytes per minute "
"(default:15)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
-"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."),
+"Delete all wallet transactions and only recover those part of the blockchain "
+"through -rescan on startup"),
+QT_TRANSLATE_NOOP("bitcoin-core", ""
+"Distributed under the MIT/X11 software license, see the accompanying file "
+"COPYING or <http://www.opensource.org/licenses/mit-license.php>."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Enter regression test mode, which uses a special chain in which blocks can "
"be solved instantly."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
-"Error: Listening for incoming connections failed (listen returned error %d)"),
+"Error: Listening for incoming connections failed (listen returned error %s)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"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 "
@@ -55,6 +66,9 @@ QT_TRANSLATE_NOOP("bitcoin-core", ""
"Error: This transaction requires a transaction fee of at least %s because of "
"its amount, complexity, or use of recently received funds!"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
+"Execute command when a network tx respends wallet tx input (%s=respend TxID, "
+"%t=wallet TxID)"),
+QT_TRANSLATE_NOOP("bitcoin-core", ""
"Execute command when a relevant alert is received or we see a really long "
"fork (%s in cmd is replaced by message)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
@@ -64,14 +78,20 @@ QT_TRANSLATE_NOOP("bitcoin-core", ""
"Execute command when the best block changes (%s in cmd is replaced by block "
"hash)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
-"Fees smaller than this are considered zero fee (for transaction creation) "
-"(default:"),
+"Fees (in BTC/Kb) smaller than this are considered zero fee for relaying "
+"(default: %s)"),
+QT_TRANSLATE_NOOP("bitcoin-core", ""
+"Fees (in BTC/Kb) smaller than this are considered zero fee for transaction "
+"creation (default: %s)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Flush database activity from memory pool to disk log every <n> megabytes "
"(default: 100)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"How thorough the block verification of -checkblocks is (0-4, default: 3)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
+"If paytxfee is not set, include enough fee so transactions are confirmed on "
+"average within n blocks (default: 1)"),
+QT_TRANSLATE_NOOP("bitcoin-core", ""
"In this mode -genproclimit controls how many blocks are generated "
"immediately."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
@@ -93,6 +113,10 @@ QT_TRANSLATE_NOOP("bitcoin-core", ""
"This is a pre-release test build - use at your own risk - do not use for "
"mining or merchant applications"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
+"This product includes software developed by the OpenSSL Project for use in "
+"the OpenSSL Toolkit <https://www.openssl.org/> and cryptographic software "
+"written by Eric Young and UPnP software written by Thomas Bernard."),
+QT_TRANSLATE_NOOP("bitcoin-core", ""
"Unable to bind to %s on this computer. Bitcoin Core is probably already "
"running."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
@@ -117,11 +141,6 @@ QT_TRANSLATE_NOOP("bitcoin-core", ""
"Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as "
"wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect "
"you should restore from a backup."),
-QT_TRANSLATE_NOOP("bitcoin-core", ""
-"You must set rpcpassword=<password> in the configuration file:\n"
-"%s\n"
-"If the file does not exist, create it with owner-readable-only file "
-"permissions."),
QT_TRANSLATE_NOOP("bitcoin-core", "(default: 1)"),
QT_TRANSLATE_NOOP("bitcoin-core", "(default: wallet.dat)"),
QT_TRANSLATE_NOOP("bitcoin-core", "<category> can be:"),
@@ -129,22 +148,19 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Accept command line and JSON-RPC commands"),
QT_TRANSLATE_NOOP("bitcoin-core", "Accept connections from outside (default: 1 if no -proxy or -connect)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Add a node to connect to and attempt to keep the connection open"),
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 Core Daemon"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Bitcoin Core RPC client version"),
QT_TRANSLATE_NOOP("bitcoin-core", "Block creation options:"),
QT_TRANSLATE_NOOP("bitcoin-core", "Cannot downgrade wallet"),
QT_TRANSLATE_NOOP("bitcoin-core", "Cannot resolve -bind address: '%s'"),
QT_TRANSLATE_NOOP("bitcoin-core", "Cannot resolve -externalip address: '%s'"),
QT_TRANSLATE_NOOP("bitcoin-core", "Cannot write default address"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Clear list of wallet transactions (diagnostic tool; implies -rescan)"),
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", "Connection options:"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Copyright (C) 2009-%i The Bitcoin Core Developers"),
QT_TRANSLATE_NOOP("bitcoin-core", "Corrupted block database detected"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Could not parse -rpcbind value %s as network address"),
QT_TRANSLATE_NOOP("bitcoin-core", "Debugging/Testing options:"),
QT_TRANSLATE_NOOP("bitcoin-core", "Disable safemode, override a real safe mode event (default: 0)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Discover own IP address (default: 1 when listening and no -externalip)"),
@@ -160,6 +176,7 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Error loading wallet.dat: Wallet requires new
QT_TRANSLATE_NOOP("bitcoin-core", "Error opening block database"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error: Disk space is low!"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Error: Unsupported argument -tor found, use -onion."),
QT_TRANSLATE_NOOP("bitcoin-core", "Error: Wallet locked, unable to create transaction!"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error: system error: "),
QT_TRANSLATE_NOOP("bitcoin-core", "Failed to listen on any port. Use -listen=0 if you want this."),
@@ -173,27 +190,28 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Failed to write file info"),
QT_TRANSLATE_NOOP("bitcoin-core", "Failed to write to coin database"),
QT_TRANSLATE_NOOP("bitcoin-core", "Failed to write transaction index"),
QT_TRANSLATE_NOOP("bitcoin-core", "Failed to write undo data"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Fee per kB to add to transactions you send"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Fees smaller than this are considered zero fee (for relaying) (default:"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Fee (in BTC/kB) to add to transactions you send (default: %s)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Find peers using DNS lookup (default: 1 unless -connect)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Force safe mode (default: 0)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Generate coins (default: 0)"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Get help for a command"),
QT_TRANSLATE_NOOP("bitcoin-core", "How many blocks to check at startup (default: 288, 0 = all)"),
QT_TRANSLATE_NOOP("bitcoin-core", "If <category> is not supplied, output all debugging information."),
QT_TRANSLATE_NOOP("bitcoin-core", "Importing..."),
QT_TRANSLATE_NOOP("bitcoin-core", "Imports blocks from external blk000??.dat file"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Include IP addresses in debug output (default: 0)"),
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", "Initialization sanity check failed. Bitcoin Core is shutting down."),
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 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' (must be at least %s)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Invalid amount for -paytxfee=<amount>: '%s'"),
QT_TRANSLATE_NOOP("bitcoin-core", "Invalid amount"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Keep at most <n> unconnectable blocks in memory (default: %u)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Limit size of signature cache to <n> entries (default: 50000)"),
-QT_TRANSLATE_NOOP("bitcoin-core", "List commands"),
QT_TRANSLATE_NOOP("bitcoin-core", "Listen for connections on <port> (default: 8333 or testnet: 18333)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Loading addresses..."),
QT_TRANSLATE_NOOP("bitcoin-core", "Loading block index..."),
@@ -203,6 +221,7 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Maintain a full transaction index (default: 0
QT_TRANSLATE_NOOP("bitcoin-core", "Maintain at most <n> connections to peers (default: 125)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Maximum per-connection receive buffer, <n>*1000 bytes (default: 5000)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Maximum per-connection send buffer, <n>*1000 bytes (default: 1000)"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Node relay options:"),
QT_TRANSLATE_NOOP("bitcoin-core", "Not enough file descriptors available."),
QT_TRANSLATE_NOOP("bitcoin-core", "Only accept block chain matching built-in checkpoints (default: 1)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Only connect to nodes in network <net> (IPv4, IPv6 or Tor)"),
@@ -212,19 +231,16 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Prepend debug output with timestamp (default:
QT_TRANSLATE_NOOP("bitcoin-core", "Print block on startup, if found in block index"),
QT_TRANSLATE_NOOP("bitcoin-core", "Print block tree on startup (default: 0)"),
QT_TRANSLATE_NOOP("bitcoin-core", "RPC SSL options: (see the Bitcoin Wiki for SSL setup instructions)"),
-QT_TRANSLATE_NOOP("bitcoin-core", "RPC client options:"),
QT_TRANSLATE_NOOP("bitcoin-core", "RPC server options:"),
QT_TRANSLATE_NOOP("bitcoin-core", "Randomly drop 1 of every <n> network messages"),
QT_TRANSLATE_NOOP("bitcoin-core", "Randomly fuzz 1 of every <n> network messages"),
QT_TRANSLATE_NOOP("bitcoin-core", "Rebuild block chain index from current blk000??.dat files"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Relay and mine data carrier transactions (default: 1)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Rescan the block chain for missing wallet transactions"),
QT_TRANSLATE_NOOP("bitcoin-core", "Rescanning..."),
QT_TRANSLATE_NOOP("bitcoin-core", "Run a thread to flush wallet periodically (default: 1)"),
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 SOCKS version for -proxy (4 or 5, default: 5)"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Send command to Bitcoin Core"),
-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", "Server certificate file (default: server.cert)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Server private key (default: server.pem)"),
@@ -245,21 +261,20 @@ 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", "Spend unconfirmed change when sending transactions (default: 1)"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Start Bitcoin Core Daemon"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Stop running after importing blocks from disk (default: 0)"),
QT_TRANSLATE_NOOP("bitcoin-core", "System error: "),
QT_TRANSLATE_NOOP("bitcoin-core", "This help message"),
+QT_TRANSLATE_NOOP("bitcoin-core", "This is experimental software."),
QT_TRANSLATE_NOOP("bitcoin-core", "This is intended for regression testing tools and app development."),
QT_TRANSLATE_NOOP("bitcoin-core", "Threshold for disconnecting misbehaving peers (default: 100)"),
QT_TRANSLATE_NOOP("bitcoin-core", "To use the %s option"),
QT_TRANSLATE_NOOP("bitcoin-core", "Transaction amount too small"),
QT_TRANSLATE_NOOP("bitcoin-core", "Transaction amounts must be positive"),
QT_TRANSLATE_NOOP("bitcoin-core", "Transaction too large"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Unable to bind to %s on this computer (bind returned error %d, %s)"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Unable to bind to %s on this computer (bind returned error %s)"),
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)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Use UPnP to map the listening port (default: 1 when listening)"),
@@ -267,7 +282,6 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Use the test network"),
QT_TRANSLATE_NOOP("bitcoin-core", "Username for JSON-RPC connections"),
QT_TRANSLATE_NOOP("bitcoin-core", "Verifying blocks..."),
QT_TRANSLATE_NOOP("bitcoin-core", "Verifying wallet..."),
-QT_TRANSLATE_NOOP("bitcoin-core", "Wait for RPC server to start"),
QT_TRANSLATE_NOOP("bitcoin-core", "Wallet %s resides outside data directory %s"),
QT_TRANSLATE_NOOP("bitcoin-core", "Wallet needed to be rewritten: restart Bitcoin to complete"),
QT_TRANSLATE_NOOP("bitcoin-core", "Wallet options:"),
@@ -277,6 +291,5 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Warning: This version is obsolete, upgrade re
QT_TRANSLATE_NOOP("bitcoin-core", "You need to rebuild the database using -reindex to change -txindex"),
QT_TRANSLATE_NOOP("bitcoin-core", "Zapping all transactions from wallet..."),
QT_TRANSLATE_NOOP("bitcoin-core", "on startup"),
-QT_TRANSLATE_NOOP("bitcoin-core", "version"),
QT_TRANSLATE_NOOP("bitcoin-core", "wallet.dat corrupt, salvage failed"),
};
diff --git a/src/qt/bitcoinunits.cpp b/src/qt/bitcoinunits.cpp
index 2fed443cf2..bbc9b2e5af 100644
--- a/src/qt/bitcoinunits.cpp
+++ b/src/qt/bitcoinunits.cpp
@@ -34,6 +34,17 @@ bool BitcoinUnits::valid(int unit)
}
}
+QString BitcoinUnits::id(int unit)
+{
+ switch(unit)
+ {
+ case BTC: return QString("btc");
+ case mBTC: return QString("mbtc");
+ case uBTC: return QString("ubtc");
+ default: return QString("???");
+ }
+}
+
QString BitcoinUnits::name(int unit)
{
switch(unit)
@@ -169,6 +180,16 @@ bool BitcoinUnits::parse(int unit, const QString &value, qint64 *val_out)
return ok;
}
+QString BitcoinUnits::getAmountColumnTitle(int unit)
+{
+ QString amountTitle = QObject::tr("Amount");
+ if (BitcoinUnits::valid(unit))
+ {
+ amountTitle += " ("+BitcoinUnits::name(unit) + ")";
+ }
+ return amountTitle;
+}
+
int BitcoinUnits::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
diff --git a/src/qt/bitcoinunits.h b/src/qt/bitcoinunits.h
index 46517fc07b..da34ed8976 100644
--- a/src/qt/bitcoinunits.h
+++ b/src/qt/bitcoinunits.h
@@ -36,6 +36,8 @@ public:
static QList<Unit> availableUnits();
//! Is unit ID valid?
static bool valid(int unit);
+ //! Identifier, e.g. for image names
+ static QString id(int unit);
//! Short name
static QString name(int unit);
//! Longer description
@@ -54,6 +56,8 @@ public:
static QString formatWithUnit(int unit, qint64 amount, bool plussign=false);
//! Parse string to coin amount
static bool parse(int unit, const QString &value, qint64 *val_out);
+ //! Gets title for amount column including current display unit if optionsModel reference available */
+ static QString getAmountColumnTitle(int unit);
///@}
//! @name AbstractListModel implementation
diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp
index d1f68ebd22..4c21eb5594 100644
--- a/src/qt/clientmodel.cpp
+++ b/src/qt/clientmodel.cpp
@@ -5,6 +5,7 @@
#include "clientmodel.h"
#include "guiconstants.h"
+#include "peertablemodel.h"
#include "alert.h"
#include "chainparams.h"
@@ -22,11 +23,14 @@
static const int64_t nClientStartupTime = GetTime();
ClientModel::ClientModel(OptionsModel *optionsModel, QObject *parent) :
- QObject(parent), optionsModel(optionsModel),
+ QObject(parent),
+ optionsModel(optionsModel),
+ peerTableModel(0),
cachedNumBlocks(0),
cachedReindexing(0), cachedImporting(0),
numBlocksAtStartup(-1), pollTimer(0)
{
+ peerTableModel = new PeerTableModel(this);
pollTimer = new QTimer(this);
connect(pollTimer, SIGNAL(timeout()), this, SLOT(updateTimer()));
pollTimer->start(MODEL_UPDATE_DELAY);
@@ -81,7 +85,7 @@ QDateTime ClientModel::getLastBlockDate() const
if (chainActive.Tip())
return QDateTime::fromTime_t(chainActive.Tip()->GetBlockTime());
else
- return QDateTime::fromTime_t(Params().GenesisBlock().nTime); // Genesis block's time of current network
+ return QDateTime::fromTime_t(Params().GenesisBlock().GetBlockTime()); // Genesis block's time of current network
}
double ClientModel::getVerificationProgress() const
@@ -138,14 +142,6 @@ void ClientModel::updateAlert(const QString &hash, int status)
emit alertsChanged(getStatusBarWarnings());
}
-QString ClientModel::getNetworkName() const
-{
- QString netname(QString::fromStdString(Params().DataDir()));
- if(netname.isEmpty())
- netname = "main";
- return netname;
-}
-
bool ClientModel::inInitialBlockDownload() const
{
return IsInitialBlockDownload();
@@ -173,6 +169,11 @@ OptionsModel *ClientModel::getOptionsModel()
return optionsModel;
}
+PeerTableModel *ClientModel::getPeerTableModel()
+{
+ return peerTableModel;
+}
+
QString ClientModel::formatFullVersion() const
{
return QString::fromStdString(FormatFullVersion());
@@ -199,6 +200,14 @@ QString ClientModel::formatClientStartupTime() const
}
// Handlers for core signals
+static void ShowProgress(ClientModel *clientmodel, const std::string &title, int nProgress)
+{
+ // emits signal "showProgress"
+ QMetaObject::invokeMethod(clientmodel, "showProgress", Qt::QueuedConnection,
+ Q_ARG(QString, QString::fromStdString(title)),
+ Q_ARG(int, nProgress));
+}
+
static void NotifyBlocksChanged(ClientModel *clientmodel)
{
// This notification is too frequent. Don't trigger a signal.
@@ -223,6 +232,7 @@ static void NotifyAlertChanged(ClientModel *clientmodel, const uint256 &hash, Ch
void ClientModel::subscribeToCoreSignals()
{
// Connect signals to client
+ uiInterface.ShowProgress.connect(boost::bind(ShowProgress, this, _1, _2));
uiInterface.NotifyBlocksChanged.connect(boost::bind(NotifyBlocksChanged, this));
uiInterface.NotifyNumConnectionsChanged.connect(boost::bind(NotifyNumConnectionsChanged, this, _1));
uiInterface.NotifyAlertChanged.connect(boost::bind(NotifyAlertChanged, this, _1, _2));
@@ -231,6 +241,7 @@ void ClientModel::subscribeToCoreSignals()
void ClientModel::unsubscribeFromCoreSignals()
{
// Disconnect signals from client
+ uiInterface.ShowProgress.disconnect(boost::bind(ShowProgress, this, _1, _2));
uiInterface.NotifyBlocksChanged.disconnect(boost::bind(NotifyBlocksChanged, this));
uiInterface.NotifyNumConnectionsChanged.disconnect(boost::bind(NotifyNumConnectionsChanged, this, _1));
uiInterface.NotifyAlertChanged.disconnect(boost::bind(NotifyAlertChanged, this, _1, _2));
diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h
index cab853d92d..c7bd60bd41 100644
--- a/src/qt/clientmodel.h
+++ b/src/qt/clientmodel.h
@@ -9,6 +9,7 @@
class AddressTableModel;
class OptionsModel;
+class PeerTableModel;
class TransactionTableModel;
class CWallet;
@@ -42,6 +43,7 @@ public:
~ClientModel();
OptionsModel *getOptionsModel();
+ PeerTableModel *getPeerTableModel();
//! Return number of connections, default is in- and outbound (total)
int getNumConnections(unsigned int flags = CONNECTIONS_ALL) const;
@@ -54,8 +56,6 @@ public:
double getVerificationProgress() const;
QDateTime getLastBlockDate() const;
- //! Return network (main, testnet3, regtest)
- QString getNetworkName() const;
//! Return true if core is doing initial block download
bool inInitialBlockDownload() const;
//! Return true if core is importing blocks
@@ -71,6 +71,7 @@ public:
private:
OptionsModel *optionsModel;
+ PeerTableModel *peerTableModel;
int cachedNumBlocks;
bool cachedReindexing;
@@ -92,6 +93,9 @@ signals:
//! Fired when a message should be reported to the user
void message(const QString &title, const QString &message, unsigned int style);
+ // Show progress dialog e.g. for verifychain
+ void showProgress(const QString &title, int nProgress);
+
public slots:
void updateTimer();
void updateNumConnections(int numConnections);
diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp
index dc9d2afe27..b4ddda3eaa 100644
--- a/src/qt/coincontroldialog.cpp
+++ b/src/qt/coincontroldialog.cpp
@@ -16,6 +16,8 @@
#include "main.h"
#include "wallet.h"
+#include <boost/assign/list_of.hpp> // for 'map_list_of()'
+
#include <QApplication>
#include <QCheckBox>
#include <QCursor>
@@ -71,7 +73,7 @@ CoinControlDialog::CoinControlDialog(QWidget *parent) :
QAction *clipboardAfterFeeAction = new QAction(tr("Copy after fee"), this);
QAction *clipboardBytesAction = new QAction(tr("Copy bytes"), this);
QAction *clipboardPriorityAction = new QAction(tr("Copy priority"), this);
- QAction *clipboardLowOutputAction = new QAction(tr("Copy low output"), this);
+ QAction *clipboardLowOutputAction = new QAction(tr("Copy dust"), this);
QAction *clipboardChangeAction = new QAction(tr("Copy change"), this);
connect(clipboardQuantityAction, SIGNAL(triggered()), this, SLOT(clipboardQuantity()));
@@ -309,7 +311,7 @@ void CoinControlDialog::clipboardPriority()
GUIUtil::setClipboard(ui->labelCoinControlPriority->text());
}
-// copy label "Low output" to clipboard
+// copy label "Dust" to clipboard
void CoinControlDialog::clipboardLowOutput()
{
GUIUtil::setClipboard(ui->labelCoinControlLowOutput->text());
@@ -400,23 +402,26 @@ void CoinControlDialog::viewItemChanged(QTreeWidgetItem* item, int column)
}
// return human readable label for priority number
-QString CoinControlDialog::getPriorityLabel(double dPriority)
+QString CoinControlDialog::getPriorityLabel(const CTxMemPool& pool, double dPriority)
{
- if (AllowFree(dPriority)) // at least medium
+ // confirmations -> textual description
+ typedef std::map<unsigned int, QString> PriorityDescription;
+ const static PriorityDescription priorityDescriptions = boost::assign::map_list_of
+ (1, tr("highest"))(2, tr("higher"))(3, tr("high"))
+ (5, tr("medium-high"))(6, tr("medium"))
+ (10, tr("low-medium"))(15, tr("low"))
+ (20, tr("lower"));
+
+ BOOST_FOREACH(const PriorityDescription::value_type& i, priorityDescriptions)
{
- if (AllowFree(dPriority / 1000000)) return tr("highest");
- else if (AllowFree(dPriority / 100000)) return tr("higher");
- else if (AllowFree(dPriority / 10000)) return tr("high");
- else if (AllowFree(dPriority / 1000)) return tr("medium-high");
- else return tr("medium");
- }
- else
- {
- if (AllowFree(dPriority * 10)) return tr("low-medium");
- else if (AllowFree(dPriority * 100)) return tr("low");
- else if (AllowFree(dPriority * 1000)) return tr("lower");
- else return tr("lowest");
+ double p = mempool.estimatePriority(i.first);
+ if (p > 0 && dPriority >= p) return i.second;
}
+ // Note: if mempool hasn't accumulated enough history (estimatePriority
+ // returns -1) we're conservative and classify as "lowest"
+ if (mempool.estimatePriority(nTxConfirmTarget) <= 0 && AllowFree(dPriority))
+ return ">=" + tr("medium");
+ return tr("lowest");
}
// shows count of locked unspent outputs
@@ -439,21 +444,17 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
// nPayAmount
qint64 nPayAmount = 0;
- bool fLowOutput = false;
bool fDust = false;
- CTransaction txDummy;
+ CMutableTransaction txDummy;
foreach(const qint64 &amount, CoinControlDialog::payAmounts)
{
nPayAmount += amount;
if (amount > 0)
{
- if (amount < CENT)
- fLowOutput = true;
-
CTxOut txout(amount, (CScript)vector<unsigned char>(24, 0));
txDummy.vout.push_back(txout);
- if (txout.IsDust(CTransaction::nMinRelayTxFee))
+ if (txout.IsDust(::minRelayTxFee))
fDust = true;
}
}
@@ -522,40 +523,33 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
// Priority
dPriority = dPriorityInputs / (nBytes - nBytesInputs + (nQuantityUncompressed * 29)); // 29 = 180 - 151 (uncompressed public keys are over the limit. max 151 bytes of the input are ignored for priority)
- sPriorityLabel = CoinControlDialog::getPriorityLabel(dPriority);
+ sPriorityLabel = CoinControlDialog::getPriorityLabel(mempool, dPriority);
- // Fee
- int64_t nFee = nTransactionFee * (1 + (int64_t)nBytes / 1000);
+ // Voluntary Fee
+ nPayFee = payTxFee.GetFee(max((unsigned int)1000, nBytes));
// Min Fee
- int64_t nMinFee = GetMinFee(txDummy, nBytes, AllowFree(dPriority), GMF_SEND);
+ if (nPayFee == 0)
+ {
+ nPayFee = CWallet::GetMinimumFee(nBytes, nTxConfirmTarget, mempool);
+
+ double dPriorityNeeded = mempool.estimatePriority(nTxConfirmTarget);
+ if (dPriorityNeeded <= 0 && !AllowFree(dPriority)) // not enough mempool history: never send free
+ dPriorityNeeded = std::numeric_limits<double>::max();
- nPayFee = max(nFee, nMinFee);
+ if (nBytes <= MAX_FREE_TRANSACTION_CREATE_SIZE && dPriority >= dPriorityNeeded)
+ nPayFee = 0;
+ }
if (nPayAmount > 0)
{
nChange = nAmount - nPayFee - nPayAmount;
- // if sub-cent change is required, the fee must be raised to at least CTransaction::nMinTxFee
- if (nPayFee < CTransaction::nMinTxFee && nChange > 0 && nChange < CENT)
- {
- if (nChange < CTransaction::nMinTxFee) // change < 0.0001 => simply move all change to fees
- {
- nPayFee += nChange;
- nChange = 0;
- }
- else
- {
- nChange = nChange + nPayFee - CTransaction::nMinTxFee;
- nPayFee = CTransaction::nMinTxFee;
- }
- }
-
// Never create dust outputs; if we would, just add the dust to the fee.
if (nChange > 0 && nChange < CENT)
{
CTxOut txout(nChange, (CScript)vector<unsigned char>(24, 0));
- if (txout.IsDust(CTransaction::nMinRelayTxFee))
+ if (txout.IsDust(::minRelayTxFee))
{
nPayFee += nChange;
nChange = 0;
@@ -586,7 +580,7 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
QLabel *l7 = dialog->findChild<QLabel *>("labelCoinControlLowOutput");
QLabel *l8 = dialog->findChild<QLabel *>("labelCoinControlChange");
- // enable/disable "low output" and "change"
+ // enable/disable "dust" and "change"
dialog->findChild<QLabel *>("labelCoinControlLowOutputText")->setEnabled(nPayAmount > 0);
dialog->findChild<QLabel *>("labelCoinControlLowOutput") ->setEnabled(nPayAmount > 0);
dialog->findChild<QLabel *>("labelCoinControlChangeText") ->setEnabled(nPayAmount > 0);
@@ -599,35 +593,44 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
l4->setText(BitcoinUnits::formatWithUnit(nDisplayUnit, nAfterFee)); // After Fee
l5->setText(((nBytes > 0) ? "~" : "") + QString::number(nBytes)); // Bytes
l6->setText(sPriorityLabel); // Priority
- l7->setText((fLowOutput ? (fDust ? tr("Dust") : tr("yes")) : tr("no"))); // Low Output / Dust
+ l7->setText(fDust ? tr("yes") : tr("no")); // Dust
l8->setText(BitcoinUnits::formatWithUnit(nDisplayUnit, nChange)); // Change
+ if (nPayFee > 0)
+ {
+ l3->setText("~" + l3->text());
+ l4->setText("~" + l4->text());
+ if (nChange > 0)
+ l8->setText("~" + l8->text());
+ }
// turn labels "red"
- l5->setStyleSheet((nBytes >= 1000) ? "color:red;" : ""); // Bytes >= 1000
+ l5->setStyleSheet((nBytes >= MAX_FREE_TRANSACTION_CREATE_SIZE) ? "color:red;" : "");// Bytes >= 1000
l6->setStyleSheet((dPriority > 0 && !AllowFree(dPriority)) ? "color:red;" : ""); // Priority < "medium"
- l7->setStyleSheet((fLowOutput) ? "color:red;" : ""); // Low Output = "yes"
- l8->setStyleSheet((nChange > 0 && nChange < CENT) ? "color:red;" : ""); // Change < 0.01BTC
+ l7->setStyleSheet((fDust) ? "color:red;" : ""); // Dust = "yes"
// tool tips
QString toolTip1 = tr("This label turns red, if the transaction size is greater than 1000 bytes.") + "<br /><br />";
- toolTip1 += tr("This means a fee of at least %1 per kB is required.").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, CTransaction::nMinTxFee)) + "<br /><br />";
+ toolTip1 += tr("This means a fee of at least %1 per kB is required.").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, CWallet::minTxFee.GetFeePerK())) + "<br /><br />";
toolTip1 += tr("Can vary +/- 1 byte per input.");
QString toolTip2 = tr("Transactions with higher priority are more likely to get included into a block.") + "<br /><br />";
toolTip2 += tr("This label turns red, if the priority is smaller than \"medium\".") + "<br /><br />";
- toolTip2 += tr("This means a fee of at least %1 per kB is required.").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, CTransaction::nMinTxFee));
+ toolTip2 += tr("This means a fee of at least %1 per kB is required.").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, CWallet::minTxFee.GetFeePerK()));
- QString toolTip3 = tr("This label turns red, if any recipient receives an amount smaller than %1.").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, CENT)) + "<br /><br />";
- toolTip3 += tr("This means a fee of at least %1 is required.").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, CTransaction::nMinTxFee)) + "<br /><br />";
- toolTip3 += tr("Amounts below 0.546 times the minimum relay fee are shown as dust.");
+ QString toolTip3 = tr("This label turns red, if any recipient receives an amount smaller than %1.").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, ::minRelayTxFee.GetFee(546)));
- QString toolTip4 = tr("This label turns red, if the change is smaller than %1.").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, CENT)) + "<br /><br />";
- toolTip4 += tr("This means a fee of at least %1 is required.").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, CTransaction::nMinTxFee));
+ // how many satoshis the estimated fee can vary per byte we guess wrong
+ double dFeeVary = (double)std::max(CWallet::minTxFee.GetFeePerK(), std::max(payTxFee.GetFeePerK(), mempool.estimateFee(nTxConfirmTarget).GetFeePerK())) / 1000;
+ QString toolTip4 = tr("Can vary +/- %1 satoshi(s) per input.").arg(dFeeVary);
+ l3->setToolTip(toolTip4);
+ l4->setToolTip(toolTip4);
l5->setToolTip(toolTip1);
l6->setToolTip(toolTip2);
l7->setToolTip(toolTip3);
l8->setToolTip(toolTip4);
+ dialog->findChild<QLabel *>("labelCoinControlFeeText") ->setToolTip(l3->toolTip());
+ dialog->findChild<QLabel *>("labelCoinControlAfterFeeText") ->setToolTip(l4->toolTip());
dialog->findChild<QLabel *>("labelCoinControlBytesText") ->setToolTip(l5->toolTip());
dialog->findChild<QLabel *>("labelCoinControlPriorityText") ->setToolTip(l6->toolTip());
dialog->findChild<QLabel *>("labelCoinControlLowOutputText")->setToolTip(l7->toolTip());
@@ -742,7 +745,7 @@ void CoinControlDialog::updateView()
// priority
double dPriority = ((double)out.tx->vout[out.i].nValue / (nInputSize + 78)) * (out.nDepth+1); // 78 = 2 * 34 + 10
- itemOutput->setText(COLUMN_PRIORITY, CoinControlDialog::getPriorityLabel(dPriority));
+ itemOutput->setText(COLUMN_PRIORITY, CoinControlDialog::getPriorityLabel(mempool, dPriority));
itemOutput->setText(COLUMN_PRIORITY_INT64, strPad(QString::number((int64_t)dPriority), 20, " "));
dPrioritySum += (double)out.tx->vout[out.i].nValue * (out.nDepth+1);
nInputSum += nInputSize;
@@ -775,7 +778,7 @@ void CoinControlDialog::updateView()
itemWalletAddress->setText(COLUMN_CHECKBOX, "(" + QString::number(nChildren) + ")");
itemWalletAddress->setText(COLUMN_AMOUNT, BitcoinUnits::format(nDisplayUnit, nSum));
itemWalletAddress->setText(COLUMN_AMOUNT_INT64, strPad(QString::number(nSum), 15, " "));
- itemWalletAddress->setText(COLUMN_PRIORITY, CoinControlDialog::getPriorityLabel(dPrioritySum));
+ itemWalletAddress->setText(COLUMN_PRIORITY, CoinControlDialog::getPriorityLabel(mempool, dPrioritySum));
itemWalletAddress->setText(COLUMN_PRIORITY_INT64, strPad(QString::number((int64_t)dPrioritySum), 20, " "));
}
}
diff --git a/src/qt/coincontroldialog.h b/src/qt/coincontroldialog.h
index 465e2a009d..4f7422642f 100644
--- a/src/qt/coincontroldialog.h
+++ b/src/qt/coincontroldialog.h
@@ -19,6 +19,7 @@ namespace Ui {
}
class WalletModel;
class CCoinControl;
+class CTxMemPool;
class CoinControlDialog : public QDialog
{
@@ -32,7 +33,7 @@ public:
// static because also called from sendcoinsdialog
static void updateLabels(WalletModel*, QDialog*);
- static QString getPriorityLabel(double);
+ static QString getPriorityLabel(const CTxMemPool& pool, double);
static QList<qint64> payAmounts;
static CCoinControl *coinControl;
diff --git a/src/qt/forms/aboutdialog.ui b/src/qt/forms/aboutdialog.ui
deleted file mode 100644
index 3ab4675bf3..0000000000
--- a/src/qt/forms/aboutdialog.ui
+++ /dev/null
@@ -1,189 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>AboutDialog</class>
- <widget class="QDialog" name="AboutDialog">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>593</width>
- <height>319</height>
- </rect>
- </property>
- <property name="windowTitle">
- <string>About Bitcoin Core</string>
- </property>
- <layout class="QHBoxLayout" name="horizontalLayout_2">
- <item>
- <widget class="QLabel" name="label_4">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Preferred" vsizetype="Ignored">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="pixmap">
- <pixmap resource="../bitcoin.qrc">:/images/about</pixmap>
- </property>
- </widget>
- </item>
- <item>
- <layout class="QVBoxLayout" name="verticalLayout_2">
- <item>
- <spacer name="verticalSpacer_2">
- <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="QLabel" name="label">
- <property name="cursor">
- <cursorShape>IBeamCursor</cursorShape>
- </property>
- <property name="text">
- <string>&lt;b&gt;Bitcoin Core&lt;/b&gt; version</string>
- </property>
- <property name="textInteractionFlags">
- <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QLabel" name="versionLabel">
- <property name="cursor">
- <cursorShape>IBeamCursor</cursorShape>
- </property>
- <property name="text">
- <string notr="true">0.3.666-beta</string>
- </property>
- <property name="textInteractionFlags">
- <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
- </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>
- </layout>
- </item>
- <item>
- <widget class="QLabel" name="copyrightLabel">
- <property name="cursor">
- <cursorShape>IBeamCursor</cursorShape>
- </property>
- <property name="text">
- <string notr="true">Copyright &amp;copy; 2009-YYYY The Bitcoin Core developers</string>
- </property>
- <property name="textFormat">
- <enum>Qt::RichText</enum>
- </property>
- <property name="textInteractionFlags">
- <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QLabel" name="label_2">
- <property name="cursor">
- <cursorShape>IBeamCursor</cursorShape>
- </property>
- <property name="text">
- <string>
-This is experimental software.
-
-Distributed under the MIT/X11 software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/) and cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP software written by Thomas Bernard.</string>
- </property>
- <property name="wordWrap">
- <bool>true</bool>
- </property>
- <property name="textInteractionFlags">
- <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
- </property>
- </widget>
- </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>
- <widget class="QDialogButtonBox" name="buttonBox">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="standardButtons">
- <set>QDialogButtonBox::Ok</set>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- </layout>
- </widget>
- <resources>
- <include location="../bitcoin.qrc"/>
- </resources>
- <connections>
- <connection>
- <sender>buttonBox</sender>
- <signal>accepted()</signal>
- <receiver>AboutDialog</receiver>
- <slot>accept()</slot>
- <hints>
- <hint type="sourcelabel">
- <x>20</x>
- <y>20</y>
- </hint>
- <hint type="destinationlabel">
- <x>20</x>
- <y>20</y>
- </hint>
- </hints>
- </connection>
- <connection>
- <sender>buttonBox</sender>
- <signal>rejected()</signal>
- <receiver>AboutDialog</receiver>
- <slot>reject()</slot>
- <hints>
- <hint type="sourcelabel">
- <x>20</x>
- <y>20</y>
- </hint>
- <hint type="destinationlabel">
- <x>20</x>
- <y>20</y>
- </hint>
- </hints>
- </connection>
- </connections>
-</ui>
diff --git a/src/qt/forms/coincontroldialog.ui b/src/qt/forms/coincontroldialog.ui
index cd1c0ffa18..67ea3a9d8c 100644
--- a/src/qt/forms/coincontroldialog.ui
+++ b/src/qt/forms/coincontroldialog.ui
@@ -225,7 +225,7 @@
</font>
</property>
<property name="text">
- <string>Low Output:</string>
+ <string>Dust:</string>
</property>
</widget>
</item>
diff --git a/src/qt/forms/helpmessagedialog.ui b/src/qt/forms/helpmessagedialog.ui
index f68fea7e64..81dbd90b12 100644
--- a/src/qt/forms/helpmessagedialog.ui
+++ b/src/qt/forms/helpmessagedialog.ui
@@ -16,7 +16,7 @@
</font>
</property>
<property name="windowTitle">
- <string>Bitcoin Core - Command-line options</string>
+ <string notr="true">Bitcoin Core - Command-line options</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
@@ -54,17 +54,15 @@
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QLabel" name="helpMessageLabel">
- <property name="font">
- <font>
- <family>Terminal</family>
- </font>
- </property>
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
+ <property name="openExternalLinks">
+ <bool>true</bool>
+ </property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
diff --git a/src/qt/forms/optionsdialog.ui b/src/qt/forms/optionsdialog.ui
index 0103842e02..1f535a4a62 100644
--- a/src/qt/forms/optionsdialog.ui
+++ b/src/qt/forms/optionsdialog.ui
@@ -243,6 +243,16 @@
</widget>
</item>
<item>
+ <widget class="QCheckBox" name="allowIncoming">
+ <property name="toolTip">
+ <string>Accept connections from outside</string>
+ </property>
+ <property name="text">
+ <string>Allow incoming connections</string>
+ </property>
+ </widget>
+ </item>
+ <item>
<widget class="QCheckBox" name="connectSocks">
<property name="toolTip">
<string>Connect to the Bitcoin network through a SOCKS proxy.</string>
@@ -319,26 +329,6 @@
</widget>
</item>
<item>
- <widget class="QLabel" name="socksVersionLabel">
- <property name="text">
- <string>SOCKS &amp;Version:</string>
- </property>
- <property name="textFormat">
- <enum>Qt::PlainText</enum>
- </property>
- <property name="buddy">
- <cstring>socksVersion</cstring>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QValueComboBox" name="socksVersion">
- <property name="toolTip">
- <string>SOCKS version of the proxy (e.g. 5)</string>
- </property>
- </widget>
- </item>
- <item>
<spacer name="horizontalSpacer_1_Network">
<property name="orientation">
<enum>Qt::Horizontal</enum>
diff --git a/src/qt/forms/overviewpage.ui b/src/qt/forms/overviewpage.ui
index e662912781..8784da5f3e 100644
--- a/src/qt/forms/overviewpage.ui
+++ b/src/qt/forms/overviewpage.ui
@@ -6,7 +6,7 @@
<rect>
<x>0</x>
<y>0</y>
- <width>573</width>
+ <width>596</width>
<height>342</height>
</rect>
</property>
@@ -46,204 +46,369 @@
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
- <widget class="QLabel" name="label_5">
- <property name="font">
- <font>
- <weight>75</weight>
- <bold>true</bold>
- </font>
- </property>
- <property name="text">
- <string>Wallet</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QLabel" name="labelWalletStatus">
- <property name="toolTip">
- <string>The displayed information may be out of date. Your wallet automatically synchronizes with the Bitcoin network after a connection is established, but this process has not completed yet.</string>
- </property>
- <property name="styleSheet">
- <string notr="true">QLabel { color: red; }</string>
- </property>
- <property name="text">
- <string notr="true">(out of sync)</string>
- </property>
- <property name="alignment">
- <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
- </property>
- </widget>
+ <layout class="QHBoxLayout" name="horizontalLayout_7">
+ <item>
+ <widget class="QLabel" name="label_5">
+ <property name="font">
+ <font>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>Wallet</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="labelWalletStatus">
+ <property name="toolTip">
+ <string>The displayed information may be out of date. Your wallet automatically synchronizes with the Bitcoin network after a connection is established, but this process has not completed yet.</string>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">QLabel { color: red; }</string>
+ </property>
+ <property name="text">
+ <string notr="true">(out of sync)</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
</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>
+ <layout class="QHBoxLayout" name="horizontalLayout_8">
+ <item>
+ <widget class="QLabel" name="labelWatchonly">
+ <property name="font">
+ <font>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>Watchonly:</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Preferred</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
</item>
</layout>
</item>
<item>
- <layout class="QHBoxLayout" name="horizontalLayout_3">
- <item>
- <layout class="QFormLayout" name="formLayout_2">
- <property name="fieldGrowthPolicy">
- <enum>QFormLayout::AllNonFixedFieldsGrow</enum>
- </property>
- <property name="horizontalSpacing">
- <number>12</number>
- </property>
- <property name="verticalSpacing">
- <number>12</number>
- </property>
- <item row="0" column="0">
- <widget class="QLabel" name="label">
- <property name="text">
- <string>Available:</string>
- </property>
- </widget>
- </item>
- <item row="0" column="1">
- <widget class="QLabel" name="labelBalance">
- <property name="font">
- <font>
- <weight>75</weight>
- <bold>true</bold>
- </font>
- </property>
- <property name="cursor">
- <cursorShape>IBeamCursor</cursorShape>
- </property>
- <property name="toolTip">
- <string>Your current spendable balance</string>
- </property>
- <property name="text">
- <string notr="true">0 BTC</string>
- </property>
- <property name="alignment">
- <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
- </property>
- <property name="textInteractionFlags">
- <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
- </property>
- </widget>
- </item>
- <item row="1" column="0">
- <widget class="QLabel" name="label_3">
- <property name="text">
- <string>Pending:</string>
- </property>
- </widget>
- </item>
- <item row="1" column="1">
- <widget class="QLabel" name="labelUnconfirmed">
- <property name="font">
- <font>
- <weight>75</weight>
- <bold>true</bold>
- </font>
- </property>
- <property name="cursor">
- <cursorShape>IBeamCursor</cursorShape>
- </property>
- <property name="toolTip">
- <string>Total of transactions that have yet to be confirmed, and do not yet count toward the spendable balance</string>
- </property>
- <property name="text">
- <string notr="true">0 BTC</string>
- </property>
- <property name="alignment">
- <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
- </property>
- <property name="textInteractionFlags">
- <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
- </property>
- </widget>
- </item>
- <item row="2" column="0">
- <widget class="QLabel" name="labelImmatureText">
- <property name="text">
- <string>Immature:</string>
- </property>
- </widget>
- </item>
- <item row="2" column="1">
- <widget class="QLabel" name="labelImmature">
- <property name="font">
- <font>
- <weight>75</weight>
- <bold>true</bold>
- </font>
- </property>
- <property name="toolTip">
- <string>Mined balance that has not yet matured</string>
- </property>
- <property name="text">
- <string notr="true">0 BTC</string>
- </property>
- <property name="alignment">
- <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
- </property>
- <property name="textInteractionFlags">
- <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
- </property>
- </widget>
- </item>
- <item row="4" column="0">
- <widget class="QLabel" name="labelTotalText">
- <property name="text">
- <string>Total:</string>
- </property>
- </widget>
- </item>
- <item row="4" column="1">
- <widget class="QLabel" name="labelTotal">
- <property name="font">
- <font>
- <weight>75</weight>
- <bold>true</bold>
- </font>
- </property>
- <property name="cursor">
- <cursorShape>IBeamCursor</cursorShape>
- </property>
- <property name="toolTip">
- <string>Your current total balance</string>
- </property>
- <property name="text">
- <string notr="true">0 BTC</string>
- </property>
- <property name="alignment">
- <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
- </property>
- <property name="textInteractionFlags">
- <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
- </property>
- </widget>
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <item>
+ <layout class="QFormLayout" name="formLayout_2">
+ <property name="fieldGrowthPolicy">
+ <enum>QFormLayout::AllNonFixedFieldsGrow</enum>
+ </property>
+ <property name="horizontalSpacing">
+ <number>12</number>
+ </property>
+ <property name="verticalSpacing">
+ <number>12</number>
+ </property>
+ <item row="0" column="0">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Available:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLabel" name="labelBalance">
+ <property name="font">
+ <font>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="cursor">
+ <cursorShape>IBeamCursor</cursorShape>
+ </property>
+ <property name="toolTip">
+ <string>Your current spendable balance</string>
+ </property>
+ <property name="text">
+ <string notr="true">0 BTC</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>Pending:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLabel" name="labelUnconfirmed">
+ <property name="font">
+ <font>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="cursor">
+ <cursorShape>IBeamCursor</cursorShape>
+ </property>
+ <property name="toolTip">
+ <string>Total of transactions that have yet to be confirmed, and do not yet count toward the spendable balance</string>
+ </property>
+ <property name="text">
+ <string notr="true">0 BTC</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="labelImmatureText">
+ <property name="text">
+ <string>Immature:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QLabel" name="labelImmature">
+ <property name="font">
+ <font>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="cursor">
+ <cursorShape>IBeamCursor</cursorShape>
+ </property>
+ <property name="toolTip">
+ <string>Mined balance that has not yet matured</string>
+ </property>
+ <property name="text">
+ <string notr="true">0 BTC</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0" colspan="2">
+ <widget class="Line" name="line">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="0">
+ <widget class="QLabel" name="labelTotalText">
+ <property name="text">
+ <string>Total:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="1">
+ <widget class="QLabel" name="labelTotal">
+ <property name="font">
+ <font>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="cursor">
+ <cursorShape>IBeamCursor</cursorShape>
+ </property>
+ <property name="toolTip">
+ <string>Your current total balance</string>
+ </property>
+ <property name="text">
+ <string notr="true">0 BTC</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
</item>
- <item row="3" column="0" colspan="2">
- <widget class="Line" name="line">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- </widget>
+ <item>
+ <layout class="QFormLayout" name="formLayout">
+ <property name="fieldGrowthPolicy">
+ <enum>QFormLayout::AllNonFixedFieldsGrow</enum>
+ </property>
+ <property name="horizontalSpacing">
+ <number>12</number>
+ </property>
+ <property name="verticalSpacing">
+ <number>12</number>
+ </property>
+ <item row="0" column="1">
+ <widget class="QLabel" name="labelWatchAvailable">
+ <property name="font">
+ <font>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="cursor">
+ <cursorShape>IBeamCursor</cursorShape>
+ </property>
+ <property name="toolTip">
+ <string>Your current balance in watchonly addresses</string>
+ </property>
+ <property name="text">
+ <string>0 BTC</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLabel" name="labelWatchPending">
+ <property name="font">
+ <font>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="cursor">
+ <cursorShape>IBeamCursor</cursorShape>
+ </property>
+ <property name="toolTip">
+ <string>Unconfirmed transactions to watchonly addresses</string>
+ </property>
+ <property name="text">
+ <string>0 BTC</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QLabel" name="labelWatchImmature">
+ <property name="font">
+ <font>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="cursor">
+ <cursorShape>IBeamCursor</cursorShape>
+ </property>
+ <property name="toolTip">
+ <string>Mined balance in watchonly addresses that has not yet matured</string>
+ </property>
+ <property name="text">
+ <string>0 BTC</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0" colspan="2">
+ <widget class="Line" name="lineWatchBalance">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>140</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="1">
+ <widget class="QLabel" name="labelWatchTotal">
+ <property name="font">
+ <font>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="cursor">
+ <cursorShape>IBeamCursor</cursorShape>
+ </property>
+ <property name="toolTip">
+ <string>Current total balance in watchonly addresses</string>
+ </property>
+ <property name="text">
+ <string>0 BTC</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
</item>
- </layout>
- </item>
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Expanding</enum>
+ </property>
<property name="sizeHint" stdset="0">
<size>
- <width>40</width>
+ <width>20</width>
<height>20</height>
</size>
</property>
diff --git a/src/qt/forms/rpcconsole.ui b/src/qt/forms/rpcconsole.ui
index fcb6bb60bb..7158b65c2d 100644
--- a/src/qt/forms/rpcconsole.ui
+++ b/src/qt/forms/rpcconsole.ui
@@ -113,13 +113,39 @@
</widget>
</item>
<item row="4" column="0">
+ <widget class="QLabel" name="label_berkeleyDBVersion">
+ <property name="text">
+ <string>Using BerkeleyDB version</string>
+ </property>
+ <property name="indent">
+ <number>10</number>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="1">
+ <widget class="QLabel" name="berkeleyDBVersion">
+ <property name="cursor">
+ <cursorShape>IBeamCursor</cursorShape>
+ </property>
+ <property name="text">
+ <string>N/A</string>
+ </property>
+ <property name="textFormat">
+ <enum>Qt::PlainText</enum>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="0">
<widget class="QLabel" name="label_12">
<property name="text">
<string>Build date</string>
</property>
</widget>
</item>
- <item row="4" column="1">
+ <item row="5" column="1">
<widget class="QLabel" name="buildDate">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -135,14 +161,14 @@
</property>
</widget>
</item>
- <item row="5" column="0">
+ <item row="6" column="0">
<widget class="QLabel" name="label_13">
<property name="text">
<string>Startup time</string>
</property>
</widget>
</item>
- <item row="5" column="1">
+ <item row="6" column="1">
<widget class="QLabel" name="startupTime">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -158,7 +184,7 @@
</property>
</widget>
</item>
- <item row="6" column="0">
+ <item row="7" column="0">
<widget class="QLabel" name="label_11">
<property name="font">
<font>
@@ -171,14 +197,14 @@
</property>
</widget>
</item>
- <item row="7" column="0">
+ <item row="8" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Name</string>
</property>
</widget>
</item>
- <item row="7" column="1">
+ <item row="8" column="1">
<widget class="QLabel" name="networkName">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -194,14 +220,14 @@
</property>
</widget>
</item>
- <item row="8" column="0">
+ <item row="9" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Number of connections</string>
</property>
</widget>
</item>
- <item row="8" column="1">
+ <item row="9" column="1">
<widget class="QLabel" name="numberOfConnections">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -217,7 +243,7 @@
</property>
</widget>
</item>
- <item row="9" column="0">
+ <item row="10" column="0">
<widget class="QLabel" name="label_10">
<property name="font">
<font>
@@ -230,14 +256,14 @@
</property>
</widget>
</item>
- <item row="10" column="0">
+ <item row="11" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Current number of blocks</string>
</property>
</widget>
</item>
- <item row="10" column="1">
+ <item row="11" column="1">
<widget class="QLabel" name="numberOfBlocks">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -253,14 +279,14 @@
</property>
</widget>
</item>
- <item row="11" column="0">
+ <item row="12" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Last block time</string>
</property>
</widget>
</item>
- <item row="11" column="1">
+ <item row="12" column="1">
<widget class="QLabel" name="lastBlockTime">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -276,7 +302,7 @@
</property>
</widget>
</item>
- <item row="12" column="0">
+ <item row="13" column="0">
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
@@ -289,7 +315,7 @@
</property>
</spacer>
</item>
- <item row="13" column="0">
+ <item row="14" column="0">
<widget class="QLabel" name="labelDebugLogfile">
<property name="font">
<font>
@@ -302,7 +328,7 @@
</property>
</widget>
</item>
- <item row="14" column="0">
+ <item row="15" column="0">
<widget class="QPushButton" name="openDebugLogfileButton">
<property name="toolTip">
<string>Open the Bitcoin debug log file from the current data directory. This can take a few seconds for large log files.</string>
@@ -315,7 +341,7 @@
</property>
</widget>
</item>
- <item row="15" column="0">
+ <item row="16" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
@@ -533,7 +559,7 @@
<item>
<widget class="QLabel" name="label_16">
<property name="text">
- <string>In:</string>
+ <string>Received</string>
</property>
</widget>
</item>
@@ -613,7 +639,7 @@
<item>
<widget class="QLabel" name="label_17">
<property name="text">
- <string>Out:</string>
+ <string>Sent</string>
</property>
</widget>
</item>
@@ -652,6 +678,281 @@
</item>
</layout>
</widget>
+ <widget class="QWidget" name="tab_peers">
+ <attribute name="title">
+ <string>&amp;Peers</string>
+ </attribute>
+ <layout class="QGridLayout" name="gridLayout_2">
+ <item row="0" column="1">
+ <widget class="QLabel" name="peerHeading">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Select a peer to view detailed information.</string>
+ </property>
+ <property name="margin">
+ <number>3</number>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0" rowspan="2">
+ <widget class="QTableView" name="peerWidget">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="horizontalScrollBarPolicy">
+ <enum>Qt::ScrollBarAlwaysOff</enum>
+ </property>
+ <property name="editTriggers">
+ <set>QAbstractItemView::AnyKeyPressed|QAbstractItemView::DoubleClicked|QAbstractItemView::EditKeyPressed</set>
+ </property>
+ <property name="sortingEnabled">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QWidget" name="detailWidget" native="true">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <layout class="QGridLayout" name="gridLayout_3">
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <item row="12" column="0">
+ <widget class="QLabel" name="label_21">
+ <property name="text">
+ <string>Version:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="11" column="1">
+ <widget class="QLabel" name="peerPingTime">
+ <property name="text">
+ <string>N/A</string>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="0">
+ <widget class="QLabel" name="label_19">
+ <property name="text">
+ <string>Last Receive:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="14" column="0">
+ <widget class="QLabel" name="label_28">
+ <property name="text">
+ <string>User Agent:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="12" column="1">
+ <widget class="QLabel" name="peerVersion">
+ <property name="text">
+ <string>N/A</string>
+ </property>
+ </widget>
+ </item>
+ <item row="8" column="1">
+ <widget class="QLabel" name="peerConnTime">
+ <property name="minimumSize">
+ <size>
+ <width>160</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>N/A</string>
+ </property>
+ </widget>
+ </item>
+ <item row="11" column="0">
+ <widget class="QLabel" name="label_26">
+ <property name="text">
+ <string>Ping Time:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="1">
+ <widget class="QLabel" name="peerLastRecv">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>N/A</string>
+ </property>
+ </widget>
+ </item>
+ <item row="8" column="0">
+ <widget class="QLabel" name="label_22">
+ <property name="text">
+ <string>Connection Time:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="6" column="1">
+ <widget class="QLabel" name="peerBytesSent">
+ <property name="text">
+ <string>N/A</string>
+ </property>
+ </widget>
+ </item>
+ <item row="14" column="1">
+ <widget class="QLabel" name="peerSubversion">
+ <property name="text">
+ <string>N/A</string>
+ </property>
+ </widget>
+ </item>
+ <item row="15" column="0">
+ <widget class="QLabel" name="label_29">
+ <property name="text">
+ <string>Starting Height:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="7" column="1">
+ <widget class="QLabel" name="peerBytesRecv">
+ <property name="text">
+ <string>N/A</string>
+ </property>
+ </widget>
+ </item>
+ <item row="6" column="0">
+ <widget class="QLabel" name="label_18">
+ <property name="text">
+ <string>Bytes Sent:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="7" column="0">
+ <widget class="QLabel" name="label_20">
+ <property name="text">
+ <string>Bytes Received:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="15" column="1">
+ <widget class="QLabel" name="peerHeight">
+ <property name="text">
+ <string>N/A</string>
+ </property>
+ </widget>
+ </item>
+ <item row="16" column="0">
+ <widget class="QLabel" name="label_24">
+ <property name="text">
+ <string>Ban Score:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="16" column="1">
+ <widget class="QLabel" name="peerBanScore">
+ <property name="text">
+ <string>N/A</string>
+ </property>
+ </widget>
+ </item>
+ <item row="17" column="0">
+ <widget class="QLabel" name="label_23">
+ <property name="text">
+ <string>Direction:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="17" column="1">
+ <widget class="QLabel" name="peerDirection">
+ <property name="text">
+ <string>N/A</string>
+ </property>
+ </widget>
+ </item>
+ <item row="19" column="0">
+ <widget class="QLabel" name="label_25">
+ <property name="text">
+ <string>Sync Node:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="19" column="1">
+ <widget class="QLabel" name="peerSyncNode">
+ <property name="text">
+ <string>N/A</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0">
+ <widget class="QLabel" name="label_15">
+ <property name="text">
+ <string>Last Send:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="label_4">
+ <property name="text">
+ <string>Services:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_27">
+ <property name="text">
+ <string>IP Address/port:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1">
+ <widget class="QLabel" name="peerLastSend">
+ <property name="text">
+ <string>N/A</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QLabel" name="peerServices">
+ <property name="text">
+ <string>N/A</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLabel" name="peerAddr">
+ <property name="text">
+ <string>N/A</string>
+ </property>
+ </widget>
+ </item>
+ <item row="20" column="0">
+ <widget class="QWidget" name="widget" native="true">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
</widget>
</item>
</layout>
diff --git a/src/qt/forms/sendcoinsdialog.ui b/src/qt/forms/sendcoinsdialog.ui
index 4cb1670c79..a631b04670 100644
--- a/src/qt/forms/sendcoinsdialog.ui
+++ b/src/qt/forms/sendcoinsdialog.ui
@@ -417,7 +417,7 @@
</font>
</property>
<property name="text">
- <string>Low Output:</string>
+ <string>Dust:</string>
</property>
</widget>
</item>
diff --git a/src/qt/forms/sendcoinsentry.ui b/src/qt/forms/sendcoinsentry.ui
index e77de0d9b8..9d829970f0 100644
--- a/src/qt/forms/sendcoinsentry.ui
+++ b/src/qt/forms/sendcoinsentry.ui
@@ -51,7 +51,7 @@
<item>
<widget class="QValidatedLineEdit" name="payTo">
<property name="toolTip">
- <string>The address to send the payment to (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</string>
+ <string>The Bitcoin address to send the payment to</string>
</property>
</widget>
</item>
diff --git a/src/qt/forms/signverifymessagedialog.ui b/src/qt/forms/signverifymessagedialog.ui
index aa271b4f2a..53573ec821 100644
--- a/src/qt/forms/signverifymessagedialog.ui
+++ b/src/qt/forms/signverifymessagedialog.ui
@@ -45,7 +45,7 @@
<item>
<widget class="QValidatedLineEdit" name="addressIn_SM">
<property name="toolTip">
- <string>The address to sign the message with (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</string>
+ <string>The Bitcoin address to sign the message with</string>
</property>
</widget>
</item>
@@ -255,7 +255,7 @@
<item>
<widget class="QValidatedLineEdit" name="addressIn_VM">
<property name="toolTip">
- <string>The address the message was signed with (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</string>
+ <string>The Bitcoin address the message was signed with</string>
</property>
</widget>
</item>
diff --git a/src/qt/guiconstants.h b/src/qt/guiconstants.h
index 5ae4bc833d..696761e234 100644
--- a/src/qt/guiconstants.h
+++ b/src/qt/guiconstants.h
@@ -23,6 +23,10 @@ static const int STATUSBAR_ICONSIZE = 16;
#define COLOR_NEGATIVE QColor(255, 0, 0)
/* Transaction list -- bare address (without label) */
#define COLOR_BAREADDRESS QColor(140, 140, 140)
+/* Transaction list -- has conflicting transactions */
+#define COLOR_HASCONFLICTING QColor(255, 255, 255)
+/* Transaction list -- has conflicting transactions - background */
+#define COLOR_HASCONFLICTING_BG QColor(192, 0, 0)
/* Tooltips longer than this (in characters) are converted into rich text,
so that they can be word-wrapped.
diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp
index 7b264d27c7..60a131df7e 100644
--- a/src/qt/guiutil.cpp
+++ b/src/qt/guiutil.cpp
@@ -11,6 +11,8 @@
#include "core.h"
#include "init.h"
+#include "main.h"
+#include "protocol.h"
#include "util.h"
#ifdef WIN32
@@ -76,7 +78,11 @@ QString dateTimeStr(qint64 nTime)
QFont bitcoinAddressFont()
{
QFont font("Monospace");
+#if QT_VERSION >= 0x040800
+ font.setStyleHint(QFont::Monospace);
+#else
font.setStyleHint(QFont::TypeWriter);
+#endif
return font;
}
@@ -86,7 +92,9 @@ void setupAddressWidget(QValidatedLineEdit *widget, QWidget *parent)
widget->setFont(bitcoinAddressFont());
#if QT_VERSION >= 0x040700
- widget->setPlaceholderText(QObject::tr("Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)"));
+ // We don't want translators to use own addresses in translations
+ // and this is the only place, where this address is supplied.
+ widget->setPlaceholderText(QObject::tr("Enter a Bitcoin address (e.g. %1)").arg("1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L"));
#endif
widget->setValidator(new BitcoinAddressEntryValidator(parent));
widget->setCheckValidator(new BitcoinAddressCheckValidator(parent));
@@ -205,7 +213,7 @@ bool isDust(const QString& address, qint64 amount)
CTxDestination dest = CBitcoinAddress(address.toStdString()).Get();
CScript script; script.SetDestination(dest);
CTxOut txOut(amount, script);
- return txOut.IsDust(CTransaction::nMinRelayTxFee);
+ return txOut.IsDust(::minRelayTxFee);
}
QString HtmlEscape(const QString& str, bool fMultiLine)
@@ -570,7 +578,7 @@ bool SetStartOnSystemStartup(bool fAutoStart)
return true;
}
-#elif defined(LINUX)
+#elif defined(Q_OS_LINUX)
// Follow the Desktop Application Autostart Spec:
// http://standards.freedesktop.org/autostart-spec/autostart-spec-latest.html
@@ -750,4 +758,50 @@ QString boostPathToQString(const boost::filesystem::path &path)
}
#endif
+QString formatDurationStr(int secs)
+{
+ QStringList strList;
+ int days = secs / 86400;
+ int hours = (secs % 86400) / 3600;
+ int mins = (secs % 3600) / 60;
+ int seconds = secs % 60;
+
+ if (days)
+ strList.append(QString(QObject::tr("%1 d")).arg(days));
+ if (hours)
+ strList.append(QString(QObject::tr("%1 h")).arg(hours));
+ if (mins)
+ strList.append(QString(QObject::tr("%1 m")).arg(mins));
+ if (seconds || (!days && !hours && !mins))
+ strList.append(QString(QObject::tr("%1 s")).arg(seconds));
+
+ return strList.join(" ");
+}
+
+QString formatServicesStr(uint64_t mask)
+{
+ QStringList strList;
+
+ // Just scan the last 8 bits for now.
+ for (int i = 0; i < 8; i++) {
+ uint64_t check = 1 << i;
+ if (mask & check)
+ {
+ switch (check)
+ {
+ case NODE_NETWORK:
+ strList.append(QObject::tr("NETWORK"));
+ break;
+ default:
+ strList.append(QString("%1[%2]").arg(QObject::tr("UNKNOWN")).arg(check));
+ }
+ }
+ }
+
+ if (strList.size())
+ return strList.join(" & ");
+ else
+ return QObject::tr("None");
+}
+
} // namespace GUIUtil
diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h
index 4f9416d1af..45c78b4e14 100644
--- a/src/qt/guiutil.h
+++ b/src/qt/guiutil.h
@@ -173,6 +173,11 @@ namespace GUIUtil
/* Convert OS specific boost path to QString through UTF-8 */
QString boostPathToQString(const boost::filesystem::path &path);
+ /* Convert seconds into a QString with days, hours, mins, secs */
+ QString formatDurationStr(int secs);
+
+ /* Format CNodeStats.nServices bitmask into a user-readable string */
+ QString formatServicesStr(uint64_t mask);
} // namespace GUIUtil
#endif // GUIUTIL_H
diff --git a/src/qt/locale/bitcoin_da.ts b/src/qt/locale/bitcoin_da.ts
index 5795701497..a0514035fd 100644
--- a/src/qt/locale/bitcoin_da.ts
+++ b/src/qt/locale/bitcoin_da.ts
@@ -3,11 +3,11 @@
<name>AboutDialog</name>
<message>
<source>About Bitcoin Core</source>
- <translation type="unfinished"/>
+ <translation>Om Bitcoin Core</translation>
</message>
<message>
<source>&lt;b&gt;Bitcoin Core&lt;/b&gt; version</source>
- <translation type="unfinished"/>
+ <translation>&lt;b&gt;Bitcoin Core&lt;/b&gt; version</translation>
</message>
<message>
<source>
@@ -25,15 +25,15 @@ Produktet indeholder software som er udviklet af OpenSSL Project til brug i Open
</message>
<message>
<source>Copyright</source>
- <translation>Copyright</translation>
+ <translation>Ophavsret</translation>
</message>
<message>
<source>The Bitcoin Core developers</source>
- <translation type="unfinished"/>
+ <translation>Udviklerne af Bitcoin Core</translation>
</message>
<message>
<source>(%1-bit)</source>
- <translation type="unfinished"/>
+ <translation>(%1-bit)</translation>
</message>
</context>
<context>
@@ -48,7 +48,7 @@ Produktet indeholder software som er udviklet af OpenSSL Project til brug i Open
</message>
<message>
<source>&amp;New</source>
- <translation>&amp;Ny</translation>
+ <translation>Ny</translation>
</message>
<message>
<source>Copy the currently selected address to the system clipboard</source>
@@ -56,11 +56,11 @@ Produktet indeholder software som er udviklet af OpenSSL Project til brug i Open
</message>
<message>
<source>&amp;Copy</source>
- <translation>&amp;Kopiér</translation>
+ <translation>Kopiér</translation>
</message>
<message>
<source>C&amp;lose</source>
- <translation type="unfinished"/>
+ <translation>Luk</translation>
</message>
<message>
<source>&amp;Copy Address</source>
@@ -76,7 +76,7 @@ Produktet indeholder software som er udviklet af OpenSSL Project til brug i Open
</message>
<message>
<source>&amp;Export</source>
- <translation>Eksporter</translation>
+ <translation>Eksportér</translation>
</message>
<message>
<source>&amp;Delete</source>
@@ -84,15 +84,15 @@ Produktet indeholder software som er udviklet af OpenSSL Project til brug i Open
</message>
<message>
<source>Choose the address to send coins to</source>
- <translation type="unfinished"/>
+ <translation>Vælg adresse at sende bitcoins til</translation>
</message>
<message>
<source>Choose the address to receive coins with</source>
- <translation type="unfinished"/>
+ <translation>Vælg adresse at modtage bitcoins med</translation>
</message>
<message>
<source>C&amp;hoose</source>
- <translation type="unfinished"/>
+ <translation>Vælg</translation>
</message>
<message>
<source>Sending addresses</source>
@@ -108,7 +108,7 @@ Produktet indeholder software som er udviklet af OpenSSL Project til brug i Open
</message>
<message>
<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>Dette er dine Bitcoin-adresser til at modtage betalinger med. Det anbefales are bruge en ny modtagelsesadresse for hver transaktion.</translation>
</message>
<message>
<source>Copy &amp;Label</source>
@@ -120,7 +120,7 @@ Produktet indeholder software som er udviklet af OpenSSL Project til brug i Open
</message>
<message>
<source>Export Address List</source>
- <translation type="unfinished"/>
+ <translation>Eksportér adresseliste</translation>
</message>
<message>
<source>Comma separated file (*.csv)</source>
@@ -128,11 +128,11 @@ Produktet indeholder software som er udviklet af OpenSSL Project til brug i Open
</message>
<message>
<source>Exporting Failed</source>
- <translation type="unfinished"/>
+ <translation>Eksport mislykkedes</translation>
</message>
<message>
<source>There was an error trying to save the address list to %1.</source>
- <translation type="unfinished"/>
+ <translation>En fejl opstod under gemning af adresseliste til %1.</translation>
</message>
</context>
<context>
@@ -214,7 +214,7 @@ Produktet indeholder software som er udviklet af OpenSSL Project til brug i Open
</message>
<message>
<source>IMPORTANT: Any previous backups you have made of your wallet file should be replaced with the newly generated, encrypted wallet file. For security reasons, previous backups of the unencrypted wallet file will become useless as soon as you start using the new, encrypted wallet.</source>
- <translation>VIGTIGT: Enhver tidligere sikkerhedskopi, som du har lavet af tegnebogsfilen, bør blive erstattet af den nyligt genererede, krypterede tegnebogsfil. Af sikkerhedsmæssige årsager vil tidligere sikkerhedskopier af den ikke-krypterede tegnebogsfil blive ubrugelig i det øjeblik, du starter med at anvende den nye, krypterede tegnebog.</translation>
+ <translation>VIGTIGT: Enhver tidligere sikkerhedskopi, som du har lavet af tegnebogsfilen, bør blive erstattet af den nyligt genererede, krypterede tegnebogsfil. Af sikkerhedsmæssige årsager vil tidligere sikkerhedskopier af den ikke-krypterede tegnebogsfil blive ubrugelige i det øjeblik, du starter med at anvende den nye, krypterede tegnebog.</translation>
</message>
<message>
<source>Warning: The Caps Lock key is on!</source>
@@ -273,7 +273,7 @@ Produktet indeholder software som er udviklet af OpenSSL Project til brug i Open
</message>
<message>
<source>Node</source>
- <translation type="unfinished"/>
+ <translation>Knude</translation>
</message>
<message>
<source>Show general overview of wallet</source>
@@ -325,23 +325,23 @@ Produktet indeholder software som er udviklet af OpenSSL Project til brug i Open
</message>
<message>
<source>&amp;Sending addresses...</source>
- <translation>&amp;Afsendelsesadresser...</translation>
+ <translation>Afsendelsesadresser …</translation>
</message>
<message>
<source>&amp;Receiving addresses...</source>
- <translation>&amp;Modtagelsesadresser...</translation>
+ <translation>Modtagelsesadresser …</translation>
</message>
<message>
<source>Open &amp;URI...</source>
- <translation type="unfinished"/>
+ <translation>Åbn URI …</translation>
</message>
<message>
<source>Importing blocks from disk...</source>
- <translation>Importerer blokke fra disken...</translation>
+ <translation>Importerer blokke fra disken …</translation>
</message>
<message>
<source>Reindexing blocks on disk...</source>
- <translation>Genindekserer blokke på disken...</translation>
+ <translation>Genindekserer blokke på disken …</translation>
</message>
<message>
<source>Send coins to a Bitcoin address</source>
@@ -397,7 +397,7 @@ Produktet indeholder software som er udviklet af OpenSSL Project til brug i Open
</message>
<message>
<source>Encrypt the private keys that belong to your wallet</source>
- <translation>Krypter de private nøgler, der hører til din tegnebog</translation>
+ <translation>Kryptér de private nøgler, der hører til din tegnebog</translation>
</message>
<message>
<source>Sign messages with your Bitcoin addresses to prove you own them</source>
@@ -405,7 +405,7 @@ Produktet indeholder software som er udviklet af OpenSSL Project til brug i Open
</message>
<message>
<source>Verify messages to ensure they were signed with specified Bitcoin addresses</source>
- <translation>Verificér beskeder for at sikre, at de er underskrevet med de(n) angivne Bitcoin-adresse(r)</translation>
+ <translation>Verificér beskeder for at sikre, at de er underskrevet med de angivne Bitcoin-adresser</translation>
</message>
<message>
<source>&amp;File</source>
@@ -433,31 +433,31 @@ Produktet indeholder software som er udviklet af OpenSSL Project til brug i Open
</message>
<message>
<source>Request payments (generates QR codes and bitcoin: URIs)</source>
- <translation type="unfinished"/>
+ <translation>Forespørg betalinger (genererer QR-koder og &quot;bitcoin:&quot;-URI&apos;er)</translation>
</message>
<message>
<source>&amp;About Bitcoin Core</source>
- <translation type="unfinished"/>
+ <translation>Om Bitcoin Core</translation>
</message>
<message>
<source>Show the list of used sending addresses and labels</source>
- <translation type="unfinished"/>
+ <translation>Vis listen over brugte afsendelsesadresser og -mærkater</translation>
</message>
<message>
<source>Show the list of used receiving addresses and labels</source>
- <translation type="unfinished"/>
+ <translation>Vis listen over brugte modtagelsesadresser og -mærkater</translation>
</message>
<message>
<source>Open a bitcoin: URI or payment request</source>
- <translation type="unfinished"/>
+ <translation>Åbn en &quot;bitcoin:&quot;-URI eller betalingsforespørgsel</translation>
</message>
<message>
<source>&amp;Command-line options</source>
- <translation type="unfinished"/>
+ <translation>Tilvalg for kommandolinje</translation>
</message>
<message>
<source>Show the Bitcoin Core help message to get a list with possible Bitcoin command-line options</source>
- <translation type="unfinished"/>
+ <translation>Vis Bitcoin Core hjælpebesked for at få en liste over mulige tilvalg for Bitcoin kommandolinje</translation>
</message>
<message>
<source>Bitcoin client</source>
@@ -469,7 +469,7 @@ Produktet indeholder software som er udviklet af OpenSSL Project til brug i Open
</message>
<message>
<source>No block source available...</source>
- <translation>Ingen blokkilde tilgængelig...</translation>
+ <translation>Ingen blokkilde tilgængelig …</translation>
</message>
<message>
<source>Processed %1 of %2 (estimated) blocks of transaction history.</source>
@@ -493,11 +493,11 @@ Produktet indeholder software som er udviklet af OpenSSL Project til brug i Open
</message>
<message>
<source>%1 and %2</source>
- <translation type="unfinished"/>
+ <translation>%1 og %2</translation>
</message>
<message numerus="yes">
<source>%n year(s)</source>
- <translation type="unfinished"><numerusform></numerusform><numerusform></numerusform></translation>
+ <translation><numerusform>%n år</numerusform><numerusform>%n år</numerusform></translation>
</message>
<message>
<source>%1 behind</source>
@@ -575,15 +575,15 @@ Adresse: %4
<name>CoinControlDialog</name>
<message>
<source>Coin Control Address Selection</source>
- <translation type="unfinished"/>
+ <translation>Adressevalg for coin-styring</translation>
</message>
<message>
<source>Quantity:</source>
- <translation type="unfinished"/>
+ <translation>Mængde:</translation>
</message>
<message>
<source>Bytes:</source>
- <translation type="unfinished"/>
+ <translation>Byte:</translation>
</message>
<message>
<source>Amount:</source>
@@ -591,35 +591,35 @@ Adresse: %4
</message>
<message>
<source>Priority:</source>
- <translation type="unfinished"/>
+ <translation>Prioritet:</translation>
</message>
<message>
<source>Fee:</source>
- <translation type="unfinished"/>
+ <translation>Gebyr:</translation>
</message>
<message>
<source>Low Output:</source>
- <translation type="unfinished"/>
+ <translation>Lavt output:</translation>
</message>
<message>
<source>After Fee:</source>
- <translation type="unfinished"/>
+ <translation>Efter gebyr:</translation>
</message>
<message>
<source>Change:</source>
- <translation type="unfinished"/>
+ <translation>Byttepenge:</translation>
</message>
<message>
<source>(un)select all</source>
- <translation type="unfinished"/>
+ <translation>(af)vælg alle</translation>
</message>
<message>
<source>Tree mode</source>
- <translation type="unfinished"/>
+ <translation>Trætilstand</translation>
</message>
<message>
<source>List mode</source>
- <translation type="unfinished"/>
+ <translation>Listetilstand</translation>
</message>
<message>
<source>Amount</source>
@@ -635,7 +635,7 @@ Adresse: %4
</message>
<message>
<source>Confirmations</source>
- <translation type="unfinished"/>
+ <translation>Bekræftelser</translation>
</message>
<message>
<source>Confirmed</source>
@@ -643,151 +643,151 @@ Adresse: %4
</message>
<message>
<source>Priority</source>
- <translation type="unfinished"/>
+ <translation>Prioritet</translation>
</message>
<message>
<source>Copy address</source>
- <translation>Kopier adresse</translation>
+ <translation>Kopiér adresse</translation>
</message>
<message>
<source>Copy label</source>
- <translation>Kopier mærkat</translation>
+ <translation>Kopiér mærkat</translation>
</message>
<message>
<source>Copy amount</source>
- <translation>Kopier beløb</translation>
+ <translation>Kopiér beløb</translation>
</message>
<message>
<source>Copy transaction ID</source>
- <translation>Kopier transaktionens ID</translation>
+ <translation>Kopiér transaktions-ID</translation>
</message>
<message>
<source>Lock unspent</source>
- <translation type="unfinished"/>
+ <translation>Fastlås ubrugte</translation>
</message>
<message>
<source>Unlock unspent</source>
- <translation type="unfinished"/>
+ <translation>Lås ubrugte op</translation>
</message>
<message>
<source>Copy quantity</source>
- <translation type="unfinished"/>
+ <translation>Kopiér mængde</translation>
</message>
<message>
<source>Copy fee</source>
- <translation type="unfinished"/>
+ <translation>Kopiér gebyr</translation>
</message>
<message>
<source>Copy after fee</source>
- <translation type="unfinished"/>
+ <translation>Kopiér efter-gebyr</translation>
</message>
<message>
<source>Copy bytes</source>
- <translation type="unfinished"/>
+ <translation>Kopiér byte</translation>
</message>
<message>
<source>Copy priority</source>
- <translation type="unfinished"/>
+ <translation>Kopiér prioritet</translation>
</message>
<message>
<source>Copy low output</source>
- <translation type="unfinished"/>
+ <translation>Kopiér lavt output</translation>
</message>
<message>
<source>Copy change</source>
- <translation type="unfinished"/>
+ <translation>Kopiér byttepenge</translation>
</message>
<message>
<source>highest</source>
- <translation type="unfinished"/>
+ <translation>højest</translation>
</message>
<message>
<source>higher</source>
- <translation type="unfinished"/>
+ <translation>højere</translation>
</message>
<message>
<source>high</source>
- <translation type="unfinished"/>
+ <translation>højt</translation>
</message>
<message>
<source>medium-high</source>
- <translation type="unfinished"/>
+ <translation>mellemhøj</translation>
</message>
<message>
<source>medium</source>
- <translation type="unfinished"/>
+ <translation>medium</translation>
</message>
<message>
<source>low-medium</source>
- <translation type="unfinished"/>
+ <translation>mellemlav</translation>
</message>
<message>
<source>low</source>
- <translation type="unfinished"/>
+ <translation>lav</translation>
</message>
<message>
<source>lower</source>
- <translation type="unfinished"/>
+ <translation>lavere</translation>
</message>
<message>
<source>lowest</source>
- <translation type="unfinished"/>
+ <translation>lavest</translation>
</message>
<message>
<source>(%1 locked)</source>
- <translation type="unfinished"/>
+ <translation>(%1 fastlåst)</translation>
</message>
<message>
<source>none</source>
- <translation type="unfinished"/>
+ <translation>ingen</translation>
</message>
<message>
<source>Dust</source>
- <translation type="unfinished"/>
+ <translation>Støv</translation>
</message>
<message>
<source>yes</source>
- <translation type="unfinished"/>
+ <translation>ja</translation>
</message>
<message>
<source>no</source>
- <translation type="unfinished"/>
+ <translation>nej</translation>
</message>
<message>
<source>This label turns red, if the transaction size is greater than 1000 bytes.</source>
- <translation type="unfinished"/>
+ <translation>Dette mærkat bliver rødt, hvis transaktionsstørrelsen er større end 1000 byte.</translation>
</message>
<message>
<source>This means a fee of at least %1 per kB is required.</source>
- <translation type="unfinished"/>
+ <translation>Dette betyder, at et gebyr på mindst %1 pr. kB er nødvendigt.</translation>
</message>
<message>
<source>Can vary +/- 1 byte per input.</source>
- <translation type="unfinished"/>
+ <translation>Kan variere ±1 byte pr. input.</translation>
</message>
<message>
<source>Transactions with higher priority are more likely to get included into a block.</source>
- <translation type="unfinished"/>
+ <translation>Transaktioner med højere prioritet har højere sansynlighed for at blive inkluderet i en blok.</translation>
</message>
<message>
<source>This label turns red, if the priority is smaller than &quot;medium&quot;.</source>
- <translation type="unfinished"/>
+ <translation>Dette mærkat bliver rødt, hvis prioriteten er mindre end &quot;medium&quot;.</translation>
</message>
<message>
<source>This label turns red, if any recipient receives an amount smaller than %1.</source>
- <translation type="unfinished"/>
+ <translation>Dette mærkat bliver rødt, hvis mindst én modtager et beløb mindre end %1.</translation>
</message>
<message>
<source>This means a fee of at least %1 is required.</source>
- <translation type="unfinished"/>
+ <translation>Dette betyder, at et gebyr på mindst %1 er nødvendigt.</translation>
</message>
<message>
<source>Amounts below 0.546 times the minimum relay fee are shown as dust.</source>
- <translation type="unfinished"/>
+ <translation>Beløb under 0,546 gange det minimale videreførselsgebyr vises som støv.</translation>
</message>
<message>
<source>This label turns red, if the change is smaller than %1.</source>
- <translation type="unfinished"/>
+ <translation>Dette mærkat bliver rødt, hvis byttepengene er mindre end %1.</translation>
</message>
<message>
<source>(no label)</source>
@@ -795,11 +795,11 @@ Adresse: %4
</message>
<message>
<source>change from %1 (%2)</source>
- <translation type="unfinished"/>
+ <translation>byttepenge fra %1 (%2)</translation>
</message>
<message>
<source>(change)</source>
- <translation type="unfinished"/>
+ <translation>(byttepange)</translation>
</message>
</context>
<context>
@@ -814,11 +814,11 @@ Adresse: %4
</message>
<message>
<source>The label associated with this address list entry</source>
- <translation type="unfinished"/>
+ <translation>Mærkatet, der er associeret med denne indgang i adresselisten</translation>
</message>
<message>
<source>The address associated with this address list entry. This can only be modified for sending addresses.</source>
- <translation type="unfinished"/>
+ <translation>Adressen, der er associeret med denne indgang i adresselisten. Denne kan kune ændres for afsendelsesadresser.</translation>
</message>
<message>
<source>&amp;Address</source>
@@ -861,7 +861,7 @@ Adresse: %4
<name>FreespaceChecker</name>
<message>
<source>A new data directory will be created.</source>
- <translation type="unfinished"/>
+ <translation>En ny datamappe vil blive oprettet.</translation>
</message>
<message>
<source>name</source>
@@ -869,22 +869,22 @@ Adresse: %4
</message>
<message>
<source>Directory already exists. Add %1 if you intend to create a new directory here.</source>
- <translation type="unfinished"/>
+ <translation>Mappe eksisterer allerede. Tilføj %1, hvis du vil oprette en ny mappe her.</translation>
</message>
<message>
<source>Path already exists, and is not a directory.</source>
- <translation type="unfinished"/>
+ <translation>Sti eksisterer allerede og er ikke en mappe.</translation>
</message>
<message>
<source>Cannot create data directory here.</source>
- <translation type="unfinished"/>
+ <translation>Kan ikke oprette en mappe her.</translation>
</message>
</context>
<context>
<name>HelpMessageDialog</name>
<message>
<source>Bitcoin Core - Command-line options</source>
- <translation type="unfinished"/>
+ <translation>Bitcoin Core – tilvalg for kommandolinje</translation>
</message>
<message>
<source>Bitcoin Core</source>
@@ -908,7 +908,7 @@ Adresse: %4
</message>
<message>
<source>Set language, for example &quot;de_DE&quot; (default: system locale)</source>
- <translation>Angiv sprog, f.eks &quot;de_DE&quot; (standard: systemlokalitet)</translation>
+ <translation>Angiv sprog, fx &quot;da_DK&quot; (standard: systemlokalitet)</translation>
</message>
<message>
<source>Start minimized</source>
@@ -916,15 +916,15 @@ Adresse: %4
</message>
<message>
<source>Set SSL root certificates for payment request (default: -system-)</source>
- <translation type="unfinished"/>
+ <translation>Sæt SSL-rodcertifikater for betalingsforespørgsel (standard: -system-)</translation>
</message>
<message>
<source>Show splash screen on startup (default: 1)</source>
- <translation>Vis opstartsbillede ved start (standard: 1)</translation>
+ <translation>Vis opstartsbillede ved opstart (standard: 1)</translation>
</message>
<message>
<source>Choose data directory on startup (default: 0)</source>
- <translation type="unfinished"/>
+ <translation>Vælg datamappe ved opstart (standard: 0)</translation>
</message>
</context>
<context>
@@ -935,23 +935,23 @@ Adresse: %4
</message>
<message>
<source>Welcome to Bitcoin Core.</source>
- <translation type="unfinished"/>
+ <translation>Velkommen til Bitcoin Core.</translation>
</message>
<message>
<source>As this is the first time the program is launched, you can choose where Bitcoin Core will store its data.</source>
- <translation type="unfinished"/>
+ <translation>Siden dette er første gang, programmet startes, kan du vælge, hvor Bitcoin Core skal gemme sin data.</translation>
</message>
<message>
<source>Bitcoin Core will download and store a copy of the Bitcoin block chain. At least %1GB of data will be stored in this directory, and it will grow over time. The wallet will also be stored in this directory.</source>
- <translation type="unfinished"/>
+ <translation>Bitcoin Core vil downloade og gemme et kopi af Bitcoin-blokkæden. Mindst %1 GB data vil blive gemt i denne mappe, og den vil vokse over tid. Tegnebogen vil også blive gemt i denne mappe.</translation>
</message>
<message>
<source>Use the default data directory</source>
- <translation type="unfinished"/>
+ <translation>Brug standardmappen for data</translation>
</message>
<message>
<source>Use a custom data directory:</source>
- <translation type="unfinished"/>
+ <translation>Brug tilpasset mappe for data:</translation>
</message>
<message>
<source>Bitcoin</source>
@@ -959,7 +959,7 @@ Adresse: %4
</message>
<message>
<source>Error: Specified data directory &quot;%1&quot; can not be created.</source>
- <translation type="unfinished"/>
+ <translation>Fejl: Angivet datamappe &quot;%1&quot; kan ikke oprettes.</translation>
</message>
<message>
<source>Error</source>
@@ -967,34 +967,34 @@ Adresse: %4
</message>
<message>
<source>GB of free space available</source>
- <translation type="unfinished"/>
+ <translation>GB fri plads tilgængelig</translation>
</message>
<message>
<source>(of %1GB needed)</source>
- <translation type="unfinished"/>
+ <translation>(ud af %1 GB behøvet)</translation>
</message>
</context>
<context>
<name>OpenURIDialog</name>
<message>
<source>Open URI</source>
- <translation type="unfinished"/>
+ <translation>Åbn URI</translation>
</message>
<message>
<source>Open payment request from URI or file</source>
- <translation type="unfinished"/>
+ <translation>Åbn betalingsforespørgsel fra URI eller fil</translation>
</message>
<message>
<source>URI:</source>
- <translation type="unfinished"/>
+ <translation>URI:</translation>
</message>
<message>
<source>Select payment request file</source>
- <translation type="unfinished"/>
+ <translation>Vælg fil for betalingsforespørgsel</translation>
</message>
<message>
<source>Select payment request file to open</source>
- <translation type="unfinished"/>
+ <translation>Vælg fil for betalingsforespørgsel til åbning</translation>
</message>
</context>
<context>
@@ -1025,39 +1025,39 @@ Adresse: %4
</message>
<message>
<source>Size of &amp;database cache</source>
- <translation type="unfinished"/>
+ <translation>Størrelsen på databasens cache</translation>
</message>
<message>
<source>MB</source>
- <translation type="unfinished"/>
+ <translation>MB</translation>
</message>
<message>
<source>Number of script &amp;verification threads</source>
- <translation type="unfinished"/>
+ <translation>Antallet af scriptverificeringstråde</translation>
</message>
<message>
<source>Connect to the Bitcoin network through a SOCKS proxy.</source>
- <translation type="unfinished"/>
+ <translation>Forbind til Bitcoin-netværket gennem en SOCKS-proxy.</translation>
</message>
<message>
<source>&amp;Connect through SOCKS proxy (default proxy):</source>
- <translation type="unfinished"/>
+ <translation>Forbind gennem SOCKS-proxy (standard-proxy):</translation>
</message>
<message>
<source>IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1)</source>
- <translation type="unfinished"/>
+ <translation>IP-adresse for proxyen (fx IPv4: 127.0.0.1 / IPv6: ::1)</translation>
</message>
<message>
<source>Third party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items. %s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |.</source>
- <translation type="unfinished"/>
+ <translation>Tredjeparts-URL&apos;er (fx et blokhåndteringsværktøj), der vises i transaktionsfanen som genvejsmenupunkter. %s i URL&apos;en erstattes med transaktionens hash. Flere URL&apos;er separeres med en lodret streg |.</translation>
</message>
<message>
<source>Third party transaction URLs</source>
- <translation type="unfinished"/>
+ <translation>Tredjeparts-transaktions-URL&apos;er</translation>
</message>
<message>
<source>Active command-line options that override above options:</source>
- <translation type="unfinished"/>
+ <translation>Aktuelle tilvalg for kommandolinjen, der tilsidesætter ovenstående tilvalg:</translation>
</message>
<message>
<source>Reset all client options to default.</source>
@@ -1073,27 +1073,27 @@ Adresse: %4
</message>
<message>
<source>(0 = auto, &lt;0 = leave that many cores free)</source>
- <translation type="unfinished"/>
+ <translation>(0 = auto, &lt;0 = efterlad så mange kerner fri)</translation>
</message>
<message>
<source>W&amp;allet</source>
- <translation type="unfinished"/>
+ <translation>Tegnebog</translation>
</message>
<message>
<source>Expert</source>
- <translation type="unfinished"/>
+ <translation>Ekspert</translation>
</message>
<message>
<source>Enable coin &amp;control features</source>
- <translation type="unfinished"/>
+ <translation>Slå egenskaber for coin-styring til</translation>
</message>
<message>
<source>If you disable the spending of unconfirmed change, the change from a transaction cannot be used until that transaction has at least one confirmation. This also affects how your balance is computed.</source>
- <translation type="unfinished"/>
+ <translation>Hvis du slår brug af ubekræftede byttepenge fra, kan byttepengene fra en transaktion ikke bruges, før pågældende transaktion har mindst én bekræftelse. Dette påvirker også måden hvorpå din saldo beregnes.</translation>
</message>
<message>
<source>&amp;Spend unconfirmed change</source>
- <translation type="unfinished"/>
+ <translation>Brug ubekræftede byttepenge</translation>
</message>
<message>
<source>Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled.</source>
@@ -1133,15 +1133,15 @@ Adresse: %4
</message>
<message>
<source>&amp;Minimize to the tray instead of the taskbar</source>
- <translation>Minimer til statusfeltet i stedet for proceslinjen</translation>
+ <translation>Minimér til statusfeltet i stedet for proceslinjen</translation>
</message>
<message>
<source>Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu.</source>
- <translation>Minimer i stedet for at afslutte programmet, når vinduet lukkes. Når denne indstilling er valgt, vil programmet kun blive lukket, når du har valgt Afslut i menuen.</translation>
+ <translation>Minimér i stedet for at afslutte programmet, når vinduet lukkes. Når denne indstilling er valgt, vil programmet kun blive lukket, når du har valgt Afslut i menuen.</translation>
</message>
<message>
<source>M&amp;inimize on close</source>
- <translation>Minimer ved lukning</translation>
+ <translation>Minimér ved lukning</translation>
</message>
<message>
<source>&amp;Display</source>
@@ -1149,11 +1149,11 @@ Adresse: %4
</message>
<message>
<source>User Interface &amp;language:</source>
- <translation>Brugergrænsefladesprog:</translation>
+ <translation>Sprog for brugergrænseflade:</translation>
</message>
<message>
<source>The user interface language can be set here. This setting will take effect after restarting Bitcoin.</source>
- <translation>Brugergrænsefladesproget kan angives her. Denne indstilling træder først i kraft, når Bitcoin genstartes.</translation>
+ <translation>Sproget for brugergrænsefladen kan angives her. Denne indstilling træder først i kraft, når Bitcoin genstartes.</translation>
</message>
<message>
<source>&amp;Unit to show amounts in:</source>
@@ -1161,7 +1161,7 @@ Adresse: %4
</message>
<message>
<source>Choose the default subdivision unit to show in the interface and when sending coins.</source>
- <translation>Vælg den standard underopdelingsenhed, som skal vises i brugergrænsefladen og ved afsendelse af bitcoins.</translation>
+ <translation>Vælg standard for underopdeling af enhed, som skal vises i brugergrænsefladen og ved afsendelse af bitcoins.</translation>
</message>
<message>
<source>Whether to show Bitcoin addresses in the transaction list or not.</source>
@@ -1173,7 +1173,7 @@ Adresse: %4
</message>
<message>
<source>Whether to show coin control features or not.</source>
- <translation type="unfinished"/>
+ <translation>Hvorvidt egenskaber for coin-styring skal vises eller ej.</translation>
</message>
<message>
<source>&amp;OK</source>
@@ -1181,7 +1181,7 @@ Adresse: %4
</message>
<message>
<source>&amp;Cancel</source>
- <translation>Annuller</translation>
+ <translation>Annullér</translation>
</message>
<message>
<source>default</source>
@@ -1189,7 +1189,7 @@ Adresse: %4
</message>
<message>
<source>none</source>
- <translation type="unfinished"/>
+ <translation>ingeningen</translation>
</message>
<message>
<source>Confirm options reset</source>
@@ -1197,19 +1197,19 @@ Adresse: %4
</message>
<message>
<source>Client restart required to activate changes.</source>
- <translation type="unfinished"/>
+ <translation>Genstart af klienten er nødvendig for at aktivere ændringer.</translation>
</message>
<message>
<source>Client will be shutdown, do you want to proceed?</source>
- <translation type="unfinished"/>
+ <translation>Klienten vil blive lukket ned; vil du fortsætte?</translation>
</message>
<message>
<source>This change would require a client restart.</source>
- <translation type="unfinished"/>
+ <translation>Denne ændring vil kræve en genstart af klienten.</translation>
</message>
<message>
<source>The supplied proxy address is invalid.</source>
- <translation>Ugyldig proxy-adresse</translation>
+ <translation>Den angivne proxy-adresse er ugyldig.</translation>
</message>
</context>
<context>
@@ -1228,7 +1228,7 @@ Adresse: %4
</message>
<message>
<source>Available:</source>
- <translation type="unfinished"/>
+ <translation>Tilgængelig:</translation>
</message>
<message>
<source>Your current spendable balance</source>
@@ -1236,11 +1236,11 @@ Adresse: %4
</message>
<message>
<source>Pending:</source>
- <translation type="unfinished"/>
+ <translation>Uafgjort:</translation>
</message>
<message>
<source>Total of transactions that have yet to be confirmed, and do not yet count toward the spendable balance</source>
- <translation>Total transaktioner, som ikke er blevet bekræftet endnu, og som ikke endnu er en del af den nuværende saldo</translation>
+ <translation>Total saldo for transaktioner, som ikke er blevet bekræftet endnu, og som ikke endnu er en del af den tilgængelige saldo</translation>
</message>
<message>
<source>Immature:</source>
@@ -1279,11 +1279,11 @@ Adresse: %4
</message>
<message>
<source>Requested payment amount of %1 is too small (considered dust).</source>
- <translation type="unfinished"/>
+ <translation>Forespurgt betalingsbeløb på %1 er for lille (regnes som støv).</translation>
</message>
<message>
<source>Payment request error</source>
- <translation>Fejl i betalingsforespørgelse</translation>
+ <translation>Fejl i betalingsforespørgsel</translation>
</message>
<message>
<source>Cannot start bitcoin: click-to-pay handler</source>
@@ -1291,27 +1291,27 @@ Adresse: %4
</message>
<message>
<source>Net manager warning</source>
- <translation type="unfinished"/>
+ <translation>Net-håndterings-advarsel</translation>
</message>
<message>
<source>Your active proxy doesn&apos;t support SOCKS5, which is required for payment requests via proxy.</source>
- <translation type="unfinished"/>
+ <translation>Din aktuelle proxy understøtter ikke SOCKS5, hvilket kræves for betalingsforespørgsler via proxy.</translation>
</message>
<message>
<source>Payment request fetch URL is invalid: %1</source>
- <translation type="unfinished"/>
+ <translation>Betalingsforespørgslens hentnings-URL er ugyldig: %1</translation>
</message>
<message>
<source>Payment request file handling</source>
- <translation type="unfinished"/>
+ <translation>Filhåndtering for betalingsanmodninger</translation>
</message>
<message>
<source>Payment request file can not be read or processed! This can be caused by an invalid payment request file.</source>
- <translation type="unfinished"/>
+ <translation>Betalingsanmodningsfil kan ikke indlæses eller bearbejdes! Dette kan skyldes en ugyldig betalingsanmodningsfil.</translation>
</message>
<message>
<source>Unverified payment requests to custom payment scripts are unsupported.</source>
- <translation type="unfinished"/>
+ <translation>Ikke-verificerede betalingsforespørgsler for tilpassede betalings-scripts understøttes ikke.</translation>
</message>
<message>
<source>Refund from %1</source>
@@ -1319,23 +1319,23 @@ Adresse: %4
</message>
<message>
<source>Error communicating with %1: %2</source>
- <translation type="unfinished"/>
+ <translation>Fejl under kommunikation med %1: %2</translation>
</message>
<message>
<source>Payment request can not be parsed or processed!</source>
- <translation type="unfinished"/>
+ <translation>Betalingsanmodning kan ikke fortolkes eller bearbejdes!</translation>
</message>
<message>
<source>Bad response from server %1</source>
- <translation type="unfinished"/>
+ <translation>Fejlagtigt svar fra server %1</translation>
</message>
<message>
<source>Payment acknowledged</source>
- <translation type="unfinished"/>
+ <translation>Betaling anerkendt</translation>
</message>
<message>
<source>Network request error</source>
- <translation type="unfinished"/>
+ <translation>Fejl i netværksforespørgsel</translation>
</message>
</context>
<context>
@@ -1346,34 +1346,34 @@ Adresse: %4
</message>
<message>
<source>Error: Specified data directory &quot;%1&quot; does not exist.</source>
- <translation type="unfinished"/>
+ <translation>Fejl: Angivet datamappe &quot;%1&quot; eksisterer ikke.</translation>
</message>
<message>
<source>Error: Cannot parse configuration file: %1. Only use key=value syntax.</source>
- <translation type="unfinished"/>
+ <translation>Fejl: Kan ikke fortolke konfigurationsfil: %1. Brug kun syntaksen nøgle=værdi.</translation>
</message>
<message>
<source>Error: Invalid combination of -regtest and -testnet.</source>
- <translation type="unfinished"/>
+ <translation>Fejl: Ugyldig kombination af -regtest og -testnet.</translation>
</message>
<message>
<source>Bitcoin Core didn&apos;t yet exit safely...</source>
- <translation type="unfinished"/>
+ <translation>Bitcoin Core blev ikke afsluttet på sikker vis …</translation>
</message>
<message>
<source>Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</source>
- <translation>Indtast en Bitcoin-adresse (f.eks. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</translation>
+ <translation>Indtast en Bitcoin-adresse (fx 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</translation>
</message>
</context>
<context>
<name>QRImageWidget</name>
<message>
<source>&amp;Save Image...</source>
- <translation>&amp;Gem foto...</translation>
+ <translation>Gem billede …</translation>
</message>
<message>
<source>&amp;Copy Image</source>
- <translation>&amp;Kopiér foto</translation>
+ <translation>Kopiér foto</translation>
</message>
<message>
<source>Save QR Code</source>
@@ -1381,7 +1381,7 @@ Adresse: %4
</message>
<message>
<source>PNG Image (*.png)</source>
- <translation type="unfinished"/>
+ <translation>PNG-billede (*.png)</translation>
</message>
</context>
<context>
@@ -1404,11 +1404,11 @@ Adresse: %4
</message>
<message>
<source>Debug window</source>
- <translation type="unfinished"/>
+ <translation>Fejlsøgningsvindue</translation>
</message>
<message>
<source>General</source>
- <translation type="unfinished"/>
+ <translation>Generelt</translation>
</message>
<message>
<source>Using OpenSSL version</source>
@@ -1456,23 +1456,23 @@ Adresse: %4
</message>
<message>
<source>&amp;Network Traffic</source>
- <translation type="unfinished"/>
+ <translation>Netværkstrafik</translation>
</message>
<message>
<source>&amp;Clear</source>
- <translation type="unfinished"/>
+ <translation>Ryd</translation>
</message>
<message>
<source>Totals</source>
- <translation type="unfinished"/>
+ <translation>Totaler</translation>
</message>
<message>
<source>In:</source>
- <translation type="unfinished"/>
+ <translation>Indkommende:</translation>
</message>
<message>
<source>Out:</source>
- <translation>Ud:</translation>
+ <translation>Udgående:</translation>
</message>
<message>
<source>Build date</source>
@@ -1484,7 +1484,7 @@ Adresse: %4
</message>
<message>
<source>Open the Bitcoin debug log file from the current data directory. This can take a few seconds for large log files.</source>
- <translation>Åbn Bitcoin-fejlsøgningslogfilen fra det nuværende datakatalog. Dette kan tage nogle få sekunder for en store logfiler.</translation>
+ <translation>Åbn Bitcoin-fejlsøgningslogfilen fra den nuværende datamappe. Dette kan tage nogle få sekunder for store logfiler.</translation>
</message>
<message>
<source>Clear console</source>
@@ -1535,7 +1535,7 @@ Adresse: %4
<name>ReceiveCoinsDialog</name>
<message>
<source>&amp;Amount:</source>
- <translation>&amp;Mængde:</translation>
+ <translation>Beløb:</translation>
</message>
<message>
<source>&amp;Label:</source>
@@ -1543,35 +1543,35 @@ Adresse: %4
</message>
<message>
<source>&amp;Message:</source>
- <translation>&amp;Besked:</translation>
+ <translation>Besked:</translation>
</message>
<message>
<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>Genbrug en af de tidligere brugte modtagelsesadresser. Genbrug af adresser har indflydelse på sikkerhed og privatliv. Brug ikke dette med mindre du genskaber en betalingsforespørgsel fra tidligere.</translation>
</message>
<message>
<source>R&amp;euse an existing receiving address (not recommended)</source>
- <translation type="unfinished"/>
+ <translation>Genbrug en eksisterende modtagelsesadresse (anbefales ikke)</translation>
</message>
<message>
<source>An optional message to attach to the payment request, which will be displayed when the request is opened. Note: The message will not be sent with the payment over the Bitcoin network.</source>
- <translation type="unfinished"/>
+ <translation>En valgfri besked, der føjes til betalingsanmodningen, og som vil vises, når anmodningen åbnes. Bemærk: Beskeden vil ikke sendes med betalingen over Bitcoin-netværket.</translation>
</message>
<message>
<source>An optional label to associate with the new receiving address.</source>
- <translation type="unfinished"/>
+ <translation>Et valgfrit mærkat, der associeres med den nye modtagelsesadresse.</translation>
</message>
<message>
<source>Use this form to request payments. All fields are &lt;b&gt;optional&lt;/b&gt;.</source>
- <translation type="unfinished"/>
+ <translation>Brug denne formular for at anmode om betalinger. Alle felter er &lt;b&gt;valgfri&lt;/b&gt;.</translation>
</message>
<message>
<source>An optional amount to request. Leave this empty or zero to not request a specific amount.</source>
- <translation type="unfinished"/>
+ <translation>Et valgfrit beløb til anmodning. Lad dette felt være tomt eller indeholde nul for at anmode om et ikke-specifikt beløb.</translation>
</message>
<message>
<source>Clear all fields of the form.</source>
- <translation>Ryd alle fælter af formen.</translation>
+ <translation>Ryd alle felter af formen.</translation>
</message>
<message>
<source>Clear</source>
@@ -1579,35 +1579,35 @@ Adresse: %4
</message>
<message>
<source>Requested payments history</source>
- <translation type="unfinished"/>
+ <translation>Historik over betalingsanmodninger</translation>
</message>
<message>
<source>&amp;Request payment</source>
- <translation>&amp;Anmod betaling</translation>
+ <translation>Anmod om betaling</translation>
</message>
<message>
<source>Show the selected request (does the same as double clicking an entry)</source>
- <translation type="unfinished"/>
+ <translation>Vis den valgte forespørgsel (gør det samme som dobbeltklik på en indgang)</translation>
</message>
<message>
<source>Show</source>
- <translation type="unfinished"/>
+ <translation>Vis</translation>
</message>
<message>
<source>Remove the selected entries from the list</source>
- <translation type="unfinished"/>
+ <translation>Fjern de valgte indgange fra listen</translation>
</message>
<message>
<source>Remove</source>
- <translation type="unfinished"/>
+ <translation>Fjern</translation>
</message>
<message>
<source>Copy label</source>
- <translation>Kopier mærkat</translation>
+ <translation>Kopiér mærkat</translation>
</message>
<message>
<source>Copy message</source>
- <translation type="unfinished"/>
+ <translation>Kopiér besked</translation>
</message>
<message>
<source>Copy amount</source>
@@ -1618,23 +1618,23 @@ Adresse: %4
<name>ReceiveRequestDialog</name>
<message>
<source>QR Code</source>
- <translation>QR Kode</translation>
+ <translation>QR-kode</translation>
</message>
<message>
<source>Copy &amp;URI</source>
- <translation>Kopiér &amp;URL</translation>
+ <translation>Kopiér URI</translation>
</message>
<message>
<source>Copy &amp;Address</source>
- <translation>Kopiér &amp;Adresse</translation>
+ <translation>Kopiér adresse</translation>
</message>
<message>
<source>&amp;Save Image...</source>
- <translation>&amp;Gem foto...</translation>
+ <translation>Gem billede …</translation>
</message>
<message>
<source>Request payment to %1</source>
- <translation type="unfinished"/>
+ <translation>Anmod om betaling til %1</translation>
</message>
<message>
<source>Payment information</source>
@@ -1666,7 +1666,7 @@ Adresse: %4
</message>
<message>
<source>Error encoding URI into QR Code.</source>
- <translation>Fejl ved kodning fra URI til QR-kode</translation>
+ <translation>Fejl ved kodning fra URI til QR-kode.</translation>
</message>
</context>
<context>
@@ -1693,11 +1693,11 @@ Adresse: %4
</message>
<message>
<source>(no message)</source>
- <translation type="unfinished"/>
+ <translation>(ingen besked)</translation>
</message>
<message>
<source>(no amount)</source>
- <translation type="unfinished"/>
+ <translation>(intet beløb)</translation>
</message>
</context>
<context>
@@ -1708,27 +1708,27 @@ Adresse: %4
</message>
<message>
<source>Coin Control Features</source>
- <translation type="unfinished"/>
+ <translation>Egenskaber for coin-styring</translation>
</message>
<message>
<source>Inputs...</source>
- <translation type="unfinished"/>
+ <translation>Inputs …</translation>
</message>
<message>
<source>automatically selected</source>
- <translation type="unfinished"/>
+ <translation>valgt automatisk</translation>
</message>
<message>
<source>Insufficient funds!</source>
- <translation type="unfinished"/>
+ <translation>Utilstrækkelige midler!</translation>
</message>
<message>
<source>Quantity:</source>
- <translation type="unfinished"/>
+ <translation>Mængde:</translation>
</message>
<message>
<source>Bytes:</source>
- <translation type="unfinished"/>
+ <translation>Byte:</translation>
</message>
<message>
<source>Amount:</source>
@@ -1736,31 +1736,31 @@ Adresse: %4
</message>
<message>
<source>Priority:</source>
- <translation type="unfinished"/>
+ <translation>Prioritet:</translation>
</message>
<message>
<source>Fee:</source>
- <translation type="unfinished"/>
+ <translation>Gebyr:</translation>
</message>
<message>
<source>Low Output:</source>
- <translation type="unfinished"/>
+ <translation>Lavt output:</translation>
</message>
<message>
<source>After Fee:</source>
- <translation type="unfinished"/>
+ <translation>Efter gebyr:</translation>
</message>
<message>
<source>Change:</source>
- <translation type="unfinished"/>
+ <translation>Byttepenge:</translation>
</message>
<message>
<source>If this is activated, but the change address is empty or invalid, change will be sent to a newly generated address.</source>
- <translation type="unfinished"/>
+ <translation>Hvis dette aktiveres, men byttepengeadressen er tom eller ugyldig, vil byttepenge blive sendt til en nygenereret adresse.</translation>
</message>
<message>
<source>Custom change address</source>
- <translation type="unfinished"/>
+ <translation>Tilpasset byttepengeadresse</translation>
</message>
<message>
<source>Send to multiple recipients at once</source>
@@ -1772,7 +1772,7 @@ Adresse: %4
</message>
<message>
<source>Clear all fields of the form.</source>
- <translation>Ryd alle fælter af formen.</translation>
+ <translation>Ryd alle felter af formen.</translation>
</message>
<message>
<source>Clear &amp;All</source>
@@ -1796,11 +1796,11 @@ Adresse: %4
</message>
<message>
<source>%1 to %2</source>
- <translation type="unfinished"/>
+ <translation>%1 til %2</translation>
</message>
<message>
<source>Copy quantity</source>
- <translation type="unfinished"/>
+ <translation>Kopiér mængde</translation>
</message>
<message>
<source>Copy amount</source>
@@ -1808,35 +1808,35 @@ Adresse: %4
</message>
<message>
<source>Copy fee</source>
- <translation type="unfinished"/>
+ <translation>Kopiér gebyr</translation>
</message>
<message>
<source>Copy after fee</source>
- <translation type="unfinished"/>
+ <translation>Kopiér efter-gebyr</translation>
</message>
<message>
<source>Copy bytes</source>
- <translation type="unfinished"/>
+ <translation>Kopiér byte</translation>
</message>
<message>
<source>Copy priority</source>
- <translation type="unfinished"/>
+ <translation>Kopiér prioritet</translation>
</message>
<message>
<source>Copy low output</source>
- <translation type="unfinished"/>
+ <translation>Kopiér lavt output</translation>
</message>
<message>
<source>Copy change</source>
- <translation type="unfinished"/>
+ <translation>Kopiér byttepenge</translation>
</message>
<message>
<source>Total Amount %1 (= %2)</source>
- <translation type="unfinished"/>
+ <translation>Totalbeløb %1 (= %2)</translation>
</message>
<message>
<source>or</source>
- <translation type="unfinished"/>
+ <translation>eller</translation>
</message>
<message>
<source>The recipient address is not valid, please recheck.</source>
@@ -1860,15 +1860,15 @@ Adresse: %4
</message>
<message>
<source>Transaction creation failed!</source>
- <translation type="unfinished"/>
+ <translation>Oprettelse af transaktion mislykkedes!</translation>
</message>
<message>
<source>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.</source>
- <translation type="unfinished"/>
+ <translation>Transaktionen blev afvist! Dette kan ske, hvis nogle af dine bitcoins i din tegnebog allerede er brugt, som hvis du brugte en kopi af wallet.dat og dine bitcoins er blevet brugt i kopien, men ikke er markeret som brugt her.</translation>
</message>
<message>
<source>Warning: Invalid Bitcoin address</source>
- <translation type="unfinished"/>
+ <translation>Advarsel: Ugyldig Bitcoin-adresse</translation>
</message>
<message>
<source>(no label)</source>
@@ -1876,11 +1876,11 @@ Adresse: %4
</message>
<message>
<source>Warning: Unknown change address</source>
- <translation type="unfinished"/>
+ <translation>Advarsel: Ukendt byttepengeadresse</translation>
</message>
<message>
<source>Are you sure you want to send?</source>
- <translation>Er du sikker på at du vil sende?</translation>
+ <translation>Er du sikker på, at du vil sende?</translation>
</message>
<message>
<source>added as transaction fee</source>
@@ -1888,11 +1888,11 @@ Adresse: %4
</message>
<message>
<source>Payment request expired</source>
- <translation>Betalingsforespørgsel udløb</translation>
+ <translation>Betalingsforespørgsel udløbet</translation>
</message>
<message>
<source>Invalid payment address %1</source>
- <translation type="unfinished"/>
+ <translation>Ugyldig betalingsadresse %1</translation>
</message>
</context>
<context>
@@ -1907,7 +1907,7 @@ Adresse: %4
</message>
<message>
<source>The address to send the payment to (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</source>
- <translation>Bitcoin-adressen som betalingen skal sendes til (f.eks. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</translation>
+ <translation>Bitcoin-adressen som betalingen skal sendes til (fx 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</translation>
</message>
<message>
<source>Enter a label for this address to add it to your address book</source>
@@ -1919,11 +1919,11 @@ Adresse: %4
</message>
<message>
<source>Choose previously used address</source>
- <translation type="unfinished"/>
+ <translation>Vælg tidligere brugt adresse</translation>
</message>
<message>
<source>This is a normal payment.</source>
- <translation type="unfinished"/>
+ <translation>Dette er en normal betaling.</translation>
</message>
<message>
<source>Alt+A</source>
@@ -1939,7 +1939,7 @@ Adresse: %4
</message>
<message>
<source>Remove this entry</source>
- <translation type="unfinished"/>
+ <translation>Fjern denne indgang</translation>
</message>
<message>
<source>Message:</source>
@@ -1947,38 +1947,38 @@ Adresse: %4
</message>
<message>
<source>This is a verified payment request.</source>
- <translation type="unfinished"/>
+ <translation>Dette er en verificeret betalingsforespørgsel.</translation>
</message>
<message>
<source>Enter a label for this address to add it to the list of used addresses</source>
- <translation type="unfinished"/>
+ <translation>Indtast et mærkat for denne adresse for at føje den til listen over brugte adresser</translation>
</message>
<message>
<source>A message that was attached to the bitcoin: URI which will be stored with the transaction for your reference. Note: This message will not be sent over the Bitcoin network.</source>
- <translation type="unfinished"/>
+ <translation>En besked, som blev føjet til &quot;bitcon:&quot;-URI&apos;en, som vil gemmes med transaktionen til din reference. Bemærk: Denne besked vil ikke blive sendt over Bitcoin-netværket.</translation>
</message>
<message>
<source>This is an unverified payment request.</source>
- <translation type="unfinished"/>
+ <translation>Dette er en ikke-verificeret betalingsforespørgsel.</translation>
</message>
<message>
<source>Pay To:</source>
- <translation type="unfinished"/>
+ <translation>Betal til:</translation>
</message>
<message>
<source>Memo:</source>
- <translation type="unfinished"/>
+ <translation>Memo:</translation>
</message>
</context>
<context>
<name>ShutdownWindow</name>
<message>
<source>Bitcoin Core is shutting down...</source>
- <translation type="unfinished"/>
+ <translation>Bitcoin Core lukker ned …</translation>
</message>
<message>
<source>Do not shut down the computer until this window disappears.</source>
- <translation type="unfinished"/>
+ <translation>Luk ikke computeren ned, før dette vindue forsvinder.</translation>
</message>
</context>
<context>
@@ -1997,11 +1997,11 @@ Adresse: %4
</message>
<message>
<source>The address to sign the message with (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</source>
- <translation>Bitcoin-adressen som beskeden skal underskrives med (f.eks. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</translation>
+ <translation>Bitcoin-adressen som beskeden skal underskrives med (fx 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</translation>
</message>
<message>
<source>Choose previously used address</source>
- <translation type="unfinished"/>
+ <translation>Vælg tidligere brugt adresse</translation>
</message>
<message>
<source>Alt+A</source>
@@ -2017,7 +2017,7 @@ Adresse: %4
</message>
<message>
<source>Enter the message you want to sign here</source>
- <translation>Indtast beskeden, du ønsker at underskrive</translation>
+ <translation>Indtast her beskeden, du ønsker at underskrive</translation>
</message>
<message>
<source>Signature</source>
@@ -2025,7 +2025,7 @@ Adresse: %4
</message>
<message>
<source>Copy the current signature to the system clipboard</source>
- <translation>Kopier den nuværende underskrift til systemets udklipsholder</translation>
+ <translation>Kopiér den nuværende underskrift til systemets udklipsholder</translation>
</message>
<message>
<source>Sign the message to prove you own this Bitcoin address</source>
@@ -2049,11 +2049,11 @@ Adresse: %4
</message>
<message>
<source>Enter the signing address, message (ensure you copy line breaks, spaces, tabs, etc. exactly) and signature below to verify the message. Be careful not to read more into the signature than what is in the signed message itself, to avoid being tricked by a man-in-the-middle attack.</source>
- <translation>Indtast den underskrevne adresse, beskeden (inkluder linjeskift, mellemrum mv. nøjagtigt, som de fremgår) og underskriften for at verificére beskeden. Vær forsigtig med ikke at lægge mere i underskriften end besked selv, så du undgår at blive narret af et man-in-the-middle-angreb.</translation>
+ <translation>Indtast herunder den underskrivende adresse, beskeden (inkludér linjeskift, mellemrum mv. nøjagtigt, som de fremgår) og underskriften for at verificere beskeden. Vær forsigtig med ikke at lægge mere i underskriften end besked selv, så du undgår at blive narret af et man-in-the-middle-angreb.</translation>
</message>
<message>
<source>The address the message was signed with (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</source>
- <translation>Bitcoin-adressen som beskeden er underskrevet med (f.eks. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</translation>
+ <translation>Bitcoin-adressen som beskeden er underskrevet med (fx 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</translation>
</message>
<message>
<source>Verify the message to ensure it was signed with the specified Bitcoin address</source>
@@ -2069,7 +2069,7 @@ Adresse: %4
</message>
<message>
<source>Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</source>
- <translation>Indtast en Bitcoin-adresse (f.eks. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</translation>
+ <translation>Indtast en Bitcoin-adresse (fx 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</translation>
</message>
<message>
<source>Click &quot;Sign Message&quot; to generate signature</source>
@@ -2081,7 +2081,7 @@ Adresse: %4
</message>
<message>
<source>Please check the address and try again.</source>
- <translation>Tjek venligst adressen, og forsøg igen.</translation>
+ <translation>Tjek venligst adressen og forsøg igen.</translation>
</message>
<message>
<source>The entered address does not refer to a key.</source>
@@ -2117,11 +2117,11 @@ Adresse: %4
</message>
<message>
<source>Message verification failed.</source>
- <translation>Verificéring af besked mislykkedes.</translation>
+ <translation>Verificering af besked mislykkedes.</translation>
</message>
<message>
<source>Message verified.</source>
- <translation>Besked verificéret.</translation>
+ <translation>Besked verificeret.</translation>
</message>
</context>
<context>
@@ -2132,11 +2132,11 @@ Adresse: %4
</message>
<message>
<source>The Bitcoin Core developers</source>
- <translation type="unfinished"/>
+ <translation>Udviklerne af Bitcoin Core</translation>
</message>
<message>
<source>[testnet]</source>
- <translation>[testnet]</translation>
+ <translation>[testnetværk]</translation>
</message>
</context>
<context>
@@ -2154,7 +2154,7 @@ Adresse: %4
</message>
<message>
<source>conflicted</source>
- <translation type="unfinished"/>
+ <translation>konflikt</translation>
</message>
<message>
<source>%1/offline</source>
@@ -2174,7 +2174,7 @@ Adresse: %4
</message>
<message numerus="yes">
<source>, broadcast through %n node(s)</source>
- <translation><numerusform>, transmitteret igennem %n knude(r)</numerusform><numerusform>, transmitteret igennem %n knude(r)</numerusform></translation>
+ <translation><numerusform>, transmitteret igennem %n knude</numerusform><numerusform>, transmitteret igennem %n knuder</numerusform></translation>
</message>
<message>
<source>Date</source>
@@ -2210,7 +2210,7 @@ Adresse: %4
</message>
<message numerus="yes">
<source>matures in %n more block(s)</source>
- <translation><numerusform>modner efter yderligere %n blok(ke)</numerusform><numerusform>modner efter yderligere %n blok(ke)</numerusform></translation>
+ <translation><numerusform>modner efter yderligere %n blok</numerusform><numerusform>modner efter yderligere %n blokke</numerusform></translation>
</message>
<message>
<source>not accepted</source>
@@ -2238,15 +2238,15 @@ Adresse: %4
</message>
<message>
<source>Transaction ID</source>
- <translation>Transaktionens ID</translation>
+ <translation>Transaktions-ID</translation>
</message>
<message>
<source>Merchant</source>
- <translation type="unfinished"/>
+ <translation>Forretningsdrivende</translation>
</message>
<message>
<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 &quot;not accepted&quot; and it won&apos;t be spendable. This may occasionally happen if another node generates a block within a few seconds of yours.</source>
- <translation type="unfinished"/>
+ <translation>Udvundne bitcoins skal modne %1 blokke, før de kan bruges. Da du genererede denne blok, blev den udsendt til netværket for at blive føjet til blokkæden. Hvis det ikke lykkes at få den i kæden, vil dens tilstand ændres til &quot;ikke accepteret&quot;, og den vil ikke kunne bruges. Dette kan ske nu og da, hvis en anden knude udvinder en blok inden for nogle få sekunder fra din.</translation>
</message>
<message>
<source>Debug information</source>
@@ -2316,7 +2316,7 @@ Adresse: %4
</message>
<message>
<source>Immature (%1 confirmations, will be available after %2)</source>
- <translation type="unfinished"/>
+ <translation>Umoden (%1 bekræftelser; vil være tilgængelig efter %2)</translation>
</message>
<message numerus="yes">
<source>Open for %n more block(s)</source>
@@ -2340,19 +2340,19 @@ Adresse: %4
</message>
<message>
<source>Offline</source>
- <translation type="unfinished"/>
+ <translation>Offline</translation>
</message>
<message>
<source>Unconfirmed</source>
- <translation type="unfinished"/>
+ <translation>Ubekræftet</translation>
</message>
<message>
<source>Confirming (%1 of %2 recommended confirmations)</source>
- <translation type="unfinished"/>
+ <translation>Bekræfter (%1 af %2 anbefalede bekræftelser)</translation>
</message>
<message>
<source>Conflicted</source>
- <translation type="unfinished"/>
+ <translation>Konflikt</translation>
</message>
<message>
<source>Received with</source>
@@ -2471,7 +2471,7 @@ Adresse: %4
</message>
<message>
<source>Copy transaction ID</source>
- <translation>Kopier transaktionens ID</translation>
+ <translation>Kopiér transaktions-ID</translation>
</message>
<message>
<source>Edit label</source>
@@ -2483,23 +2483,23 @@ Adresse: %4
</message>
<message>
<source>Export Transaction History</source>
- <translation type="unfinished"/>
+ <translation>Historik for eksport af transaktioner</translation>
</message>
<message>
<source>Exporting Failed</source>
- <translation type="unfinished"/>
+ <translation>Eksport mislykkedes</translation>
</message>
<message>
<source>There was an error trying to save the transaction history to %1.</source>
- <translation type="unfinished"/>
+ <translation>En fejl opstod under gemning af transaktionshistorik til %1.</translation>
</message>
<message>
<source>Exporting Successful</source>
- <translation type="unfinished"/>
+ <translation>Eksport problemfri</translation>
</message>
<message>
<source>The transaction history was successfully saved to %1.</source>
- <translation type="unfinished"/>
+ <translation>Transaktionshistorikken blev gemt til %1 med succes.</translation>
</message>
<message>
<source>Comma separated file (*.csv)</source>
@@ -2546,7 +2546,7 @@ Adresse: %4
<name>WalletFrame</name>
<message>
<source>No wallet has been loaded.</source>
- <translation type="unfinished"/>
+ <translation>Ingen tegnebog er indlæst.</translation>
</message>
</context>
<context>
@@ -2560,7 +2560,7 @@ Adresse: %4
<name>WalletView</name>
<message>
<source>&amp;Export</source>
- <translation>Eksporter</translation>
+ <translation>Eksportér</translation>
</message>
<message>
<source>Export the data in the current tab to a file</source>
@@ -2568,7 +2568,7 @@ Adresse: %4
</message>
<message>
<source>Backup Wallet</source>
- <translation>Sikkerhedskopier tegnebog</translation>
+ <translation>Sikkerhedskopiér tegnebog</translation>
</message>
<message>
<source>Wallet Data (*.dat)</source>
@@ -2576,19 +2576,19 @@ Adresse: %4
</message>
<message>
<source>Backup Failed</source>
- <translation>Foretagelse af sikkerhedskopi fejlede</translation>
+ <translation>Sikkerhedskopiering mislykkedes</translation>
</message>
<message>
<source>There was an error trying to save the wallet data to %1.</source>
- <translation type="unfinished"/>
+ <translation>Der skete en fejl under gemning af tegnebogsdata til %1.</translation>
</message>
<message>
<source>The wallet data was successfully saved to %1.</source>
- <translation type="unfinished"/>
+ <translation>Tegnebogsdata blev gemt til %1 med succes.</translation>
</message>
<message>
<source>Backup Successful</source>
- <translation>Sikkerhedskopieret problemfri</translation>
+ <translation>Sikkerhedskopiering problemfri</translation>
</message>
</context>
<context>
@@ -2619,7 +2619,7 @@ Adresse: %4
</message>
<message>
<source>Specify data directory</source>
- <translation>Angiv datakatalog</translation>
+ <translation>Angiv datamappe</translation>
</message>
<message>
<source>Listen for connections on &lt;port&gt; (default: 8333 or testnet: 18333)</source>
@@ -2659,7 +2659,7 @@ Adresse: %4
</message>
<message>
<source>Bitcoin Core RPC client version</source>
- <translation type="unfinished"/>
+ <translation>Bitcoin Core RPC-klient-version</translation>
</message>
<message>
<source>Run in the background as a daemon and accept commands</source>
@@ -2671,7 +2671,7 @@ Adresse: %4
</message>
<message>
<source>Accept connections from outside (default: 1 if no -proxy or -connect)</source>
- <translation>Accepter forbindelser udefra (standard: 1 hvis hverken -proxy eller -connect)</translation>
+ <translation>Acceptér forbindelser udefra (standard: 1 hvis hverken -proxy eller -connect)</translation>
</message>
<message>
<source>%s, you must set a rpcpassword in the configuration file:
@@ -2694,12 +2694,12 @@ rpcpassword=%s
Brugernavnet og adgangskode MÅ IKKE være det samme.
Hvis filen ikke eksisterer, opret den og giv ingen andre end ejeren læserettighed.
Det anbefales også at angive alertnotify, så du påmindes om problemer;
-f.eks.: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.com
+fx: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.com
</translation>
</message>
<message>
<source>Acceptable ciphers (default: TLSv1.2+HIGH:TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!3DES:@STRENGTH)</source>
- <translation type="unfinished"/>
+ <translation>Accepterede krypteringer (standard: TLSv1.2+HIGH:TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!3DES:@STRENGTH)</translation>
</message>
<message>
<source>An error occurred while setting up the RPC port %u for listening on IPv6, falling back to IPv4: %s</source>
@@ -2711,19 +2711,19 @@ f.eks.: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.com
</message>
<message>
<source>Continuously rate-limit free transactions to &lt;n&gt;*1000 bytes per minute (default:15)</source>
- <translation type="unfinished"/>
+ <translation>Rate-begræns kontinuerligt frie transaktioner til &lt;n&gt;*1000 byte i minuttet (standard:15)</translation>
</message>
<message>
<source>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.</source>
- <translation type="unfinished"/>
+ <translation>Start regressionstesttilstand, som bruger en speciel kæde, hvor blokke kan løses med det samme. Dette er tiltænkt til testværktøjer for regression of programudvikling.</translation>
</message>
<message>
<source>Enter regression test mode, which uses a special chain in which blocks can be solved instantly.</source>
- <translation type="unfinished"/>
+ <translation>Start regressionstesttilstand, som bruger en speciel kæde, hvor blokke kan løses med det samme.</translation>
</message>
<message>
<source>Error: Listening for incoming connections failed (listen returned error %d)</source>
- <translation type="unfinished"/>
+ <translation>Fejl: Lytning efter indkommende forbindelser mislykkedes (lytning returnerede fejl %d)</translation>
</message>
<message>
<source>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.</source>
@@ -2731,7 +2731,7 @@ f.eks.: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.com
</message>
<message>
<source>Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds!</source>
- <translation>Fejl: Denne transaktion kræver et transaktionsgebyr på minimum %s pga. dens størrelse, kompleksitet eller anvendelse af nyligt modtagne bitcoins!</translation>
+ <translation>Fejl: Denne transaktion kræver et transaktionsgebyr på minimum %s pga. dens beløb, kompleksitet eller anvendelse af nyligt modtagne bitcoins!</translation>
</message>
<message>
<source>Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)</source>
@@ -2739,27 +2739,27 @@ f.eks.: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.com
</message>
<message>
<source>Fees smaller than this are considered zero fee (for transaction creation) (default:</source>
- <translation type="unfinished"/>
+ <translation>Gebyrer mindre end dette opfattes som nul-gebyr (for oprettelse af transaktioner) (standard:</translation>
</message>
<message>
<source>Flush database activity from memory pool to disk log every &lt;n&gt; megabytes (default: 100)</source>
- <translation type="unfinished"/>
+ <translation>Flyt databaseaktivitet fra hukommelsespulje til disklog hver &lt;n&gt; megabytes (standard: 100)</translation>
</message>
<message>
<source>How thorough the block verification of -checkblocks is (0-4, default: 3)</source>
- <translation type="unfinished"/>
+ <translation>Hvor gennemarbejdet blokverificeringen for -checkblocks er (0-4; standard: 3)</translation>
</message>
<message>
<source>In this mode -genproclimit controls how many blocks are generated immediately.</source>
- <translation type="unfinished"/>
+ <translation>I denne tilstand styrer -genproclimit hvor mange blokke, der genereres med det samme.</translation>
</message>
<message>
<source>Set the number of script verification threads (%u to %d, 0 = auto, &lt;0 = leave that many cores free, default: %d)</source>
- <translation type="unfinished"/>
+ <translation>Sæt antallet af scriptverificeringstråde (%u til %d, 0 = auto, &lt;0 = efterlad det antal kernet fri, standard: %d)</translation>
</message>
<message>
<source>Set the processor limit for when generation is on (-1 = unlimited, default: -1)</source>
- <translation type="unfinished"/>
+ <translation>Sæt processorbegrænsning for når generering er slået til (-1 = ubegrænset, standard: -1)</translation>
</message>
<message>
<source>This is a pre-release test build - use at your own risk - do not use for mining or merchant applications</source>
@@ -2767,11 +2767,11 @@ f.eks.: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.com
</message>
<message>
<source>Unable to bind to %s on this computer. Bitcoin Core is probably already running.</source>
- <translation type="unfinished"/>
+ <translation>Ikke i stand til at tildele til %s på denne computer. Bitcoin Core kører sansynligvis allerede.</translation>
</message>
<message>
<source>Use separate SOCKS5 proxy to reach peers via Tor hidden services (default: -proxy)</source>
- <translation type="unfinished"/>
+ <translation>Brug separat SOCS5-proxy for at nå andre knuder via Tor skjulte tjenester (standard: -proxy)</translation>
</message>
<message>
<source>Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction.</source>
@@ -2783,11 +2783,11 @@ f.eks.: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.com
</message>
<message>
<source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source>
- <translation type="unfinished"/>
+ <translation>Advarsel: Netværket ser ikke ud til at være fuldt ud enige! Enkelte minere ser ud til at opleve problemer.</translation>
</message>
<message>
<source>Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade.</source>
- <translation type="unfinished"/>
+ <translation>Advarsel: Vi ser ikke ud til at være fuldt ud enige med andre noder! Du kan være nødt til at opgradere, eller andre noder kan være nødt til at opgradere.</translation>
</message>
<message>
<source>Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect.</source>
@@ -2795,19 +2795,19 @@ f.eks.: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.com
</message>
<message>
<source>Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup.</source>
- <translation>Advarsel: wallet.dat ødelagt, data reddet! Oprindelig wallet.net gemt som wallet.{timestamp}.bak i %s; hvis din saldo eller dine transaktioner er forkert, bør du genskabe fra en sikkerhedskopi.</translation>
+ <translation>Advarsel: wallet.dat ødelagt, data reddet! Oprindelig wallet.dat gemt som wallet.{timestamp}.bak i %s; hvis din saldo eller dine transaktioner er forkert, bør du genskabe fra en sikkerhedskopi.</translation>
</message>
<message>
<source>(default: 1)</source>
- <translation type="unfinished"/>
+ <translation>(standard: 1)</translation>
</message>
<message>
<source>(default: wallet.dat)</source>
- <translation type="unfinished"/>
+ <translation>(standard: wallet.dat)</translation>
</message>
<message>
<source>&lt;category&gt; can be:</source>
- <translation type="unfinished"/>
+ <translation>&lt;kategori&gt; kan være:</translation>
</message>
<message>
<source>Attempt to recover private keys from a corrupt wallet.dat</source>
@@ -2815,7 +2815,7 @@ f.eks.: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.com
</message>
<message>
<source>Bitcoin Core Daemon</source>
- <translation type="unfinished"/>
+ <translation>Bitcoin Core-tjeneste</translation>
</message>
<message>
<source>Block creation options:</source>
@@ -2823,7 +2823,7 @@ f.eks.: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.com
</message>
<message>
<source>Clear list of wallet transactions (diagnostic tool; implies -rescan)</source>
- <translation type="unfinished"/>
+ <translation>Ryd liste over transaktioner i tegnebog (diagnoseværktøj; medfører -rescan)</translation>
</message>
<message>
<source>Connect only to the specified node(s)</source>
@@ -2831,15 +2831,15 @@ f.eks.: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.com
</message>
<message>
<source>Connect through SOCKS proxy</source>
- <translation type="unfinished"/>
+ <translation>Forbind gennem SOCKS-proxy</translation>
</message>
<message>
<source>Connect to JSON-RPC on &lt;port&gt; (default: 8332 or testnet: 18332)</source>
- <translation type="unfinished"/>
+ <translation>Forbind til JSON-RPC på &lt;port&gt; (standard: 8332 eller testnetværk: 18332)</translation>
</message>
<message>
<source>Connection options:</source>
- <translation type="unfinished"/>
+ <translation>Tilvalg for forbindelser:</translation>
</message>
<message>
<source>Corrupted block database detected</source>
@@ -2847,11 +2847,11 @@ f.eks.: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.com
</message>
<message>
<source>Debugging/Testing options:</source>
- <translation type="unfinished"/>
+ <translation>Tilvalg for fejlfinding/test:</translation>
</message>
<message>
<source>Disable safemode, override a real safe mode event (default: 0)</source>
- <translation type="unfinished"/>
+ <translation>Slå sikker tilstand fra, tilsidesæt hændelser fra sikker tilstand (standard: 0)</translation>
</message>
<message>
<source>Discover own IP address (default: 1 when listening and no -externalip)</source>
@@ -2859,7 +2859,7 @@ f.eks.: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.com
</message>
<message>
<source>Do not load the wallet and disable wallet RPC calls</source>
- <translation type="unfinished"/>
+ <translation>Indlæs ikke tegnebogen og slå tegnebogs-RPC-kald fra</translation>
</message>
<message>
<source>Do you want to rebuild the block database now?</source>
@@ -2939,43 +2939,43 @@ f.eks.: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.com
</message>
<message>
<source>Fee per kB to add to transactions you send</source>
- <translation type="unfinished"/>
+ <translation>Føj gebyr pr. kB til transaktioner, du sender</translation>
</message>
<message>
<source>Fees smaller than this are considered zero fee (for relaying) (default:</source>
- <translation type="unfinished"/>
+ <translation>Gebyrer mindre end dette opfattes som nul-gebyr (for videreførsler) (standard:</translation>
</message>
<message>
<source>Find peers using DNS lookup (default: 1 unless -connect)</source>
- <translation>Find ligeværdige ved DNS-opslag (standard: 1 hvis ikke -connect)</translation>
+ <translation>Find andre knuder ved DNS-opslag (standard: 1 hvis ikke -connect)</translation>
</message>
<message>
<source>Force safe mode (default: 0)</source>
- <translation type="unfinished"/>
+ <translation>Gennemtving sikker tilstand (standard: 0)</translation>
</message>
<message>
<source>Generate coins (default: 0)</source>
- <translation>Generer bitcoins (standard: 0)</translation>
+ <translation>Generér bitcoins (standard: 0)</translation>
</message>
<message>
<source>How many blocks to check at startup (default: 288, 0 = all)</source>
- <translation>Antal blokke som tjekkes ved opstart (0=alle, standard: 288)</translation>
+ <translation>Antal blokke som tjekkes ved opstart (standard: 288, 0=alle)</translation>
</message>
<message>
<source>If &lt;category&gt; is not supplied, output all debugging information.</source>
- <translation type="unfinished"/>
+ <translation>Hvis &lt;kategori&gt; ikke angives, udskriv al fejlsøgningsinformation.</translation>
</message>
<message>
<source>Importing...</source>
- <translation type="unfinished"/>
+ <translation>Importerer …</translation>
</message>
<message>
<source>Incorrect or no genesis block found. Wrong datadir for network?</source>
- <translation type="unfinished"/>
+ <translation>Ukorrekt eller ingen tilblivelsesblok fundet. Forkert datamappe for netværk?</translation>
</message>
<message>
<source>Invalid -onion address: &apos;%s&apos;</source>
- <translation type="unfinished"/>
+ <translation>Ugyldig -onion adresse: &quot;%s&quot;</translation>
</message>
<message>
<source>Not enough file descriptors available.</source>
@@ -2983,11 +2983,11 @@ f.eks.: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.com
</message>
<message>
<source>Prepend debug output with timestamp (default: 1)</source>
- <translation type="unfinished"/>
+ <translation>Føj tidsstempel foran fejlsøgningsoutput (standard: 1)</translation>
</message>
<message>
<source>RPC client options:</source>
- <translation type="unfinished"/>
+ <translation>Tilvalg for RPC-klient:</translation>
</message>
<message>
<source>Rebuild block chain index from current blk000??.dat files</source>
@@ -2995,15 +2995,15 @@ f.eks.: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.com
</message>
<message>
<source>Select SOCKS version for -proxy (4 or 5, default: 5)</source>
- <translation type="unfinished"/>
+ <translation>Vælg SOCKS-version for -proxy (4 eller 5, standard: 5)</translation>
</message>
<message>
<source>Set database cache size in megabytes (%d to %d, default: %d)</source>
- <translation type="unfinished"/>
+ <translation>Sæt cache-størrelse for database i megabytes (%d til %d; standard: %d)</translation>
</message>
<message>
<source>Set maximum block size in bytes (default: %d)</source>
- <translation type="unfinished"/>
+ <translation>Sæt maksimum blokstørrelse i byte (standard: %d)</translation>
</message>
<message>
<source>Set the number of threads to service RPC calls (default: 4)</source>
@@ -3011,47 +3011,47 @@ f.eks.: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.com
</message>
<message>
<source>Specify wallet file (within data directory)</source>
- <translation type="unfinished"/>
+ <translation>Angiv tegnebogsfil (inden for datamappe)</translation>
</message>
<message>
<source>Spend unconfirmed change when sending transactions (default: 1)</source>
- <translation type="unfinished"/>
+ <translation>Brug ubekræftede byttepenge under afsendelse af transaktioner (standard: 1)</translation>
</message>
<message>
<source>This is intended for regression testing tools and app development.</source>
- <translation type="unfinished"/>
+ <translation>This is intended for regression testing tools and app development.</translation>
</message>
<message>
<source>Usage (deprecated, use bitcoin-cli):</source>
- <translation type="unfinished"/>
+ <translation>Brug (forældet, brug bitcoin-cli):</translation>
</message>
<message>
<source>Verifying blocks...</source>
- <translation>Verificerer blokke...</translation>
+ <translation>Verificerer blokke …</translation>
</message>
<message>
<source>Verifying wallet...</source>
- <translation>Verificerer tegnebog...</translation>
+ <translation>Verificerer tegnebog …</translation>
</message>
<message>
<source>Wait for RPC server to start</source>
- <translation type="unfinished"/>
+ <translation>Vent på opstart af RPC-server</translation>
</message>
<message>
<source>Wallet %s resides outside data directory %s</source>
- <translation type="unfinished"/>
+ <translation>Tegnebog %1 findes uden for datamappe %s</translation>
</message>
<message>
<source>Wallet options:</source>
- <translation type="unfinished"/>
+ <translation>Tilvalg for tegnebog:</translation>
</message>
<message>
<source>Warning: Deprecated argument -debugnet ignored, use -debug=net</source>
- <translation type="unfinished"/>
+ <translation>Advarsel: Forældet argument -debugnet ignoreret; brug -debug=net</translation>
</message>
<message>
<source>You need to rebuild the database using -reindex to change -txindex</source>
- <translation type="unfinished"/>
+ <translation>Du er nødt til at genopbygge databasen ved hjælp af -reindex for at ændre -txindex</translation>
</message>
<message>
<source>Imports blocks from external blk000??.dat file</source>
@@ -3059,19 +3059,19 @@ f.eks.: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.com
</message>
<message>
<source>Cannot obtain a lock on data directory %s. Bitcoin Core is probably already running.</source>
- <translation type="unfinished"/>
+ <translation>Kan ikke opnå en lås på datamappe %s. Bitcoin Core kører sansynligvis allerede.</translation>
</message>
<message>
<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 type="unfinished"/>
+ <translation>Udfør kommando, når en relevant alarm modtages eller vi ser en virkelig lang udsplitning (%s i cmd erstattes af besked)</translation>
</message>
<message>
<source>Output debugging information (default: 0, supplying &lt;category&gt; is optional)</source>
- <translation type="unfinished"/>
+ <translation>Udskriv fejlsøgningsinformation (standard: 0, angivelse af &lt;kategori&gt; er valgfri)</translation>
</message>
<message>
<source>Set maximum size of high-priority/low-fee transactions in bytes (default: %d)</source>
- <translation type="unfinished"/>
+ <translation>Sæt maksimumstørrelse for højprioritet/lavgebyr-transaktioner i byte (standard: %d)</translation>
</message>
<message>
<source>Information</source>
@@ -3079,19 +3079,19 @@ f.eks.: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.com
</message>
<message>
<source>Invalid amount for -minrelaytxfee=&lt;amount&gt;: &apos;%s&apos;</source>
- <translation>Ugyldigt beløb til -minrelaytxfee=&lt;beløb&gt;:&apos;%s&apos;</translation>
+ <translation>Ugyldigt beløb til -minrelaytxfee=&lt;beløb&gt;: &quot;%s&quot;</translation>
</message>
<message>
<source>Invalid amount for -mintxfee=&lt;amount&gt;: &apos;%s&apos;</source>
- <translation>Ugyldigt beløb til -mintxfee=&lt;beløb&gt;:&apos;%s&apos;</translation>
+ <translation>Ugyldigt beløb til -mintxfee=&lt;beløb&gt;: &quot;%s&quot;</translation>
</message>
<message>
<source>Limit size of signature cache to &lt;n&gt; entries (default: 50000)</source>
- <translation type="unfinished"/>
+ <translation>Begræns størrelsen på signaturcache til &lt;n&gt; indgange (standard: 50000)</translation>
</message>
<message>
<source>Log transaction priority and fee per kB when mining blocks (default: 0)</source>
- <translation type="unfinished"/>
+ <translation>Prioritet for transaktionslog og gebyr pr. kB under udvinding af blokke (standard: 0)</translation>
</message>
<message>
<source>Maintain a full transaction index (default: 0)</source>
@@ -3099,15 +3099,15 @@ f.eks.: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.com
</message>
<message>
<source>Maximum per-connection receive buffer, &lt;n&gt;*1000 bytes (default: 5000)</source>
- <translation>Maksimum for modtagelsesbuffer pr. forbindelse, &lt;n&gt;*1000 bytes (standard: 5000)</translation>
+ <translation>Maksimum for modtagelsesbuffer pr. forbindelse, &lt;n&gt;*1000 byte (standard: 5000)</translation>
</message>
<message>
<source>Maximum per-connection send buffer, &lt;n&gt;*1000 bytes (default: 1000)</source>
- <translation>Maksimum for afsendelsesbuffer pr. forbindelse, &lt;n&gt;*1000 bytes (standard: 1000)</translation>
+ <translation>Maksimum for afsendelsesbuffer pr. forbindelse, &lt;n&gt;*1000 byte (standard: 1000)</translation>
</message>
<message>
<source>Only accept block chain matching built-in checkpoints (default: 1)</source>
- <translation>Accepter kun blokkæde, som matcher indbyggede kontrolposter (standard: 1)</translation>
+ <translation>Acceptér kun blokkæde, som matcher indbyggede kontrolposter (standard: 1)</translation>
</message>
<message>
<source>Only connect to nodes in network &lt;net&gt; (IPv4, IPv6 or Tor)</source>
@@ -3115,31 +3115,31 @@ f.eks.: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.com
</message>
<message>
<source>Print block on startup, if found in block index</source>
- <translation type="unfinished"/>
+ <translation>Udskriv blok under opstart, hvis den findes i blokindeks</translation>
</message>
<message>
<source>Print block tree on startup (default: 0)</source>
- <translation type="unfinished"/>
+ <translation>Udskriv bloktræ under startop (standard: 0)</translation>
</message>
<message>
<source>RPC SSL options: (see the Bitcoin Wiki for SSL setup instructions)</source>
- <translation type="unfinished"/>
+ <translation>Tilvalg for RPC SSL: (se Bitcoin Wiki for instruktioner i SSL-opstart)</translation>
</message>
<message>
<source>RPC server options:</source>
- <translation type="unfinished"/>
+ <translation>Tilvalg for RPC-server:</translation>
</message>
<message>
<source>Randomly drop 1 of every &lt;n&gt; network messages</source>
- <translation type="unfinished"/>
+ <translation>Drop tilfældigt 1 ud af hver &lt;n&gt; netværksbeskeder</translation>
</message>
<message>
<source>Randomly fuzz 1 of every &lt;n&gt; network messages</source>
- <translation type="unfinished"/>
+ <translation>Slør tilfældigt 1 ud af hver &lt;n&gt; netværksbeskeder</translation>
</message>
<message>
<source>Run a thread to flush wallet periodically (default: 1)</source>
- <translation type="unfinished"/>
+ <translation>Kør en tråd for at rydde tegnebog periodisk (standard: 1)</translation>
</message>
<message>
<source>SSL options: (see the Bitcoin Wiki for SSL setup instructions)</source>
@@ -3147,7 +3147,7 @@ f.eks.: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.com
</message>
<message>
<source>Send command to Bitcoin Core</source>
- <translation type="unfinished"/>
+ <translation>Send kommando til Bitcoin Core</translation>
</message>
<message>
<source>Send trace/debug info to console instead of debug.log file</source>
@@ -3155,19 +3155,19 @@ f.eks.: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.com
</message>
<message>
<source>Set minimum block size in bytes (default: 0)</source>
- <translation>Angiv minimumsblokstørrelse i bytes (standard: 0)</translation>
+ <translation>Angiv minimumsblokstørrelse i byte (standard: 0)</translation>
</message>
<message>
<source>Sets the DB_PRIVATE flag in the wallet db environment (default: 1)</source>
- <translation type="unfinished"/>
+ <translation>Sætter DB_PRIVATE-flaget i tegnebogens db-miljø (standard: 1)</translation>
</message>
<message>
<source>Show all debugging options (usage: --help -help-debug)</source>
- <translation type="unfinished"/>
+ <translation>Vis alle tilvalg for fejlsøgning (brug: --help -help-debug)</translation>
</message>
<message>
<source>Show benchmark information (default: 0)</source>
- <translation type="unfinished"/>
+ <translation>Vis information om ydelsesmåling (standard: 0)</translation>
</message>
<message>
<source>Shrink debug.log file on client startup (default: 1 when no -debug)</source>
@@ -3183,7 +3183,7 @@ f.eks.: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.com
</message>
<message>
<source>Start Bitcoin Core Daemon</source>
- <translation type="unfinished"/>
+ <translation>Start Bitcoin Core-tjeneste</translation>
</message>
<message>
<source>System error: </source>
@@ -3203,11 +3203,11 @@ f.eks.: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.com
</message>
<message>
<source>Use UPnP to map the listening port (default: 0)</source>
- <translation>Forsøg at bruge UPnP til at konfigurere den lyttende port (standard: 0)</translation>
+ <translation>Brug UPnP til at konfigurere den lyttende port (standard: 0)</translation>
</message>
<message>
<source>Use UPnP to map the listening port (default: 1 when listening)</source>
- <translation>Forsøg at bruge UPnP til at konfigurere den lyttende port (standard: 1 når lytter)</translation>
+ <translation>Brug UPnP til at konfigurere den lyttende port (standard: 1 under lytning)</translation>
</message>
<message>
<source>Username for JSON-RPC connections</source>
@@ -3223,11 +3223,11 @@ f.eks.: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.com
</message>
<message>
<source>Zapping all transactions from wallet...</source>
- <translation type="unfinished"/>
+ <translation>Zapper alle transaktioner fra tegnebog …</translation>
</message>
<message>
<source>on startup</source>
- <translation type="unfinished"/>
+ <translation>under opstart</translation>
</message>
<message>
<source>version</source>
@@ -3311,11 +3311,11 @@ f.eks.: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.com
</message>
<message>
<source>Invalid -proxy address: &apos;%s&apos;</source>
- <translation>Ugyldig -proxy adresse: &apos;%s&apos;</translation>
+ <translation>Ugyldig -proxy adresse: &quot;%s&quot;</translation>
</message>
<message>
<source>Unknown network specified in -onlynet: &apos;%s&apos;</source>
- <translation>Ukendt netværk anført i -onlynet: &apos;%s&apos;</translation>
+ <translation>Ukendt netværk anført i -onlynet: &quot;%s&quot;</translation>
</message>
<message>
<source>Unknown -socks proxy version requested: %i</source>
@@ -3323,15 +3323,15 @@ f.eks.: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.com
</message>
<message>
<source>Cannot resolve -bind address: &apos;%s&apos;</source>
- <translation>Kan ikke finde -bind adressen: &apos;%s&apos;</translation>
+ <translation>Kan ikke finde -bind adressen: &quot;%s&quot;</translation>
</message>
<message>
<source>Cannot resolve -externalip address: &apos;%s&apos;</source>
- <translation>Kan ikke finde -externalip adressen: &apos;%s&apos;</translation>
+ <translation>Kan ikke finde -externalip adressen: &quot;%s&quot;</translation>
</message>
<message>
<source>Invalid amount for -paytxfee=&lt;amount&gt;: &apos;%s&apos;</source>
- <translation>Ugyldigt beløb for -paytxfee=&lt;amount&gt;: &apos;%s&apos;</translation>
+ <translation>Ugyldigt beløb for -paytxfee=&lt;beløb&gt;: &quot;%s&quot;</translation>
</message>
<message>
<source>Invalid amount</source>
@@ -3381,7 +3381,7 @@ f.eks.: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.com
<source>You must set rpcpassword=&lt;password&gt; in the configuration file:
%s
If the file does not exist, create it with owner-readable-only file permissions.</source>
- <translation>Du skal angive rpcpassword=&lt;password&gt; i konfigurationsfilen:
+ <translation>Du skal angive rpcpassword=&lt;adgangskode&gt; i konfigurationsfilen:
%s
Hvis filen ikke eksisterer, opret den og giv ingen andre end ejeren læserettighed.</translation>
</message>
diff --git a/src/qt/locale/bitcoin_el_GR.ts b/src/qt/locale/bitcoin_el_GR.ts
index 687947e3b9..e957a0088e 100644
--- a/src/qt/locale/bitcoin_el_GR.ts
+++ b/src/qt/locale/bitcoin_el_GR.ts
@@ -3,11 +3,11 @@
<name>AboutDialog</name>
<message>
<source>About Bitcoin Core</source>
- <translation type="unfinished"/>
+ <translation>Σχετικά με το Bitcoin Core</translation>
</message>
<message>
<source>&lt;b&gt;Bitcoin Core&lt;/b&gt; version</source>
- <translation type="unfinished"/>
+ <translation>&lt;b&gt;Bitcoin Core&lt;/b&gt; έκδοση</translation>
</message>
<message>
<source>
@@ -29,11 +29,11 @@ This product includes software developed by the OpenSSL Project for use in the O
</message>
<message>
<source>The Bitcoin Core developers</source>
- <translation type="unfinished"/>
+ <translation>Οι προγραμματιστές του Bitcoin Core</translation>
</message>
<message>
<source>(%1-bit)</source>
- <translation type="unfinished"/>
+ <translation>(%1-bit)</translation>
</message>
</context>
<context>
@@ -128,11 +128,11 @@ This product includes software developed by the OpenSSL Project for use in the O
</message>
<message>
<source>Exporting Failed</source>
- <translation type="unfinished"/>
+ <translation>Η εξαγωγή απέτυχε</translation>
</message>
<message>
<source>There was an error trying to save the address list to %1.</source>
- <translation type="unfinished"/>
+ <translation>Παρουσιάστηκε σφάλμα κατά την αποθήκευση της λίστας πορτοφολιών στο %1.</translation>
</message>
</context>
<context>
@@ -438,7 +438,7 @@ This product includes software developed by the OpenSSL Project for use in the O
</message>
<message>
<source>&amp;About Bitcoin Core</source>
- <translation type="unfinished"/>
+ <translation>&amp;Σχετικά με το Bitcoin Core</translation>
</message>
<message>
<source>Show the list of used sending addresses and labels</source>
@@ -494,11 +494,11 @@ This product includes software developed by the OpenSSL Project for use in the O
</message>
<message>
<source>%1 and %2</source>
- <translation type="unfinished"/>
+ <translation>%1 και %2</translation>
</message>
<message numerus="yes">
<source>%n year(s)</source>
- <translation type="unfinished"><numerusform></numerusform><numerusform></numerusform></translation>
+ <translation><numerusform>%n έτος</numerusform><numerusform>%n έτη</numerusform></translation>
</message>
<message>
<source>%1 behind</source>
@@ -608,11 +608,11 @@ Address: %4
</message>
<message>
<source>Change:</source>
- <translation type="unfinished"/>
+ <translation>Ρέστα:</translation>
</message>
<message>
<source>(un)select all</source>
- <translation type="unfinished"/>
+ <translation>(από)επιλογή όλων</translation>
</message>
<message>
<source>Tree mode</source>
@@ -672,7 +672,7 @@ Address: %4
</message>
<message>
<source>Copy quantity</source>
- <translation type="unfinished"/>
+ <translation>Αντιγραφή ποσότητας</translation>
</message>
<message>
<source>Copy fee</source>
@@ -684,11 +684,11 @@ Address: %4
</message>
<message>
<source>Copy bytes</source>
- <translation type="unfinished"/>
+ <translation>Αντιγραφή των byte</translation>
</message>
<message>
<source>Copy priority</source>
- <translation type="unfinished"/>
+ <translation>Αντιγραφή προτεραιότητας</translation>
</message>
<message>
<source>Copy low output</source>
@@ -696,51 +696,51 @@ Address: %4
</message>
<message>
<source>Copy change</source>
- <translation type="unfinished"/>
+ <translation>Αντιγραφή των ρέστων</translation>
</message>
<message>
<source>highest</source>
- <translation type="unfinished"/>
+ <translation>ύψιστη</translation>
</message>
<message>
<source>higher</source>
- <translation type="unfinished"/>
+ <translation>υψηλότερη</translation>
</message>
<message>
<source>high</source>
- <translation type="unfinished"/>
+ <translation>ψηλή</translation>
</message>
<message>
<source>medium-high</source>
- <translation type="unfinished"/>
+ <translation>μεσαία-ψηλή</translation>
</message>
<message>
<source>medium</source>
- <translation type="unfinished"/>
+ <translation>μεσαία</translation>
</message>
<message>
<source>low-medium</source>
- <translation type="unfinished"/>
+ <translation>μεσαία-χαμηλή</translation>
</message>
<message>
<source>low</source>
- <translation type="unfinished"/>
+ <translation>χαμηλή</translation>
</message>
<message>
<source>lower</source>
- <translation type="unfinished"/>
+ <translation>χαμηλότερη</translation>
</message>
<message>
<source>lowest</source>
- <translation type="unfinished"/>
+ <translation>χαμηλότατη</translation>
</message>
<message>
<source>(%1 locked)</source>
- <translation type="unfinished"/>
+ <translation>(%1 κλειδωμένο)</translation>
</message>
<message>
<source>none</source>
- <translation type="unfinished"/>
+ <translation>κανένα</translation>
</message>
<message>
<source>Dust</source>
@@ -796,11 +796,12 @@ Address: %4
</message>
<message>
<source>change from %1 (%2)</source>
- <translation type="unfinished"/>
+ <translation>ρέστα από %1 (%2) </translation>
</message>
<message>
<source>(change)</source>
- <translation type="unfinished"/>
+ <translation>(ρέστα)
+</translation>
</message>
</context>
<context>
@@ -815,7 +816,7 @@ Address: %4
</message>
<message>
<source>The label associated with this address list entry</source>
- <translation type="unfinished"/>
+ <translation>Η ετικέτα που συνδέεται με αυτήν την καταχώρηση στο βιβλίο διευθύνσεων</translation>
</message>
<message>
<source>The address associated with this address list entry. This can only be modified for sending addresses.</source>
@@ -936,11 +937,11 @@ Address: %4
</message>
<message>
<source>Welcome to Bitcoin Core.</source>
- <translation type="unfinished"/>
+ <translation>Καλώς ήρθατε στο Bitcoin Core.</translation>
</message>
<message>
<source>As this is the first time the program is launched, you can choose where Bitcoin Core will store its data.</source>
- <translation type="unfinished"/>
+ <translation>Καθώς αυτή είναι η πρώτη φορά που εκκινείται το πρόγραμμα, μπορείτε να διαλέξετε πού θα αποθηκεύει το Bitcoin Core τα δεδομένα του.</translation>
</message>
<message>
<source>Bitcoin Core will download and store a copy of the Bitcoin block chain. At least %1GB of data will be stored in this directory, and it will grow over time. The wallet will also be stored in this directory.</source>
@@ -1030,7 +1031,7 @@ Address: %4
</message>
<message>
<source>MB</source>
- <translation type="unfinished"/>
+ <translation>MB</translation>
</message>
<message>
<source>Number of script &amp;verification threads</source>
@@ -1082,7 +1083,7 @@ Address: %4
</message>
<message>
<source>Expert</source>
- <translation type="unfinished"/>
+ <translation>Έμπειρος</translation>
</message>
<message>
<source>Enable coin &amp;control features</source>
@@ -1190,7 +1191,7 @@ Address: %4
</message>
<message>
<source>none</source>
- <translation type="unfinished"/>
+ <translation>κανένα</translation>
</message>
<message>
<source>Confirm options reset</source>
@@ -1198,7 +1199,7 @@ Address: %4
</message>
<message>
<source>Client restart required to activate changes.</source>
- <translation type="unfinished"/>
+ <translation>Χρειάζεται επανεκκίνηση του προγράμματος για να ενεργοποιηθούν οι αλλαγές.</translation>
</message>
<message>
<source>Client will be shutdown, do you want to proceed?</source>
@@ -1229,7 +1230,7 @@ Address: %4
</message>
<message>
<source>Available:</source>
- <translation type="unfinished"/>
+ <translation>Διαθέσιμο:</translation>
</message>
<message>
<source>Your current spendable balance</source>
@@ -1370,11 +1371,11 @@ Address: %4
<name>QRImageWidget</name>
<message>
<source>&amp;Save Image...</source>
- <translation type="unfinished"/>
+ <translation>&amp;Αποθήκευση εικόνας...</translation>
</message>
<message>
<source>&amp;Copy Image</source>
- <translation type="unfinished"/>
+ <translation>&amp;Αντιγραφή εικόνας</translation>
</message>
<message>
<source>Save QR Code</source>
@@ -1409,7 +1410,7 @@ Address: %4
</message>
<message>
<source>General</source>
- <translation type="unfinished"/>
+ <translation>Γενικά</translation>
</message>
<message>
<source>Using OpenSSL version</source>
@@ -1425,7 +1426,7 @@ Address: %4
</message>
<message>
<source>Name</source>
- <translation type="unfinished"/>
+ <translation>Όνομα</translation>
</message>
<message>
<source>Number of connections</source>
@@ -1457,11 +1458,11 @@ Address: %4
</message>
<message>
<source>&amp;Network Traffic</source>
- <translation type="unfinished"/>
+ <translation>&amp;Κίνηση δικτύου</translation>
</message>
<message>
<source>&amp;Clear</source>
- <translation type="unfinished"/>
+ <translation>&amp;Εκκαθάριση</translation>
</message>
<message>
<source>Totals</source>
@@ -1536,7 +1537,7 @@ Address: %4
<name>ReceiveCoinsDialog</name>
<message>
<source>&amp;Amount:</source>
- <translation type="unfinished"/>
+ <translation>&amp;Ποσό:</translation>
</message>
<message>
<source>&amp;Label:</source>
@@ -1544,7 +1545,7 @@ Address: %4
</message>
<message>
<source>&amp;Message:</source>
- <translation type="unfinished"/>
+ <translation>&amp;Μήνυμα:</translation>
</message>
<message>
<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>
@@ -1584,7 +1585,7 @@ Address: %4
</message>
<message>
<source>&amp;Request payment</source>
- <translation type="unfinished"/>
+ <translation>&amp;Αίτηση πληρωμής</translation>
</message>
<message>
<source>Show the selected request (does the same as double clicking an entry)</source>
@@ -1608,7 +1609,7 @@ Address: %4
</message>
<message>
<source>Copy message</source>
- <translation type="unfinished"/>
+ <translation>Αντιγραφή μηνύματος</translation>
</message>
<message>
<source>Copy amount</source>
@@ -1631,7 +1632,7 @@ Address: %4
</message>
<message>
<source>&amp;Save Image...</source>
- <translation type="unfinished"/>
+ <translation>&amp;Αποθήκευση εικόνας...</translation>
</message>
<message>
<source>Request payment to %1</source>
@@ -1698,7 +1699,7 @@ Address: %4
</message>
<message>
<source>(no amount)</source>
- <translation type="unfinished"/>
+ <translation>(κανένα ποσό)</translation>
</message>
</context>
<context>
@@ -1717,7 +1718,7 @@ Address: %4
</message>
<message>
<source>automatically selected</source>
- <translation type="unfinished"/>
+ <translation>επιλεγμένο αυτόματα</translation>
</message>
<message>
<source>Insufficient funds!</source>
@@ -1753,7 +1754,7 @@ Address: %4
</message>
<message>
<source>Change:</source>
- <translation type="unfinished"/>
+ <translation>Ρέστα:</translation>
</message>
<message>
<source>If this is activated, but the change address is empty or invalid, change will be sent to a newly generated address.</source>
@@ -1801,7 +1802,7 @@ Address: %4
</message>
<message>
<source>Copy quantity</source>
- <translation type="unfinished"/>
+ <translation>Αντιγραφή ποσότητας</translation>
</message>
<message>
<source>Copy amount</source>
@@ -1817,11 +1818,11 @@ Address: %4
</message>
<message>
<source>Copy bytes</source>
- <translation type="unfinished"/>
+ <translation>Αντιγραφή των byte</translation>
</message>
<message>
<source>Copy priority</source>
- <translation type="unfinished"/>
+ <translation>Αντιγραφή προτεραιότητας</translation>
</message>
<message>
<source>Copy low output</source>
@@ -1829,15 +1830,15 @@ Address: %4
</message>
<message>
<source>Copy change</source>
- <translation type="unfinished"/>
+ <translation>Αντιγραφή των ρέστων</translation>
</message>
<message>
<source>Total Amount %1 (= %2)</source>
- <translation type="unfinished"/>
+ <translation>Ολικό Ποσό %1 (= %2)</translation>
</message>
<message>
<source>or</source>
- <translation type="unfinished"/>
+ <translation>ή</translation>
</message>
<message>
<source>The recipient address is not valid, please recheck.</source>
@@ -1940,7 +1941,7 @@ Address: %4
</message>
<message>
<source>Remove this entry</source>
- <translation type="unfinished"/>
+ <translation>Αφαίρεση αυτής της καταχώρησης</translation>
</message>
<message>
<source>Message:</source>
@@ -1975,11 +1976,11 @@ Address: %4
<name>ShutdownWindow</name>
<message>
<source>Bitcoin Core is shutting down...</source>
- <translation type="unfinished"/>
+ <translation>Το Bitcoin Core τερματίζεται...</translation>
</message>
<message>
<source>Do not shut down the computer until this window disappears.</source>
- <translation type="unfinished"/>
+ <translation>Μην απενεργοποιήσετε τον υπολογιστή μέχρι να κλείσει αυτό το παράθυρο.</translation>
</message>
</context>
<context>
@@ -2133,7 +2134,7 @@ Address: %4
</message>
<message>
<source>The Bitcoin Core developers</source>
- <translation type="unfinished"/>
+ <translation>Οι προγραμματιστές του Bitcoin Core</translation>
</message>
<message>
<source>[testnet]</source>
@@ -2341,11 +2342,11 @@ Address: %4
</message>
<message>
<source>Offline</source>
- <translation type="unfinished"/>
+ <translation>Offline</translation>
</message>
<message>
<source>Unconfirmed</source>
- <translation type="unfinished"/>
+ <translation>Ανεπιβεβαίωτες</translation>
</message>
<message>
<source>Confirming (%1 of %2 recommended confirmations)</source>
@@ -2484,19 +2485,19 @@ Address: %4
</message>
<message>
<source>Export Transaction History</source>
- <translation type="unfinished"/>
+ <translation>Εξαγωγή Ιστορικού Συναλλαγών</translation>
</message>
<message>
<source>Exporting Failed</source>
- <translation type="unfinished"/>
+ <translation>Η Εξαγωγή Απέτυχε</translation>
</message>
<message>
<source>There was an error trying to save the transaction history to %1.</source>
- <translation type="unfinished"/>
+ <translation>Yπήρξε σφάλμα κατά την προσπάθεια αποθήκευσης του ιστορικού συναλλαγών στο %1.</translation>
</message>
<message>
<source>Exporting Successful</source>
- <translation type="unfinished"/>
+ <translation>Επιτυχής εξαγωγή</translation>
</message>
<message>
<source>The transaction history was successfully saved to %1.</source>
@@ -2547,7 +2548,7 @@ Address: %4
<name>WalletFrame</name>
<message>
<source>No wallet has been loaded.</source>
- <translation type="unfinished"/>
+ <translation>Δεν έχει φορτωθεί πορτοφόλι</translation>
</message>
</context>
<context>
@@ -2585,7 +2586,7 @@ Address: %4
</message>
<message>
<source>The wallet data was successfully saved to %1.</source>
- <translation type="unfinished"/>
+ <translation>Τα δεδομένα πορτοφολιού αποθηκεύτηκαν με επιτυχία στο %1.</translation>
</message>
<message>
<source>Backup Successful</source>
@@ -2801,11 +2802,11 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
</message>
<message>
<source>(default: 1)</source>
- <translation type="unfinished"/>
+ <translation>(προεπιλογή: 1)</translation>
</message>
<message>
<source>(default: wallet.dat)</source>
- <translation type="unfinished"/>
+ <translation>(προεπιλογή: wallet.dat)</translation>
</message>
<message>
<source>&lt;category&gt; can be:</source>
@@ -2841,7 +2842,7 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
</message>
<message>
<source>Connection options:</source>
- <translation type="unfinished"/>
+ <translation>Επιλογές σύνδεσης:</translation>
</message>
<message>
<source>Corrupted block database detected</source>
@@ -3045,7 +3046,7 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
</message>
<message>
<source>Wallet options:</source>
- <translation type="unfinished"/>
+ <translation>Επιλογές πορτοφολιού:</translation>
</message>
<message>
<source>Warning: Deprecated argument -debugnet ignored, use -debug=net</source>
@@ -3229,7 +3230,7 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
</message>
<message>
<source>on startup</source>
- <translation type="unfinished"/>
+ <translation>κατά την εκκίνηση</translation>
</message>
<message>
<source>version</source>
diff --git a/src/qt/locale/bitcoin_id_ID.ts b/src/qt/locale/bitcoin_id_ID.ts
index c4dee5f92d..2b9685f6a0 100644
--- a/src/qt/locale/bitcoin_id_ID.ts
+++ b/src/qt/locale/bitcoin_id_ID.ts
@@ -433,7 +433,7 @@ Produk ini termasuk software yang dibangun oleh Proyek OpenSSL untuk Toolkit Ope
</message>
<message>
<source>Request payments (generates QR codes and bitcoin: URIs)</source>
- <translation type="unfinished"/>
+ <translation>Permintaan pembayaran (membangkitkan kode QR dan bitcoin: URIs)</translation>
</message>
<message>
<source>&amp;About Bitcoin Core</source>
@@ -473,7 +473,7 @@ Produk ini termasuk software yang dibangun oleh Proyek OpenSSL untuk Toolkit Ope
</message>
<message>
<source>Processed %1 of %2 (estimated) blocks of transaction history.</source>
- <translation type="unfinished"/>
+ <translation>Proses % 1 dar i% 2 (perkiraan) blok catatan transaksi</translation>
</message>
<message>
<source>Processed %1 blocks of transaction history.</source>
@@ -509,7 +509,7 @@ Produk ini termasuk software yang dibangun oleh Proyek OpenSSL untuk Toolkit Ope
</message>
<message>
<source>Transactions after this will not yet be visible.</source>
- <translation type="unfinished"/>
+ <translation>Transaksi setelah ini tidak akan ditampilkan</translation>
</message>
<message>
<source>Error</source>
@@ -561,7 +561,7 @@ Alamat: %4
</message>
<message>
<source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source>
- <translation type="unfinished"/>
+ <translation>Terjadi kesalahan fatal. Bitcoin tidak bisa lagi meneruskan dengan aman dan akan berhenti.</translation>
</message>
</context>
<context>
@@ -611,15 +611,15 @@ Alamat: %4
</message>
<message>
<source>(un)select all</source>
- <translation type="unfinished"/>
+ <translation>(Tidak)memilih semua</translation>
</message>
<message>
<source>Tree mode</source>
- <translation type="unfinished"/>
+ <translation>mode pohon</translation>
</message>
<message>
<source>List mode</source>
- <translation type="unfinished"/>
+ <translation>Mode daftar</translation>
</message>
<message>
<source>Amount</source>
@@ -663,11 +663,11 @@ Alamat: %4
</message>
<message>
<source>Lock unspent</source>
- <translation type="unfinished"/>
+ <translation>Kunci terpakai.</translation>
</message>
<message>
<source>Unlock unspent</source>
- <translation type="unfinished"/>
+ <translation>Membuka kunci terpakai</translation>
</message>
<message>
<source>Copy quantity</source>
@@ -1350,7 +1350,7 @@ Alamat: %4
</message>
<message>
<source>Error: Cannot parse configuration file: %1. Only use key=value syntax.</source>
- <translation type="unfinished"/>
+ <translation>Kesalahan: Tidak dapat memproses pengaturan berkas: %1. Hanya menggunakan kunci= nilai sintak.</translation>
</message>
<message>
<source>Error: Invalid combination of -regtest and -testnet.</source>
@@ -1408,7 +1408,7 @@ Alamat: %4
</message>
<message>
<source>General</source>
- <translation type="unfinished"/>
+ <translation>Umum</translation>
</message>
<message>
<source>Using OpenSSL version</source>
@@ -1460,7 +1460,7 @@ Alamat: %4
</message>
<message>
<source>&amp;Clear</source>
- <translation type="unfinished"/>
+ <translation>&amp;Kosongkan</translation>
</message>
<message>
<source>Totals</source>
@@ -1504,31 +1504,31 @@ Alamat: %4
</message>
<message>
<source>%1 B</source>
- <translation type="unfinished"/>
+ <translation>%1 B</translation>
</message>
<message>
<source>%1 KB</source>
- <translation type="unfinished"/>
+ <translation>%1 KB</translation>
</message>
<message>
<source>%1 MB</source>
- <translation type="unfinished"/>
+ <translation>%1 MB</translation>
</message>
<message>
<source>%1 GB</source>
- <translation type="unfinished"/>
+ <translation>%1 GB</translation>
</message>
<message>
<source>%1 m</source>
- <translation type="unfinished"/>
+ <translation>%1 menit</translation>
</message>
<message>
<source>%1 h</source>
- <translation type="unfinished"/>
+ <translation>%1 Jam</translation>
</message>
<message>
<source>%1 h %2 m</source>
- <translation type="unfinished"/>
+ <translation>%1 Jam %2 menit</translation>
</message>
</context>
<context>
@@ -1551,7 +1551,7 @@ Alamat: %4
</message>
<message>
<source>R&amp;euse an existing receiving address (not recommended)</source>
- <translation type="unfinished"/>
+ <translation>Gunakan lagi alamat penerima yang ada (tidak disarankan)</translation>
</message>
<message>
<source>An optional message to attach to the payment request, which will be displayed when the request is opened. Note: The message will not be sent with the payment over the Bitcoin network.</source>
@@ -1716,7 +1716,7 @@ Alamat: %4
</message>
<message>
<source>automatically selected</source>
- <translation type="unfinished"/>
+ <translation>Pemilihan otomatis</translation>
</message>
<message>
<source>Insufficient funds!</source>
@@ -1947,7 +1947,7 @@ Alamat: %4
</message>
<message>
<source>This is a verified payment request.</source>
- <translation type="unfinished"/>
+ <translation>Permintaan pembayaran terverifikasi.</translation>
</message>
<message>
<source>Enter a label for this address to add it to the list of used addresses</source>
@@ -1959,7 +1959,7 @@ Alamat: %4
</message>
<message>
<source>This is an unverified payment request.</source>
- <translation type="unfinished"/>
+ <translation>Permintaan pembayaran tidak terverifikasi.</translation>
</message>
<message>
<source>Pay To:</source>
@@ -2005,7 +2005,7 @@ Alamat: %4
</message>
<message>
<source>Alt+A</source>
- <translation>Alt+J</translation>
+ <translation>Alt+A</translation>
</message>
<message>
<source>Paste address from clipboard</source>
@@ -2726,7 +2726,7 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
</message>
<message>
<source>Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)</source>
- <translation type="unfinished"/>
+ <translation>Jalankan perintah ketika perubahan transaksi dompet (%s di cmd digantikan oleh TxID)</translation>
</message>
<message>
<source>Fees smaller than this are considered zero fee (for transaction creation) (default:</source>
@@ -2790,11 +2790,11 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
</message>
<message>
<source>(default: 1)</source>
- <translation type="unfinished"/>
+ <translation>(pengaturan awal: 1)</translation>
</message>
<message>
<source>(default: wallet.dat)</source>
- <translation type="unfinished"/>
+ <translation>(pengaturan awal: wallet.dat)</translation>
</message>
<message>
<source>&lt;category&gt; can be:</source>
@@ -2830,7 +2830,7 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
</message>
<message>
<source>Connection options:</source>
- <translation type="unfinished"/>
+ <translation>Pilih koneksi:</translation>
</message>
<message>
<source>Corrupted block database detected</source>
@@ -2858,11 +2858,11 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
</message>
<message>
<source>Error initializing block database</source>
- <translation type="unfinished"/>
+ <translation>Kesalahan menginisialisasi database blok</translation>
</message>
<message>
<source>Error initializing wallet database environment %s!</source>
- <translation type="unfinished"/>
+ <translation>Kesalahan menginisialisasi dompet pada database%s!</translation>
</message>
<message>
<source>Error loading block database</source>
@@ -2958,7 +2958,7 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
</message>
<message>
<source>Importing...</source>
- <translation type="unfinished"/>
+ <translation>mengimpor...</translation>
</message>
<message>
<source>Incorrect or no genesis block found. Wrong datadir for network?</source>
@@ -2970,7 +2970,7 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
</message>
<message>
<source>Not enough file descriptors available.</source>
- <translation type="unfinished"/>
+ <translation>Deskripsi berkas tidak tersedia dengan cukup.</translation>
</message>
<message>
<source>Prepend debug output with timestamp (default: 1)</source>
@@ -2978,7 +2978,7 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
</message>
<message>
<source>RPC client options:</source>
- <translation type="unfinished"/>
+ <translation>Pilihan RPC klien:</translation>
</message>
<message>
<source>Rebuild block chain index from current blk000??.dat files</source>
@@ -2998,7 +2998,7 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
</message>
<message>
<source>Set the number of threads to service RPC calls (default: 4)</source>
- <translation type="unfinished"/>
+ <translation>Mengatur jumlah urutan untuk layanan panggilan RPC (pengaturan awal: 4)</translation>
</message>
<message>
<source>Specify wallet file (within data directory)</source>
@@ -3174,11 +3174,11 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
</message>
<message>
<source>Start Bitcoin Core Daemon</source>
- <translation type="unfinished"/>
+ <translation>Memulai Bitcoin Core Daemon</translation>
</message>
<message>
<source>System error: </source>
- <translation type="unfinished"/>
+ <translation>Kesalahan sistem:</translation>
</message>
<message>
<source>Transaction amount too small</source>
diff --git a/src/qt/locale/bitcoin_ko_KR.ts b/src/qt/locale/bitcoin_ko_KR.ts
index fb013f4c1d..ce30a8603d 100644
--- a/src/qt/locale/bitcoin_ko_KR.ts
+++ b/src/qt/locale/bitcoin_ko_KR.ts
@@ -33,14 +33,14 @@ MIT/X11 프로그램 라이선스에 따라 배포합니다. COPYING 또는 http
</message>
<message>
<source>(%1-bit)</source>
- <translation type="unfinished"/>
+ <translation>(%1-비트)</translation>
</message>
</context>
<context>
<name>AddressBookPage</name>
<message>
<source>Double-click to edit address or label</source>
- <translation>주소 또는 표를 편집하기 위해 더블클릭 하시오</translation>
+ <translation>지갑 주소나 제목을 수정하려면 더블클릭하세요.</translation>
</message>
<message>
<source>Create a new address</source>
@@ -611,7 +611,7 @@ Address: %4
</message>
<message>
<source>(un)select all</source>
- <translation type="unfinished"/>
+ <translation>모두 선택(하지 않음)</translation>
</message>
<message>
<source>Tree mode</source>
@@ -663,11 +663,11 @@ Address: %4
</message>
<message>
<source>Lock unspent</source>
- <translation type="unfinished"/>
+ <translation>비트코인이 사용되지 않은 주소를 잠금 처리합니다.</translation>
</message>
<message>
<source>Unlock unspent</source>
- <translation type="unfinished"/>
+ <translation>비트코인이 사용되지 않은 주소를 잠금 해제합니다. </translation>
</message>
<message>
<source>Copy quantity</source>
@@ -755,7 +755,7 @@ Address: %4
</message>
<message>
<source>This label turns red, if the transaction size is greater than 1000 bytes.</source>
- <translation type="unfinished"/>
+ <translation>만약 거래 양이 1000bytes 보다 크면 제목이 빨간색으로 변합니다</translation>
</message>
<message>
<source>This means a fee of at least %1 per kB is required.</source>
@@ -767,27 +767,27 @@ Address: %4
</message>
<message>
<source>Transactions with higher priority are more likely to get included into a block.</source>
- <translation type="unfinished"/>
+ <translation>우선 순위가 높은 거래의 경우 블럭에 포함될 가능성이 더 많습니다.</translation>
</message>
<message>
<source>This label turns red, if the priority is smaller than &quot;medium&quot;.</source>
- <translation type="unfinished"/>
+ <translation>우선권이 중간보다 작으면 제목이 빨간색으로 변합니다. </translation>
</message>
<message>
<source>This label turns red, if any recipient receives an amount smaller than %1.</source>
- <translation type="unfinished"/>
+ <translation>만약 수령인이 받은 액수가 잔고의 1%보다 작으면 이 제목이 빨간색으로 변합니다.</translation>
</message>
<message>
<source>This means a fee of at least %1 is required.</source>
- <translation type="unfinished"/>
+ <translation>최소 %1의 거래 수수료가 필요하다는 뜻입니다. </translation>
</message>
<message>
<source>Amounts below 0.546 times the minimum relay fee are shown as dust.</source>
- <translation type="unfinished"/>
+ <translation>노드 릴레이를 위한 최저 수수료의 0.546배보다 낮은 거래는 먼지 거래로 표현됩니다.</translation>
</message>
<message>
<source>This label turns red, if the change is smaller than %1.</source>
- <translation type="unfinished"/>
+ <translation>만약 잔돈이 1%보다 작다면 제목이 빨간색으로 변합니다</translation>
</message>
<message>
<source>(no label)</source>
@@ -916,7 +916,7 @@ Address: %4
</message>
<message>
<source>Set SSL root certificates for payment request (default: -system-)</source>
- <translation type="unfinished"/>
+ <translation>지불 요청을 위해 SSL 최상위 인증을 설정합니다. (기본값: -system-)</translation>
</message>
<message>
<source>Show splash screen on startup (default: 1)</source>
@@ -939,11 +939,11 @@ Address: %4
</message>
<message>
<source>As this is the first time the program is launched, you can choose where Bitcoin Core will store its data.</source>
- <translation type="unfinished"/>
+ <translation>프로그램이 처음으로 실행되고 있습니다. 비트코인 코어가 어디에 데이터를 저장할지 선택할 수 있습니다. </translation>
</message>
<message>
<source>Bitcoin Core will download and store a copy of the Bitcoin block chain. At least %1GB of data will be stored in this directory, and it will grow over time. The wallet will also be stored in this directory.</source>
- <translation type="unfinished"/>
+ <translation>비트코인 코어가 블럭체인의 복사본을 다운로드 저장합니다. 적어도 %1GB의 데이터가 이 폴더에 저장되며 시간이 경과할수록 점차 증가합니다. 그리고 지갑 또한 이 폴더에 저장됩니다. </translation>
</message>
<message>
<source>Use the default data directory</source>
@@ -959,7 +959,7 @@ Address: %4
</message>
<message>
<source>Error: Specified data directory &quot;%1&quot; can not be created.</source>
- <translation type="unfinished"/>
+ <translation>오류 : 별도 정의한 폴더명 &quot;%1&quot; 생성에 실패했습니다. </translation>
</message>
<message>
<source>Error</source>
@@ -1033,7 +1033,7 @@ Address: %4
</message>
<message>
<source>Number of script &amp;verification threads</source>
- <translation type="unfinished"/>
+ <translation>스크립트 인증 쓰레드의 개수</translation>
</message>
<message>
<source>Connect to the Bitcoin network through a SOCKS proxy.</source>
@@ -1053,7 +1053,7 @@ Address: %4
</message>
<message>
<source>Third party transaction URLs</source>
- <translation type="unfinished"/>
+ <translation>제 3자 거래 URLs</translation>
</message>
<message>
<source>Active command-line options that override above options:</source>
@@ -1081,11 +1081,11 @@ Address: %4
</message>
<message>
<source>Expert</source>
- <translation type="unfinished"/>
+ <translation>전문가</translation>
</message>
<message>
<source>Enable coin &amp;control features</source>
- <translation type="unfinished"/>
+ <translation>코인 상세 제어기능을 활성화합니다 - &amp;C</translation>
</message>
<message>
<source>If you disable the spending of unconfirmed change, the change from a transaction cannot be used until that transaction has at least one confirmation. This also affects how your balance is computed.</source>
@@ -1093,7 +1093,7 @@ Address: %4
</message>
<message>
<source>&amp;Spend unconfirmed change</source>
- <translation type="unfinished"/>
+ <translation>&amp;확인되지 않은 돈을 쓰다</translation>
</message>
<message>
<source>Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled.</source>
@@ -1173,7 +1173,7 @@ Address: %4
</message>
<message>
<source>Whether to show coin control features or not.</source>
- <translation type="unfinished"/>
+ <translation>코인 상세 제어기능에 대한 표시 여부를 선택할 수 있습니다.</translation>
</message>
<message>
<source>&amp;OK</source>
@@ -1197,7 +1197,7 @@ Address: %4
</message>
<message>
<source>Client restart required to activate changes.</source>
- <translation type="unfinished"/>
+ <translation>변경 사항을 적용하기 위해서는 프로그램이 종료 후 재시작되어야 합니다.</translation>
</message>
<message>
<source>Client will be shutdown, do you want to proceed?</source>
@@ -1205,7 +1205,7 @@ Address: %4
</message>
<message>
<source>This change would require a client restart.</source>
- <translation type="unfinished"/>
+ <translation>이 변경 사항 적용을 위해 프로그램 재시작이 필요합니다. </translation>
</message>
<message>
<source>The supplied proxy address is invalid.</source>
@@ -1279,7 +1279,7 @@ Address: %4
</message>
<message>
<source>Requested payment amount of %1 is too small (considered dust).</source>
- <translation type="unfinished"/>
+ <translation>요청한 금액 %1의 양이 너무 적습니다. (스팸성 거래로 간주)</translation>
</message>
<message>
<source>Payment request error</source>
@@ -1295,7 +1295,7 @@ Address: %4
</message>
<message>
<source>Your active proxy doesn&apos;t support SOCKS5, which is required for payment requests via proxy.</source>
- <translation type="unfinished"/>
+ <translation>현재의 프록시가 SOCKS5를 지원하지 않아 지불 요청을 수행할 수 없습니다. </translation>
</message>
<message>
<source>Payment request fetch URL is invalid: %1</source>
@@ -1303,7 +1303,7 @@ Address: %4
</message>
<message>
<source>Payment request file handling</source>
- <translation type="unfinished"/>
+ <translation>지불이 파일 처리를 요청합니다</translation>
</message>
<message>
<source>Payment request file can not be read or processed! This can be caused by an invalid payment request file.</source>
@@ -1354,7 +1354,7 @@ Address: %4
</message>
<message>
<source>Error: Invalid combination of -regtest and -testnet.</source>
- <translation type="unfinished"/>
+ <translation>오류: 잘못된 -regtest 와 -testnet의 조합입니다.</translation>
</message>
<message>
<source>Bitcoin Core didn&apos;t yet exit safely...</source>
@@ -1460,7 +1460,7 @@ Address: %4
</message>
<message>
<source>&amp;Clear</source>
- <translation type="unfinished"/>
+ <translation>&amp;지우기</translation>
</message>
<message>
<source>Totals</source>
@@ -1547,11 +1547,11 @@ Address: %4
</message>
<message>
<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>이전에 사용된 수취용 주소를 사용할려고 합니다. 주소의 재사용은 보안과 개인정보 보호 측면에서 문제를 초래할 수 있습니다. 이전 지불 요청을 재생성하는 경우가 아니라면 주소 재사용을 권하지 않습니다. </translation>
</message>
<message>
<source>R&amp;euse an existing receiving address (not recommended)</source>
- <translation type="unfinished"/>
+ <translation>현재의 수취용 주소를 재사용합니다만 권장하지는 않습니다. (R&amp;)</translation>
</message>
<message>
<source>An optional message to attach to the payment request, which will be displayed when the request is opened. Note: The message will not be sent with the payment over the Bitcoin network.</source>
@@ -1567,7 +1567,7 @@ Address: %4
</message>
<message>
<source>An optional amount to request. Leave this empty or zero to not request a specific amount.</source>
- <translation type="unfinished"/>
+ <translation>요청할 금액 입력칸으로 선택 사항입니다. 빈 칸으로 두거나 특정 금액이 필요하지 않는 경우 0을 입력하세요. </translation>
</message>
<message>
<source>Clear all fields of the form.</source>
@@ -1712,7 +1712,7 @@ Address: %4
</message>
<message>
<source>Inputs...</source>
- <translation type="unfinished"/>
+ <translation>입력...</translation>
</message>
<message>
<source>automatically selected</source>
@@ -1864,7 +1864,7 @@ Address: %4
</message>
<message>
<source>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.</source>
- <translation type="unfinished"/>
+ <translation>거래가 거부되었습니다. 몇몇 코인들이 지갑에서 이미 사용된 경우, 예를 들어 코인을 이미 사용한 wallet.dat를 복사해서 사용한 경우 지금 지갑에 기록이 안되있어 이런 일이 생길 수 있습니다.</translation>
</message>
<message>
<source>Warning: Invalid Bitcoin address</source>
@@ -1951,7 +1951,7 @@ Address: %4
</message>
<message>
<source>Enter a label for this address to add it to the list of used addresses</source>
- <translation type="unfinished"/>
+ <translation>사용된 주소 목록에 새 주소를 추가하기 위해 제목을 입력합니다. </translation>
</message>
<message>
<source>A message that was attached to the bitcoin: URI which will be stored with the transaction for your reference. Note: This message will not be sent over the Bitcoin network.</source>
@@ -1963,7 +1963,7 @@ Address: %4
</message>
<message>
<source>Pay To:</source>
- <translation type="unfinished"/>
+ <translation>송금할 대상 : </translation>
</message>
<message>
<source>Memo:</source>
@@ -2246,7 +2246,7 @@ Address: %4
</message>
<message>
<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 &quot;not accepted&quot; and it won&apos;t be spendable. This may occasionally happen if another node generates a block within a few seconds of yours.</source>
- <translation type="unfinished"/>
+ <translation>신규 채굴된 코인이 사용되기 위해서는 %1 개의 블럭이 경과되어야 합니다. 블럭을 생성할 때 블럭체인에 추가되도록 네트워크에 전파되는 과정을 거치는데, 블럭체인에 포함되지 못하고 실패한다면 해당 블럭의 상태는 &apos;미승인&apos;으로 표현되고 비트코인 또한 사용될 수 없습니다. 이 현상은 다른 노드가 비슷한 시간대에 동시에 블럭을 생성할 때 종종 발생할 수 있습니다. </translation>
</message>
<message>
<source>Debug information</source>
@@ -2316,7 +2316,7 @@ Address: %4
</message>
<message>
<source>Immature (%1 confirmations, will be available after %2)</source>
- <translation type="unfinished"/>
+ <translation>충분히 숙성되지 않은 상태 (%1 승인, %2 후에 사용 가능합니다)</translation>
</message>
<message numerus="yes">
<source>Open for %n more block(s)</source>
@@ -2348,7 +2348,7 @@ Address: %4
</message>
<message>
<source>Confirming (%1 of %2 recommended confirmations)</source>
- <translation type="unfinished"/>
+ <translation>승인 중 (권장되는 승인 회수 %2 대비 현재 승인 수 %1)</translation>
</message>
<message>
<source>Conflicted</source>
@@ -2580,7 +2580,7 @@ Address: %4
</message>
<message>
<source>There was an error trying to save the wallet data to %1.</source>
- <translation type="unfinished"/>
+ <translation>지갑 데이터를 %1 폴더에 저장하는 동안 오류가 발생했습니다. </translation>
</message>
<message>
<source>The wallet data was successfully saved to %1.</source>
@@ -2651,7 +2651,7 @@ Address: %4
</message>
<message>
<source>Listen for JSON-RPC connections on &lt;port&gt; (default: 8332 or testnet: 18332)</source>
- <translation type="unfinished"/>
+ <translation>포트 &lt;port&gt;을 통해 JSON-RPC 연결 (기본값: 8332 또는 testnet: 18332)</translation>
</message>
<message>
<source>Accept command line and JSON-RPC commands</source>
@@ -2659,7 +2659,7 @@ Address: %4
</message>
<message>
<source>Bitcoin Core RPC client version</source>
- <translation type="unfinished"/>
+ <translation>비트코인 코어 RPC 클라이언트 버전</translation>
</message>
<message>
<source>Run in the background as a daemon and accept commands</source>
@@ -2693,7 +2693,7 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
</message>
<message>
<source>An error occurred while setting up the RPC port %u for listening on IPv6, falling back to IPv4: %s</source>
- <translation type="unfinished"/>
+ <translation>IPv6 연결을 위해 RPC port %u 설정 중 오류가 발생했습니다. IPv4: %s 환경으로 돌아갑니다.</translation>
</message>
<message>
<source>Bind to given address and always listen on it. Use [host]:port notation for IPv6</source>
@@ -2717,7 +2717,9 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
</message>
<message>
<source>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.</source>
- <translation type="unfinished"/>
+ <translation>에러: 거래가 거부되었습니다! 이런 일이 생길 수 있습니다 만약 몇개의 코인들을 지갑에서 이미 사용했다면요, 예를 들어 만약 당신이 wallet.dat를 복사해서 사용했거나 코인들을 사용 후에 복사했다면 여기선 표시가 안되서 사용할 수 없습니다
+
+-번역은 했으나 약간 이상한점이 있어서 수정해야함-</translation>
</message>
<message>
<source>Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds!</source>
@@ -2725,11 +2727,11 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
</message>
<message>
<source>Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)</source>
- <translation type="unfinished"/>
+ <translation>지갑 거래가 바뀌면 명령을 실행합니다.(%s 안의 명령어가 TxID로 바뀝니다)</translation>
</message>
<message>
<source>Fees smaller than this are considered zero fee (for transaction creation) (default:</source>
- <translation type="unfinished"/>
+ <translation>해당 금액보다 적은 수수료는 수수료 면제로 간주됩니다. (거래 생성의 목적)(기본값:</translation>
</message>
<message>
<source>Flush database activity from memory pool to disk log every &lt;n&gt; megabytes (default: 100)</source>
@@ -2789,11 +2791,11 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
</message>
<message>
<source>(default: 1)</source>
- <translation type="unfinished"/>
+ <translation>(기본값: 1)</translation>
</message>
<message>
<source>(default: wallet.dat)</source>
- <translation type="unfinished"/>
+ <translation>(기본값: wallet.dat)</translation>
</message>
<message>
<source>&lt;category&gt; can be:</source>
@@ -2829,7 +2831,7 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
</message>
<message>
<source>Connection options:</source>
- <translation type="unfinished"/>
+ <translation>연결 설정 : </translation>
</message>
<message>
<source>Corrupted block database detected</source>
@@ -2837,11 +2839,11 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
</message>
<message>
<source>Debugging/Testing options:</source>
- <translation type="unfinished"/>
+ <translation>디버그 및 테스트 설정</translation>
</message>
<message>
<source>Disable safemode, override a real safe mode event (default: 0)</source>
- <translation type="unfinished"/>
+ <translation>안전 모드를 비활성화하고 안전 모드의 이벤트가 발생하더라도 무시합니다. (기본값: 0, 비활성화)</translation>
</message>
<message>
<source>Discover own IP address (default: 1 when listening and no -externalip)</source>
@@ -2861,7 +2863,7 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
</message>
<message>
<source>Error initializing wallet database environment %s!</source>
- <translation type="unfinished"/>
+ <translation>지갑 데이터베이스 환경 초기화하는데 오류</translation>
</message>
<message>
<source>Error loading block database</source>
@@ -2929,11 +2931,11 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
</message>
<message>
<source>Fee per kB to add to transactions you send</source>
- <translation type="unfinished"/>
+ <translation>송금 거래시 추가되는 KB 당 수수료입니다. </translation>
</message>
<message>
<source>Fees smaller than this are considered zero fee (for relaying) (default:</source>
- <translation type="unfinished"/>
+ <translation>해당 금액보다 적은 수수료는 수수료 면제로 간주됩니다. (릴레이 목적)(기본값:</translation>
</message>
<message>
<source>Find peers using DNS lookup (default: 1 unless -connect)</source>
@@ -2941,7 +2943,7 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
</message>
<message>
<source>Force safe mode (default: 0)</source>
- <translation type="unfinished"/>
+ <translation>안전 모드로 강제 진입하는 기능입니다.(기본값: 0) </translation>
</message>
<message>
<source>Generate coins (default: 0)</source>
@@ -2961,7 +2963,7 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
</message>
<message>
<source>Incorrect or no genesis block found. Wrong datadir for network?</source>
- <translation type="unfinished"/>
+ <translation>올바르지 않거나 생성된 블록을 찾을 수 없습니다. 잘못된 네트워크 자료 디렉토리?</translation>
</message>
<message>
<source>Invalid -onion address: &apos;%s&apos;</source>
@@ -3053,7 +3055,7 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
</message>
<message>
<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 type="unfinished"/>
+ <translation>이 사항과 관련있는 경고가 발생하거나 아주 긴 포크가 발생했을 때 명령어를 실행해 주세요. (cmd 명령어 목록에서 %s는 메시지로 대체됩니다) </translation>
</message>
<message>
<source>Output debugging information (default: 0, supplying &lt;category&gt; is optional)</source>
@@ -3061,7 +3063,7 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
</message>
<message>
<source>Set maximum size of high-priority/low-fee transactions in bytes (default: %d)</source>
- <translation type="unfinished"/>
+ <translation>최대 크기를 최우선으로 설정 / 바이트당 최소 수수료로 거래(기본값: %d)</translation>
</message>
<message>
<source>Information</source>
@@ -3077,11 +3079,11 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
</message>
<message>
<source>Limit size of signature cache to &lt;n&gt; entries (default: 50000)</source>
- <translation type="unfinished"/>
+ <translation>&lt;n&gt;번 째 순서에서 전자서명 캐쉬의 용량을 제한합니다. (기본값: 50000) </translation>
</message>
<message>
<source>Log transaction priority and fee per kB when mining blocks (default: 0)</source>
- <translation type="unfinished"/>
+ <translation>블럭을 채굴할 때 kB당 거래 우선 순위와 수수료를 로그에 남깁니다. (기본값: 0, 비활성화)</translation>
</message>
<message>
<source>Maintain a full transaction index (default: 0)</source>
@@ -3089,11 +3091,11 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
</message>
<message>
<source>Maximum per-connection receive buffer, &lt;n&gt;*1000 bytes (default: 5000)</source>
- <translation type="unfinished"/>
+ <translation>최대 연결마다 1000bytes 버퍼를 받는다. (기본값: 5000)</translation>
</message>
<message>
<source>Maximum per-connection send buffer, &lt;n&gt;*1000 bytes (default: 1000)</source>
- <translation type="unfinished"/>
+ <translation>최대 연결 마다 1000bytes 버퍼를 보낸다.(기본값: 1000) </translation>
</message>
<message>
<source>Only accept block chain matching built-in checkpoints (default: 1)</source>
@@ -3101,27 +3103,27 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
</message>
<message>
<source>Only connect to nodes in network &lt;net&gt; (IPv4, IPv6 or Tor)</source>
- <translation type="unfinished"/>
+ <translation>노드가 있는 네트워크에만 접속 합니다(IPv4, IPv6 또는 Tor)</translation>
</message>
<message>
<source>Print block on startup, if found in block index</source>
- <translation type="unfinished"/>
+ <translation>블럭 색인을 발견하면 구동 시 블럭을 출력합니다.</translation>
</message>
<message>
<source>Print block tree on startup (default: 0)</source>
- <translation type="unfinished"/>
+ <translation>구동 시 블럭 트리를 출력합니다. (기본값: 0, 비활성화)</translation>
</message>
<message>
<source>RPC SSL options: (see the Bitcoin Wiki for SSL setup instructions)</source>
- <translation type="unfinished"/>
+ <translation>RPC SSL 옵션: (비트코인 위키의 SSL 설정 설명서 참고)</translation>
</message>
<message>
<source>RPC server options:</source>
- <translation type="unfinished"/>
+ <translation>RPC 서버 설정</translation>
</message>
<message>
<source>Randomly drop 1 of every &lt;n&gt; network messages</source>
- <translation type="unfinished"/>
+ <translation>모든 네트워크 메시지 마다 무작위로 1이 떨어진다</translation>
</message>
<message>
<source>Randomly fuzz 1 of every &lt;n&gt; network messages</source>
@@ -3137,7 +3139,7 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
</message>
<message>
<source>Send command to Bitcoin Core</source>
- <translation type="unfinished"/>
+ <translation>비트코인 코어로 명령 보내기</translation>
</message>
<message>
<source>Send trace/debug info to console instead of debug.log file</source>
@@ -3149,15 +3151,15 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
</message>
<message>
<source>Sets the DB_PRIVATE flag in the wallet db environment (default: 1)</source>
- <translation type="unfinished"/>
+ <translation>전자지갑 데이터베이스 환경에 DB_PRIVATE 플래그를 설정합니다. (기본값: 1, 활성화)</translation>
</message>
<message>
<source>Show all debugging options (usage: --help -help-debug)</source>
- <translation type="unfinished"/>
+ <translation>모든 디버그 설정 보기(설정: --help -help-debug)</translation>
</message>
<message>
<source>Show benchmark information (default: 0)</source>
- <translation type="unfinished"/>
+ <translation>벤치마크 정보 보기(기본값: 0)</translation>
</message>
<message>
<source>Shrink debug.log file on client startup (default: 1 when no -debug)</source>
@@ -3217,7 +3219,7 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
</message>
<message>
<source>on startup</source>
- <translation type="unfinished"/>
+ <translation>구동 중</translation>
</message>
<message>
<source>version</source>
diff --git a/src/qt/locale/bitcoin_nb.ts b/src/qt/locale/bitcoin_nb.ts
index 1267ad65b9..9e38c69c60 100644
--- a/src/qt/locale/bitcoin_nb.ts
+++ b/src/qt/locale/bitcoin_nb.ts
@@ -599,7 +599,7 @@ Adresse: %4
</message>
<message>
<source>Low Output:</source>
- <translation>Lav Utdata:</translation>
+ <translation>Svake Utdata:</translation>
</message>
<message>
<source>After Fee:</source>
@@ -1744,7 +1744,7 @@ Adresse: %4
</message>
<message>
<source>Low Output:</source>
- <translation>Svak Utdata:</translation>
+ <translation>Svake Utdata:</translation>
</message>
<message>
<source>After Fee:</source>
@@ -2730,7 +2730,7 @@ For eksempel: varselmelding=echo %%s | mail -s &quot;Bitcoin Varsel&quot; admin@
</message>
<message>
<source>Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds!</source>
- <translation>Feil: Denne transaksjonen trenger en gebyr på minst %s på grunn av beløpet, kompleksiteten eller bruk av allerede mottatte penger!</translation>
+ <translation>Feil: Denne transaksjonen trenger et gebyr på minst %s på grunn av beløpet, kompleksiteten eller bruk av allerede mottatte penger!</translation>
</message>
<message>
<source>Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)</source>
diff --git a/src/qt/locale/bitcoin_ro_RO.ts b/src/qt/locale/bitcoin_ro_RO.ts
index 1d9d4cc936..d09c40f62e 100644
--- a/src/qt/locale/bitcoin_ro_RO.ts
+++ b/src/qt/locale/bitcoin_ro_RO.ts
@@ -795,7 +795,7 @@ Adresa: %4
</message>
<message>
<source>change from %1 (%2)</source>
- <translation type="unfinished"/>
+ <translation>restul de la %1 (%2)</translation>
</message>
<message>
<source>(change)</source>
@@ -1587,7 +1587,7 @@ Adresa: %4
</message>
<message>
<source>Show the selected request (does the same as double clicking an entry)</source>
- <translation type="unfinished"/>
+ <translation>Arata cererea selectata (acelas lucru ca si dublu-click pe o inregistrare)</translation>
</message>
<message>
<source>Show</source>
@@ -3008,7 +3008,7 @@ spre exemplu: alertnotify=echo %%s | mail -s &quot;Alerta Bitcoin&quot; admin@fo
</message>
<message>
<source>Set the number of threads to service RPC calls (default: 4)</source>
- <translation type="unfinished"/>
+ <translation>Stabileste numarul de thread-uri care servesc apeluri RPC (implicit: 4)</translation>
</message>
<message>
<source>Specify wallet file (within data directory)</source>
diff --git a/src/qt/locale/bitcoin_sl_SI.ts b/src/qt/locale/bitcoin_sl_SI.ts
index 1a46c6ae6c..2ad31e911b 100644
--- a/src/qt/locale/bitcoin_sl_SI.ts
+++ b/src/qt/locale/bitcoin_sl_SI.ts
@@ -344,7 +344,7 @@ This product includes software developed by the OpenSSL Project for use in the O
</message>
<message>
<source>Modify configuration options for Bitcoin</source>
- <translation type="unfinished"/>
+ <translation>Spremeni konfiguracijo nastavitev za Bitcoin</translation>
</message>
<message>
<source>Backup wallet to another location</source>
@@ -1144,7 +1144,7 @@ Naslov: %4
</message>
<message>
<source>User Interface &amp;language:</source>
- <translation type="unfinished"/>
+ <translation>Vmesnik uporabnika &amp;jezik:</translation>
</message>
<message>
<source>The user interface language can be set here. This setting will take effect after restarting Bitcoin.</source>
@@ -1487,11 +1487,11 @@ Naslov: %4
</message>
<message>
<source>Welcome to the Bitcoin RPC console.</source>
- <translation type="unfinished"/>
+ <translation>Dobrodošli na Bitcoin RPC konzoli.</translation>
</message>
<message>
<source>Use up and down arrows to navigate history, and &lt;b&gt;Ctrl-L&lt;/b&gt; to clear screen.</source>
- <translation type="unfinished"/>
+ <translation>Uporabi puščice za gor in dol za navigacijo po zgodovini in &lt;b&gt;Ctrl-L&lt;/b&gt; za izbris izpisa na ekranu.</translation>
</message>
<message>
<source>Type &lt;b&gt;help&lt;/b&gt; for an overview of available commands.</source>
@@ -1847,7 +1847,7 @@ Naslov: %4
</message>
<message>
<source>The total exceeds your balance when the %1 transaction fee is included.</source>
- <translation type="unfinished"/>
+ <translation>Celotni znesek presega vaše stanje, ko je zaračunana 1% provizija.</translation>
</message>
<message>
<source>Duplicate address found, can only send to each address once per send operation.</source>
@@ -2626,7 +2626,7 @@ Naslov: %4
</message>
<message>
<source>Connect to a node to retrieve peer addresses, and disconnect</source>
- <translation type="unfinished"/>
+ <translation>Povežite se z vozliščem za pridobitev naslovov uporabnikov in nato prekinite povezavo.</translation>
</message>
<message>
<source>Specify your own public address</source>
@@ -2638,7 +2638,7 @@ Naslov: %4
</message>
<message>
<source>Number of seconds to keep misbehaving peers from reconnecting (default: 86400)</source>
- <translation type="unfinished"/>
+ <translation>Število sekund za težavo pri vzpostavitvi povezave med uporabniki (privzeto: 86400)</translation>
</message>
<message>
<source>An error occurred while setting up the RPC port %u for listening on IPv4: %s</source>
@@ -3268,11 +3268,11 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
</message>
<message>
<source>Unable to bind to %s on this computer (bind returned error %d, %s)</source>
- <translation type="unfinished"/>
+ <translation>Nemogoče je povezati s/z %s na tem računalniku (povezava je vrnila napaka %d, %s)</translation>
</message>
<message>
<source>Allow DNS lookups for -addnode, -seednode and -connect</source>
- <translation type="unfinished"/>
+ <translation>Omogoči DNS poizvedbe za -addnode, -seednode in -connect.</translation>
</message>
<message>
<source>Loading addresses...</source>
@@ -3296,27 +3296,27 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
</message>
<message>
<source>Invalid -proxy address: &apos;%s&apos;</source>
- <translation type="unfinished"/>
+ <translation>Neveljaven -proxy naslov: &apos;%s&apos;</translation>
</message>
<message>
<source>Unknown network specified in -onlynet: &apos;%s&apos;</source>
- <translation type="unfinished"/>
+ <translation>Neznano omrežje določeno v -onlynet: &apos;%s&apos;.</translation>
</message>
<message>
<source>Unknown -socks proxy version requested: %i</source>
- <translation type="unfinished"/>
+ <translation>Neznano -socks zahtevan zastopnik različice: %i</translation>
</message>
<message>
<source>Cannot resolve -bind address: &apos;%s&apos;</source>
- <translation type="unfinished"/>
+ <translation>Nemogoče rešiti -bind naslova: &apos;%s&apos;</translation>
</message>
<message>
<source>Cannot resolve -externalip address: &apos;%s&apos;</source>
- <translation type="unfinished"/>
+ <translation>Nemogoče rešiti -externalip naslova: &apos;%s&apos;</translation>
</message>
<message>
<source>Invalid amount for -paytxfee=&lt;amount&gt;: &apos;%s&apos;</source>
- <translation type="unfinished"/>
+ <translation>Neveljavna količina za -paytxfee=&lt;amount&gt;: &apos;%s&apos;</translation>
</message>
<message>
<source>Invalid amount</source>
@@ -3344,7 +3344,7 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
</message>
<message>
<source>Cannot write default address</source>
- <translation type="unfinished"/>
+ <translation>Ni mogoče zapisati privzetega naslova</translation>
</message>
<message>
<source>Rescanning...</source>
@@ -3356,7 +3356,7 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
</message>
<message>
<source>To use the %s option</source>
- <translation type="unfinished"/>
+ <translation>Za uporabo %s opcije</translation>
</message>
<message>
<source>Error</source>
@@ -3366,7 +3366,9 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
<source>You must set rpcpassword=&lt;password&gt; in the configuration file:
%s
If the file does not exist, create it with owner-readable-only file permissions.</source>
- <translation type="unfinished"/>
+ <translation>Potrebno je nastaviti rpcpassword=&lt;password&gt; v nastavitveni datoteki:
+%s
+Če datoteka ne obstaja jo ustvarite z dovoljenjem, da jo lahko bere samo uporabnik.</translation>
</message>
</context>
</TS> \ No newline at end of file
diff --git a/src/qt/locale/bitcoin_th_TH.ts b/src/qt/locale/bitcoin_th_TH.ts
index 96c49b12d0..54e15a75e0 100644
--- a/src/qt/locale/bitcoin_th_TH.ts
+++ b/src/qt/locale/bitcoin_th_TH.ts
@@ -35,7 +35,7 @@ This product includes software developed by the OpenSSL Project for use in the O
<name>AddressBookPage</name>
<message>
<source>Double-click to edit address or label</source>
- <translation>ดับเบิลคลิก เพื่อแก้ไขที่อยู่ หรือชื่อ</translation>
+ <translation>ดับเบิ้ลคลิก เพื่อแก้ไขที่อยู่ หรือชื่อ</translation>
</message>
<message>
<source>Create a new address</source>
@@ -75,7 +75,7 @@ This product includes software developed by the OpenSSL Project for use in the O
</message>
<message>
<source>&amp;Delete</source>
- <translation>ลบ</translation>
+ <translation>&amp;ลบ</translation>
</message>
<message>
<source>Choose the address to send coins to</source>
@@ -119,7 +119,7 @@ This product includes software developed by the OpenSSL Project for use in the O
</message>
<message>
<source>Comma separated file (*.csv)</source>
- <translation type="unfinished"/>
+ <translation>คั่นไฟล์ด้วยเครื่องหมายจุลภาค (*.csv)</translation>
</message>
<message>
<source>Exporting Failed</source>
@@ -165,7 +165,7 @@ This product includes software developed by the OpenSSL Project for use in the O
</message>
<message>
<source>Enter the new passphrase to the wallet.&lt;br/&gt;Please use a passphrase of &lt;b&gt;10 or more random characters&lt;/b&gt;, or &lt;b&gt;eight or more words&lt;/b&gt;.</source>
- <translation type="unfinished"/>
+ <translation>ใส่รหัสผ่านใหม่ให้กับกระเป๋าเงิน. &lt;br/&gt; กรุณาใช้รหัสผ่านของ &lt;b&gt; 10 หรือแบบสุ่มมากกว่าตัวอักษร &lt;/ b&gt; หรือ &lt;b&gt; แปดหรือมากกว่าคำ &lt;/ b&gt;</translation>
</message>
<message>
<source>Encrypt wallet</source>
@@ -173,7 +173,7 @@ This product includes software developed by the OpenSSL Project for use in the O
</message>
<message>
<source>This operation needs your wallet passphrase to unlock the wallet.</source>
- <translation type="unfinished"/>
+ <translation>การดำเนินการนี้ต้องมีรหัสผ่านกระเป๋าเงินของคุณเพื่อปลดล็อคกระเป๋าเงิน</translation>
</message>
<message>
<source>Unlock wallet</source>
@@ -181,7 +181,7 @@ This product includes software developed by the OpenSSL Project for use in the O
</message>
<message>
<source>This operation needs your wallet passphrase to decrypt the wallet.</source>
- <translation type="unfinished"/>
+ <translation>การดำเนินการนี้ต้องมีรหัสผ่านกระเป๋าเงินของคุณในการถอดรหัสกระเป๋าเงิน</translation>
</message>
<message>
<source>Decrypt wallet</source>
@@ -229,7 +229,7 @@ This product includes software developed by the OpenSSL Project for use in the O
</message>
<message>
<source>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source>
- <translation type="unfinished"/>
+ <translation>กระเป๋าเงินเข้ารหัสล้มเหลวเนื่องจากข้อผิดพลาดภายใน กระเป๋าเงินของคุณไม่ได้เข้ารหัส</translation>
</message>
<message>
<source>The supplied passphrases do not match.</source>
@@ -237,15 +237,15 @@ This product includes software developed by the OpenSSL Project for use in the O
</message>
<message>
<source>Wallet unlock failed</source>
- <translation type="unfinished"/>
+ <translation>ปลดล็อคกระเป๋าเงินล้มเหลว</translation>
</message>
<message>
<source>The passphrase entered for the wallet decryption was incorrect.</source>
- <translation type="unfinished"/>
+ <translation>ป้อนรหัสผ่านสำหรับการถอดรหัสกระเป๋าเงินไม่ถูกต้อง</translation>
</message>
<message>
<source>Wallet decryption failed</source>
- <translation type="unfinished"/>
+ <translation>ถอดรหัสกระเป๋าเงินล้มเหลว</translation>
</message>
<message>
<source>Wallet passphrase was successfully changed.</source>
@@ -260,11 +260,11 @@ This product includes software developed by the OpenSSL Project for use in the O
</message>
<message>
<source>Synchronizing with network...</source>
- <translation type="unfinished"/>
+ <translation>กำลังทำข้อมูลให้ตรงกันกับเครือข่าย ...</translation>
</message>
<message>
<source>&amp;Overview</source>
- <translation type="unfinished"/>
+ <translation>&amp;ภาพรวม</translation>
</message>
<message>
<source>Node</source>
@@ -272,15 +272,15 @@ This product includes software developed by the OpenSSL Project for use in the O
</message>
<message>
<source>Show general overview of wallet</source>
- <translation type="unfinished"/>
+ <translation>แสดงภาพรวมทั่วไปของกระเป๋าเงิน</translation>
</message>
<message>
<source>&amp;Transactions</source>
- <translation type="unfinished"/>
+ <translation>&amp;การทำรายการ</translation>
</message>
<message>
<source>Browse transaction history</source>
- <translation type="unfinished"/>
+ <translation>เรียกดูประวัติการทำธุรกรรม</translation>
</message>
<message>
<source>E&amp;xit</source>
@@ -288,11 +288,11 @@ This product includes software developed by the OpenSSL Project for use in the O
</message>
<message>
<source>Quit application</source>
- <translation type="unfinished"/>
+ <translation>ออกจากโปรแกรม</translation>
</message>
<message>
<source>Show information about Bitcoin</source>
- <translation type="unfinished"/>
+ <translation>แสดงข้อมูลเกี่ยวกับ Bitcoin</translation>
</message>
<message>
<source>About &amp;Qt</source>
@@ -304,7 +304,7 @@ This product includes software developed by the OpenSSL Project for use in the O
</message>
<message>
<source>&amp;Options...</source>
- <translation type="unfinished"/>
+ <translation>&amp;ตัวเลือก...</translation>
</message>
<message>
<source>&amp;Encrypt Wallet...</source>
@@ -352,7 +352,7 @@ This product includes software developed by the OpenSSL Project for use in the O
</message>
<message>
<source>Change the passphrase used for wallet encryption</source>
- <translation type="unfinished"/>
+ <translation>เปลี่ยนรหัสผ่านที่ใช้สำหรับการเข้ารหัสกระเป๋าเงิน</translation>
</message>
<message>
<source>&amp;Debug window</source>
@@ -404,23 +404,23 @@ This product includes software developed by the OpenSSL Project for use in the O
</message>
<message>
<source>&amp;File</source>
- <translation type="unfinished"/>
+ <translation>&amp;ไฟล์</translation>
</message>
<message>
<source>&amp;Settings</source>
- <translation type="unfinished"/>
+ <translation>&amp;การตั้งค่า</translation>
</message>
<message>
<source>&amp;Help</source>
- <translation type="unfinished"/>
+ <translation>&amp;ช่วยเหลือ</translation>
</message>
<message>
<source>Tabs toolbar</source>
- <translation type="unfinished"/>
+ <translation>แถบเครื่องมือ</translation>
</message>
<message>
<source>[testnet]</source>
- <translation type="unfinished"/>
+ <translation>[testnet]</translation>
</message>
<message>
<source>Bitcoin Core</source>
@@ -460,7 +460,7 @@ This product includes software developed by the OpenSSL Project for use in the O
</message>
<message numerus="yes">
<source>%n active connection(s) to Bitcoin network</source>
- <translation type="unfinished"><numerusform></numerusform></translation>
+ <translation><numerusform>%n ที่ใช้งานการเชื่อมต่อกับเครือข่าย Bitcoin</numerusform></translation>
</message>
<message>
<source>No block source available...</source>
@@ -520,19 +520,19 @@ This product includes software developed by the OpenSSL Project for use in the O
</message>
<message>
<source>Up to date</source>
- <translation type="unfinished"/>
+ <translation>ทันสมัย</translation>
</message>
<message>
<source>Catching up...</source>
- <translation type="unfinished"/>
+ <translation>จับได้...</translation>
</message>
<message>
<source>Sent transaction</source>
- <translation type="unfinished"/>
+ <translation>รายการที่ส่ง</translation>
</message>
<message>
<source>Incoming transaction</source>
- <translation type="unfinished"/>
+ <translation>การทำรายการขาเข้า</translation>
</message>
<message>
<source>Date: %1
@@ -544,11 +544,11 @@ Address: %4
</message>
<message>
<source>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;unlocked&lt;/b&gt;</source>
- <translation type="unfinished"/>
+ <translation>ระเป๋าเงินถูก &lt;b&gt;เข้ารหัส&lt;/b&gt; และในขณะนี้ &lt;b&gt;ปลดล็อคแล้ว&lt;/b&gt;</translation>
</message>
<message>
<source>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;locked&lt;/b&gt;</source>
- <translation type="unfinished"/>
+ <translation>กระเป๋าเงินถูก &lt;b&gt;เข้ารหัส&lt;/b&gt; และในปัจจุบัน &lt;b&gt;ล็อค &lt;/b&gt;</translation>
</message>
<message>
<source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source>
@@ -797,11 +797,11 @@ Address: %4
<name>EditAddressDialog</name>
<message>
<source>Edit Address</source>
- <translation type="unfinished"/>
+ <translation>แก้ไขที่อยู่</translation>
</message>
<message>
<source>&amp;Label</source>
- <translation type="unfinished"/>
+ <translation>&amp;ชื่อ</translation>
</message>
<message>
<source>The label associated with this address list entry</source>
@@ -813,27 +813,27 @@ Address: %4
</message>
<message>
<source>&amp;Address</source>
- <translation type="unfinished"/>
+ <translation>&amp;ที่อยู่</translation>
</message>
<message>
<source>New receiving address</source>
- <translation type="unfinished"/>
+ <translation>ที่อยู่ผู้รับใหม่</translation>
</message>
<message>
<source>New sending address</source>
- <translation type="unfinished"/>
+ <translation>ที่อยู่ผู้ส่งใหม่</translation>
</message>
<message>
<source>Edit receiving address</source>
- <translation type="unfinished"/>
+ <translation>แก้ไขที่อยู่ผู้รับ</translation>
</message>
<message>
<source>Edit sending address</source>
- <translation type="unfinished"/>
+ <translation>แก้ไขที่อยู่ผู้ส่ง</translation>
</message>
<message>
<source>The entered address &quot;%1&quot; is already in the address book.</source>
- <translation type="unfinished"/>
+ <translation>ป้อนที่อยู่ &quot;%1&quot; ที่มีอยู่แล้วในสมุดที่อยู่</translation>
</message>
<message>
<source>The entered address &quot;%1&quot; is not a valid Bitcoin address.</source>
@@ -841,11 +841,11 @@ Address: %4
</message>
<message>
<source>Could not unlock wallet.</source>
- <translation type="unfinished"/>
+ <translation>ไม่สามารถปลดล็อคกระเป๋าเงิน</translation>
</message>
<message>
<source>New key generation failed.</source>
- <translation type="unfinished"/>
+ <translation>สร้างกุญแจใหม่ล้มเหลว</translation>
</message>
</context>
<context>
@@ -992,7 +992,7 @@ Address: %4
<name>OptionsDialog</name>
<message>
<source>Options</source>
- <translation type="unfinished"/>
+ <translation>ตัวเลือก</translation>
</message>
<message>
<source>&amp;Main</source>
@@ -1207,7 +1207,7 @@ Address: %4
<name>OverviewPage</name>
<message>
<source>Form</source>
- <translation type="unfinished"/>
+ <translation>รูป</translation>
</message>
<message>
<source>The displayed information may be out of date. Your wallet automatically synchronizes with the Bitcoin network after a connection is established, but this process has not completed yet.</source>
@@ -1251,7 +1251,7 @@ Address: %4
</message>
<message>
<source>&lt;b&gt;Recent transactions&lt;/b&gt;</source>
- <translation type="unfinished"/>
+ <translation>&lt;b&gt;รายการทำธุรกรรมล่าสุด&lt;/b&gt;</translation>
</message>
<message>
<source>out of sync</source>
@@ -1695,7 +1695,7 @@ Address: %4
<name>SendCoinsDialog</name>
<message>
<source>Send Coins</source>
- <translation type="unfinished"/>
+ <translation>ส่งเหรียญ</translation>
</message>
<message>
<source>Coin Control Features</source>
@@ -2127,7 +2127,7 @@ Address: %4
</message>
<message>
<source>[testnet]</source>
- <translation type="unfinished"/>
+ <translation>[testnet]</translation>
</message>
</context>
<context>
@@ -2494,7 +2494,7 @@ Address: %4
</message>
<message>
<source>Comma separated file (*.csv)</source>
- <translation type="unfinished"/>
+ <translation>คั่นไฟล์ด้วยเครื่องหมายจุลภาค (*.csv)</translation>
</message>
<message>
<source>Confirmed</source>
@@ -2544,7 +2544,7 @@ Address: %4
<name>WalletModel</name>
<message>
<source>Send Coins</source>
- <translation type="unfinished"/>
+ <translation>ส่งเหรียญ</translation>
</message>
</context>
<context>
diff --git a/src/qt/locale/bitcoin_zh_CN.ts b/src/qt/locale/bitcoin_zh_CN.ts
index ea98c4e4b1..b87d27fe12 100644
--- a/src/qt/locale/bitcoin_zh_CN.ts
+++ b/src/qt/locale/bitcoin_zh_CN.ts
@@ -917,7 +917,7 @@ Address: %4
</message>
<message>
<source>Set SSL root certificates for payment request (default: -system-)</source>
- <translation type="unfinished"/>
+ <translation>设置SSL根证书的付款请求(默认:-系统-)</translation>
</message>
<message>
<source>Show splash screen on startup (default: 1)</source>
@@ -1050,11 +1050,11 @@ Address: %4
</message>
<message>
<source>Third party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items. %s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |.</source>
- <translation type="unfinished"/>
+ <translation>出现在交易的选项卡的上下文菜单项的第三方网址 (例如:区块链接查询) 。 %s的URL被替换为交易哈希。多个的URL需要竖线 | 分隔。</translation>
</message>
<message>
<source>Third party transaction URLs</source>
- <translation type="unfinished"/>
+ <translation>第三方交易网址</translation>
</message>
<message>
<source>Active command-line options that override above options:</source>
@@ -1074,7 +1074,7 @@ Address: %4
</message>
<message>
<source>(0 = auto, &lt;0 = leave that many cores free)</source>
- <translation type="unfinished"/>
+ <translation>(0 = 自动, &lt;0 = 离开很多免费的核心)</translation>
</message>
<message>
<source>W&amp;allet</source>
@@ -1086,7 +1086,7 @@ Address: %4
</message>
<message>
<source>Enable coin &amp;control features</source>
- <translation type="unfinished"/>
+ <translation>启动货币 &amp;控制功能</translation>
</message>
<message>
<source>If you disable the spending of unconfirmed change, the change from a transaction cannot be used until that transaction has at least one confirmation. This also affects how your balance is computed.</source>
@@ -1094,7 +1094,7 @@ Address: %4
</message>
<message>
<source>&amp;Spend unconfirmed change</source>
- <translation type="unfinished"/>
+ <translation>&amp;选择未经确认的花费</translation>
</message>
<message>
<source>Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled.</source>
@@ -1351,7 +1351,7 @@ Address: %4
</message>
<message>
<source>Error: Cannot parse configuration file: %1. Only use key=value syntax.</source>
- <translation type="unfinished"/>
+ <translation>错误: 无法解析配置文件: %1. 只有钥匙=重要的私匙.</translation>
</message>
<message>
<source>Error: Invalid combination of -regtest and -testnet.</source>
@@ -1359,7 +1359,7 @@ Address: %4
</message>
<message>
<source>Bitcoin Core didn&apos;t yet exit safely...</source>
- <translation type="unfinished"/>
+ <translation>比特币核心钱包没有安全退出....</translation>
</message>
<message>
<source>Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</source>
@@ -2667,7 +2667,7 @@ Address: %4
</message>
<message>
<source>Bitcoin Core RPC client version</source>
- <translation type="unfinished"/>
+ <translation>比特币核心钱包RPC客户端版本</translation>
</message>
<message>
<source>Run in the background as a daemon and accept commands</source>
@@ -2722,7 +2722,7 @@ rpcpassword=%s
</message>
<message>
<source>Continuously rate-limit free transactions to &lt;n&gt;*1000 bytes per minute (default:15)</source>
- <translation type="unfinished"/>
+ <translation>自由交易不断的速率限制为&lt;n&gt;*1000 字节每分钟(默认值:15)</translation>
</message>
<message>
<source>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.</source>
@@ -2734,7 +2734,7 @@ rpcpassword=%s
</message>
<message>
<source>Error: Listening for incoming connections failed (listen returned error %d)</source>
- <translation type="unfinished"/>
+ <translation>错误: 监听接收连接失败 (监听错误 %d)</translation>
</message>
<message>
<source>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.</source>
@@ -2750,27 +2750,27 @@ rpcpassword=%s
</message>
<message>
<source>Fees smaller than this are considered zero fee (for transaction creation) (default:</source>
- <translation type="unfinished"/>
+ <translation>比这手续费更小的被认为零手续费 (交易产生) (默认:</translation>
</message>
<message>
<source>Flush database activity from memory pool to disk log every &lt;n&gt; megabytes (default: 100)</source>
- <translation type="unfinished"/>
+ <translation>从缓冲池清理磁盘数据库活动日志每&lt;n&gt;兆字节 (默认值: 100)</translation>
</message>
<message>
<source>How thorough the block verification of -checkblocks is (0-4, default: 3)</source>
- <translation type="unfinished"/>
+ <translation>如何有效的验证checkblocks区块(0-4, 默认值: 3)</translation>
</message>
<message>
<source>In this mode -genproclimit controls how many blocks are generated immediately.</source>
- <translation type="unfinished"/>
+ <translation>在-genproclimit这种模式下控制产出多少区块</translation>
</message>
<message>
<source>Set the number of script verification threads (%u to %d, 0 = auto, &lt;0 = leave that many cores free, default: %d)</source>
- <translation type="unfinished"/>
+ <translation>设置脚本验证的程序 (%u 到 %d, 0 = 自动, &lt;0 = 保留自由的核心, 默认值: %d)</translation>
</message>
<message>
<source>Set the processor limit for when generation is on (-1 = unlimited, default: -1)</source>
- <translation type="unfinished"/>
+ <translation>设置处理器生成的限制 (-1 = 无限, 默认值: -1)</translation>
</message>
<message>
<source>This is a pre-release test build - use at your own risk - do not use for mining or merchant applications</source>
@@ -2778,7 +2778,7 @@ rpcpassword=%s
</message>
<message>
<source>Unable to bind to %s on this computer. Bitcoin Core is probably already running.</source>
- <translation type="unfinished"/>
+ <translation>无法 %s的绑定到电脑上,比特币核心钱包可能已经在运行。</translation>
</message>
<message>
<source>Use separate SOCKS5 proxy to reach peers via Tor hidden services (default: -proxy)</source>
@@ -2810,11 +2810,11 @@ rpcpassword=%s
</message>
<message>
<source>(default: 1)</source>
- <translation type="unfinished"/>
+ <translation>(默认值: 1)</translation>
</message>
<message>
<source>(default: wallet.dat)</source>
- <translation type="unfinished"/>
+ <translation>(默认: wallet.dat)</translation>
</message>
<message>
<source>&lt;category&gt; can be:</source>
@@ -2850,7 +2850,7 @@ rpcpassword=%s
</message>
<message>
<source>Connection options:</source>
- <translation type="unfinished"/>
+ <translation>连接选项:</translation>
</message>
<message>
<source>Corrupted block database detected</source>
@@ -2858,11 +2858,11 @@ rpcpassword=%s
</message>
<message>
<source>Debugging/Testing options:</source>
- <translation type="unfinished"/>
+ <translation>调试/测试选项:</translation>
</message>
<message>
<source>Disable safemode, override a real safe mode event (default: 0)</source>
- <translation type="unfinished"/>
+ <translation>禁止使用安全模式,重新写入一个真正的安全模式日志(默认值: 0)</translation>
</message>
<message>
<source>Discover own IP address (default: 1 when listening and no -externalip)</source>
@@ -2954,7 +2954,7 @@ rpcpassword=%s
</message>
<message>
<source>Fees smaller than this are considered zero fee (for relaying) (default:</source>
- <translation type="unfinished"/>
+ <translation>比这手续费更小的被认为零手续费 (中继) (默认值: </translation>
</message>
<message>
<source>Find peers using DNS lookup (default: 1 unless -connect)</source>
@@ -2962,7 +2962,7 @@ rpcpassword=%s
</message>
<message>
<source>Force safe mode (default: 0)</source>
- <translation type="unfinished"/>
+ <translation>强制安全模式(默认值: 0)</translation>
</message>
<message>
<source>Generate coins (default: 0)</source>
@@ -3010,7 +3010,7 @@ rpcpassword=%s
</message>
<message>
<source>Set database cache size in megabytes (%d to %d, default: %d)</source>
- <translation type="unfinished"/>
+ <translation>设置以MB为单位的数据库缓存大小(%d 到 %d, 默认值: %d)</translation>
</message>
<message>
<source>Set maximum block size in bytes (default: %d)</source>
@@ -3070,7 +3070,7 @@ rpcpassword=%s
</message>
<message>
<source>Cannot obtain a lock on data directory %s. Bitcoin Core is probably already running.</source>
- <translation type="unfinished"/>
+ <translation>无法获取数据目录的 %s. 比特币核心钱包可能已经在运行.</translation>
</message>
<message>
<source>Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message)</source>
@@ -3098,11 +3098,11 @@ rpcpassword=%s
</message>
<message>
<source>Limit size of signature cache to &lt;n&gt; entries (default: 50000)</source>
- <translation type="unfinished"/>
+ <translation>签名缓冲大小限制每&lt;n&gt; 条目 (默认值: 50000)</translation>
</message>
<message>
<source>Log transaction priority and fee per kB when mining blocks (default: 0)</source>
- <translation type="unfinished"/>
+ <translation>开采区块时,日志优先级和手续费每KB (默认值: 0)</translation>
</message>
<message>
<source>Maintain a full transaction index (default: 0)</source>
@@ -3126,15 +3126,15 @@ rpcpassword=%s
</message>
<message>
<source>Print block on startup, if found in block index</source>
- <translation type="unfinished"/>
+ <translation>如果在搜索区块中找到,请启动打印区块</translation>
</message>
<message>
<source>Print block tree on startup (default: 0)</source>
- <translation>启动时打印块树 (默认: 0)</translation>
+ <translation>启动时打印区块树 (默认值: 0)</translation>
</message>
<message>
<source>RPC SSL options: (see the Bitcoin Wiki for SSL setup instructions)</source>
- <translation type="unfinished"/>
+ <translation>RPC SSL选项:(见有关比特币设置用于SSL说明的维基百科)</translation>
</message>
<message>
<source>RPC server options:</source>
@@ -3142,15 +3142,15 @@ rpcpassword=%s
</message>
<message>
<source>Randomly drop 1 of every &lt;n&gt; network messages</source>
- <translation type="unfinished"/>
+ <translation>随机每1个丢失测试&lt;n&gt;网络信息</translation>
</message>
<message>
<source>Randomly fuzz 1 of every &lt;n&gt; network messages</source>
- <translation type="unfinished"/>
+ <translation>随机每1个模拟测试&lt;n&gt;网络信息</translation>
</message>
<message>
<source>Run a thread to flush wallet periodically (default: 1)</source>
- <translation type="unfinished"/>
+ <translation>运行一个程序,定时清理钱包 (默认值:1)</translation>
</message>
<message>
<source>SSL options: (see the Bitcoin Wiki for SSL setup instructions)</source>
@@ -3158,7 +3158,7 @@ rpcpassword=%s
</message>
<message>
<source>Send command to Bitcoin Core</source>
- <translation type="unfinished"/>
+ <translation>发送指令到比特币核心钱包</translation>
</message>
<message>
<source>Send trace/debug info to console instead of debug.log file</source>
@@ -3170,15 +3170,15 @@ rpcpassword=%s
</message>
<message>
<source>Sets the DB_PRIVATE flag in the wallet db environment (default: 1)</source>
- <translation type="unfinished"/>
+ <translation>设置DB_PRIVATE钱包标志DB环境 (默认值: 1)</translation>
</message>
<message>
<source>Show all debugging options (usage: --help -help-debug)</source>
- <translation type="unfinished"/>
+ <translation>显示所有调试选项 (用法: --帮助 -帮助调试)</translation>
</message>
<message>
<source>Show benchmark information (default: 0)</source>
- <translation type="unfinished"/>
+ <translation>显示标准信息 (默认值: 0)</translation>
</message>
<message>
<source>Shrink debug.log file on client startup (default: 1 when no -debug)</source>
@@ -3194,7 +3194,7 @@ rpcpassword=%s
</message>
<message>
<source>Start Bitcoin Core Daemon</source>
- <translation type="unfinished"/>
+ <translation>开启比特币核心钱包守护进程</translation>
</message>
<message>
<source>System error: </source>
@@ -3238,7 +3238,7 @@ rpcpassword=%s
</message>
<message>
<source>on startup</source>
- <translation type="unfinished"/>
+ <translation>启动中</translation>
</message>
<message>
<source>version</source>
diff --git a/src/qt/macdockiconhandler.mm b/src/qt/macdockiconhandler.mm
index 64291c9188..74fb64ace3 100644
--- a/src/qt/macdockiconhandler.mm
+++ b/src/qt/macdockiconhandler.mm
@@ -62,6 +62,8 @@ MacDockIconHandler::MacDockIconHandler() : QObject()
this->setMainWindow(NULL);
#if QT_VERSION < 0x050000
qt_mac_set_dock_menu(this->m_dockMenu);
+#elif QT_VERSION >= 0x050200
+ this->m_dockMenu->setAsDockMenu();
#endif
[pool release];
}
diff --git a/src/qt/notificator.cpp b/src/qt/notificator.cpp
index 38a029dbe5..3d588cd317 100644
--- a/src/qt/notificator.cpp
+++ b/src/qt/notificator.cpp
@@ -28,8 +28,10 @@
#endif
+#ifdef USE_DBUS
// https://wiki.ubuntu.com/NotificationDevelopmentGuidelines recommends at least 128
const int FREEDESKTOP_NOTIFICATION_ICON_SIZE = 128;
+#endif
Notificator::Notificator(const QString &programName, QSystemTrayIcon *trayicon, QWidget *parent) :
QObject(parent),
diff --git a/src/qt/notificator.h b/src/qt/notificator.h
index abab986992..3395e64350 100644
--- a/src/qt/notificator.h
+++ b/src/qt/notificator.h
@@ -6,7 +6,7 @@
#define NOTIFICATOR_H
#if defined(HAVE_CONFIG_H)
-#include "bitcoin-config.h"
+#include "config/bitcoin-config.h"
#endif
#include <QIcon>
diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp
index 96464d2cc0..597be40abd 100644
--- a/src/qt/optionsdialog.cpp
+++ b/src/qt/optionsdialog.cpp
@@ -3,7 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#if defined(HAVE_CONFIG_H)
-#include "bitcoin-config.h"
+#include "config/bitcoin-config.h"
#endif
#include "optionsdialog.h"
@@ -14,7 +14,10 @@
#include "monitoreddatamapper.h"
#include "optionsmodel.h"
-#include "main.h" // for CTransaction::nMinTxFee and MAX_SCRIPTCHECK_THREADS
+#include "main.h" // for MAX_SCRIPTCHECK_THREADS
+#ifdef ENABLE_WALLET
+#include "wallet.h" // for CWallet::minTxFee
+#endif
#include "netbase.h"
#include "txdb.h" // for -dbcache defaults
@@ -49,15 +52,8 @@ OptionsDialog::OptionsDialog(QWidget *parent) :
ui->proxyPort->setEnabled(false);
ui->proxyPort->setValidator(new QIntValidator(1, 65535, this));
- /** SOCKS version is only selectable for default proxy and is always 5 for IPv6 and Tor */
- ui->socksVersion->setEnabled(false);
- ui->socksVersion->addItem("5", 5);
- ui->socksVersion->addItem("4", 4);
- ui->socksVersion->setCurrentIndex(0);
-
connect(ui->connectSocks, SIGNAL(toggled(bool)), ui->proxyIp, SLOT(setEnabled(bool)));
connect(ui->connectSocks, SIGNAL(toggled(bool)), ui->proxyPort, SLOT(setEnabled(bool)));
- connect(ui->connectSocks, SIGNAL(toggled(bool)), ui->socksVersion, SLOT(setEnabled(bool)));
ui->proxyIp->installEventFilter(this);
@@ -101,7 +97,9 @@ OptionsDialog::OptionsDialog(QWidget *parent) :
#endif
ui->unit->setModel(new BitcoinUnits(this));
- ui->transactionFee->setSingleStep(CTransaction::nMinTxFee);
+#ifdef ENABLE_WALLET
+ ui->transactionFee->setSingleStep(CWallet::minTxFee.GetFeePerK());
+#endif
/* Widget-to-option mapper */
mapper = new MonitoredDataMapper(this);
@@ -151,6 +149,7 @@ void OptionsDialog::setModel(OptionsModel *model)
/* Wallet */
connect(ui->spendZeroConfChange, SIGNAL(clicked(bool)), this, SLOT(showRestartWarning()));
/* Network */
+ connect(ui->allowIncoming, SIGNAL(clicked(bool)), this, SLOT(showRestartWarning()));
connect(ui->connectSocks, SIGNAL(clicked(bool)), this, SLOT(showRestartWarning()));
/* Display */
connect(ui->lang, SIGNAL(valueChanged()), this, SLOT(showRestartWarning()));
@@ -171,11 +170,11 @@ void OptionsDialog::setMapper()
/* Network */
mapper->addMapping(ui->mapPortUpnp, OptionsModel::MapPortUPnP);
+ mapper->addMapping(ui->allowIncoming, OptionsModel::Listen);
mapper->addMapping(ui->connectSocks, OptionsModel::ProxyUse);
mapper->addMapping(ui->proxyIp, OptionsModel::ProxyIP);
mapper->addMapping(ui->proxyPort, OptionsModel::ProxyPort);
- mapper->addMapping(ui->socksVersion, OptionsModel::ProxySocksVersion);
/* Window */
#ifndef Q_OS_MAC
diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp
index e87a1d97e7..f07e66bf04 100644
--- a/src/qt/optionsmodel.cpp
+++ b/src/qt/optionsmodel.cpp
@@ -3,7 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#if defined(HAVE_CONFIG_H)
-#include "bitcoin-config.h"
+#include "config/bitcoin-config.h"
#endif
#include "optionsmodel.h"
@@ -94,7 +94,7 @@ void OptionsModel::Init()
#ifdef ENABLE_WALLET
if (!settings.contains("nTransactionFee"))
settings.setValue("nTransactionFee", (qint64)DEFAULT_TRANSACTION_FEE);
- nTransactionFee = settings.value("nTransactionFee").toLongLong(); // if -paytxfee is set, this will be overridden later in init.cpp
+ payTxFee = CFeeRate(settings.value("nTransactionFee").toLongLong()); // if -paytxfee is set, this will be overridden later in init.cpp
if (mapArgs.count("-paytxfee"))
addOverriddenOption("-paytxfee");
@@ -106,14 +106,15 @@ void OptionsModel::Init()
// Network
if (!settings.contains("fUseUPnP"))
-#ifdef USE_UPNP
- settings.setValue("fUseUPnP", true);
-#else
- settings.setValue("fUseUPnP", false);
-#endif
+ settings.setValue("fUseUPnP", DEFAULT_UPNP);
if (!SoftSetBoolArg("-upnp", settings.value("fUseUPnP").toBool()))
addOverriddenOption("-upnp");
+ if (!settings.contains("fListen"))
+ settings.setValue("fListen", DEFAULT_LISTEN);
+ if (!SoftSetBoolArg("-listen", settings.value("fListen").toBool()))
+ addOverriddenOption("-listen");
+
if (!settings.contains("fUseProxy"))
settings.setValue("fUseProxy", false);
if (!settings.contains("addrProxy"))
@@ -121,11 +122,6 @@ void OptionsModel::Init()
// Only try to set -proxy, if user has enabled fUseProxy
if (settings.value("fUseProxy").toBool() && !SoftSetArg("-proxy", settings.value("addrProxy").toString().toStdString()))
addOverriddenOption("-proxy");
- if (!settings.contains("nSocksVersion"))
- settings.setValue("nSocksVersion", 5);
- // Only try to set -socks, if user has enabled fUseProxy
- if (settings.value("fUseProxy").toBool() && !SoftSetArg("-socks", settings.value("nSocksVersion").toString().toStdString()))
- addOverriddenOption("-socks");
// Display
if (!settings.contains("language"))
@@ -187,19 +183,18 @@ QVariant OptionsModel::data(const QModelIndex & index, int role) const
QStringList strlIpPort = settings.value("addrProxy").toString().split(":", QString::SkipEmptyParts);
return strlIpPort.at(1);
}
- case ProxySocksVersion:
- return settings.value("nSocksVersion", 5);
#ifdef ENABLE_WALLET
- case Fee:
- // Attention: Init() is called before nTransactionFee is set in AppInit2()!
+ case Fee: {
+ // Attention: Init() is called before payTxFee is set in AppInit2()!
// To ensure we can change the fee on-the-fly update our QSetting when
// opening OptionsDialog, which queries Fee via the mapper.
- if (nTransactionFee != settings.value("nTransactionFee").toLongLong())
- settings.setValue("nTransactionFee", (qint64)nTransactionFee);
- // Todo: Consider to revert back to use just nTransactionFee here, if we don't want
+ if (!(payTxFee == CFeeRate(settings.value("nTransactionFee").toLongLong(), 1000)))
+ settings.setValue("nTransactionFee", (qint64)payTxFee.GetFeePerK());
+ // Todo: Consider to revert back to use just payTxFee here, if we don't want
// -paytxfee to update our QSettings!
return settings.value("nTransactionFee");
+ }
case SpendZeroConfChange:
return settings.value("bSpendZeroConfChange");
#endif
@@ -217,6 +212,8 @@ QVariant OptionsModel::data(const QModelIndex & index, int role) const
return settings.value("nDatabaseCache");
case ThreadsScriptVerif:
return settings.value("nThreadsScriptVerif");
+ case Listen:
+ return settings.value("fListen");
default:
return QVariant();
}
@@ -280,20 +277,15 @@ bool OptionsModel::setData(const QModelIndex & index, const QVariant & value, in
}
}
break;
- case ProxySocksVersion: {
- if (settings.value("nSocksVersion") != value) {
- settings.setValue("nSocksVersion", value.toInt());
- setRestartRequired(true);
- }
- }
- break;
#ifdef ENABLE_WALLET
- case Fee: // core option - can be changed on-the-fly
+ case Fee: { // core option - can be changed on-the-fly
// Todo: Add is valid check and warn via message, if not
- nTransactionFee = value.toLongLong();
- settings.setValue("nTransactionFee", (qint64)nTransactionFee);
+ qint64 nTransactionFee = value.toLongLong();
+ payTxFee = CFeeRate(nTransactionFee, 1000);
+ settings.setValue("nTransactionFee", nTransactionFee);
emit transactionFeeChanged(nTransactionFee);
break;
+ }
case SpendZeroConfChange:
if (settings.value("bSpendZeroConfChange") != value) {
settings.setValue("bSpendZeroConfChange", value);
@@ -302,9 +294,7 @@ bool OptionsModel::setData(const QModelIndex & index, const QVariant & value, in
break;
#endif
case DisplayUnit:
- nDisplayUnit = value.toInt();
- settings.setValue("nDisplayUnit", nDisplayUnit);
- emit displayUnitChanged(nDisplayUnit);
+ setDisplayUnit(value);
break;
case DisplayAddresses:
bDisplayAddresses = value.toBool();
@@ -340,35 +330,50 @@ bool OptionsModel::setData(const QModelIndex & index, const QVariant & value, in
setRestartRequired(true);
}
break;
+ case Listen:
+ if (settings.value("fListen") != value) {
+ settings.setValue("fListen", value);
+ setRestartRequired(true);
+ }
+ break;
default:
break;
}
}
+
emit dataChanged(index, index);
return successful;
}
+/** Updates current unit in memory, settings and emits displayUnitChanged(newUnit) signal */
+void OptionsModel::setDisplayUnit(const QVariant &value)
+{
+ if (!value.isNull())
+ {
+ QSettings settings;
+ nDisplayUnit = value.toInt();
+ settings.setValue("nDisplayUnit", nDisplayUnit);
+ emit displayUnitChanged(nDisplayUnit);
+ }
+}
+
bool OptionsModel::getProxySettings(QNetworkProxy& proxy) const
{
// Directly query current base proxy, because
// GUI settings can be overridden with -proxy.
proxyType curProxy;
if (GetProxy(NET_IPV4, curProxy)) {
- if (curProxy.second == 5) {
- proxy.setType(QNetworkProxy::Socks5Proxy);
- proxy.setHostName(QString::fromStdString(curProxy.first.ToStringIP()));
- proxy.setPort(curProxy.first.GetPort());
+ proxy.setType(QNetworkProxy::Socks5Proxy);
+ proxy.setHostName(QString::fromStdString(curProxy.ToStringIP()));
+ proxy.setPort(curProxy.GetPort());
- return true;
- }
- else
- return false;
+ return true;
}
else
proxy.setType(QNetworkProxy::NoProxy);
- return true;
+ return false;
}
void OptionsModel::setRestartRequired(bool fRequired)
diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h
index f05e3e92de..89c2ec7453 100644
--- a/src/qt/optionsmodel.h
+++ b/src/qt/optionsmodel.h
@@ -42,6 +42,7 @@ public:
ThreadsScriptVerif, // int
DatabaseCache, // int
SpendZeroConfChange, // bool
+ Listen, // bool
OptionIDRowCount,
};
@@ -51,6 +52,8 @@ public:
int rowCount(const QModelIndex & parent = QModelIndex()) const;
QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const;
bool setData(const QModelIndex & index, const QVariant & value, int role = Qt::EditRole);
+ /** Updates current unit in memory, settings and emits displayUnitChanged(newUnit) signal */
+ void setDisplayUnit(const QVariant &value);
/* Explicit getters */
bool getMinimizeToTray() { return fMinimizeToTray; }
diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp
index 1a9d1de571..1278f368cf 100644
--- a/src/qt/overviewpage.cpp
+++ b/src/qt/overviewpage.cpp
@@ -103,6 +103,9 @@ OverviewPage::OverviewPage(QWidget *parent) :
currentBalance(-1),
currentUnconfirmedBalance(-1),
currentImmatureBalance(-1),
+ currentWatchOnlyBalance(-1),
+ currentWatchUnconfBalance(-1),
+ currentWatchImmatureBalance(-1),
txdelegate(new TxViewDelegate()),
filter(0)
{
@@ -135,22 +138,39 @@ OverviewPage::~OverviewPage()
delete ui;
}
-void OverviewPage::setBalance(qint64 balance, qint64 unconfirmedBalance, qint64 immatureBalance)
+void OverviewPage::setBalance(qint64 balance, qint64 unconfirmedBalance, qint64 immatureBalance, qint64 watchOnlyBalance, qint64 watchUnconfBalance, qint64 watchImmatureBalance)
{
int unit = walletModel->getOptionsModel()->getDisplayUnit();
currentBalance = balance;
currentUnconfirmedBalance = unconfirmedBalance;
currentImmatureBalance = immatureBalance;
+ currentWatchOnlyBalance = watchOnlyBalance;
+ currentWatchUnconfBalance = watchUnconfBalance;
+ currentWatchImmatureBalance = watchImmatureBalance;
ui->labelBalance->setText(BitcoinUnits::formatWithUnit(unit, balance));
ui->labelUnconfirmed->setText(BitcoinUnits::formatWithUnit(unit, unconfirmedBalance));
ui->labelImmature->setText(BitcoinUnits::formatWithUnit(unit, immatureBalance));
ui->labelTotal->setText(BitcoinUnits::formatWithUnit(unit, balance + unconfirmedBalance + immatureBalance));
+ ui->labelWatchAvailable->setText(BitcoinUnits::formatWithUnit(unit, watchOnlyBalance));
+ ui->labelWatchPending->setText(BitcoinUnits::formatWithUnit(unit, watchUnconfBalance));
+ ui->labelWatchImmature->setText(BitcoinUnits::formatWithUnit(unit, watchImmatureBalance));
+ ui->labelWatchTotal->setText(BitcoinUnits::formatWithUnit(unit, watchOnlyBalance + watchUnconfBalance + watchImmatureBalance));
// only show immature (newly mined) balance if it's non-zero, so as not to complicate things
// for the non-mining users
bool showImmature = immatureBalance != 0;
- ui->labelImmature->setVisible(showImmature);
- ui->labelImmatureText->setVisible(showImmature);
+ bool showWatchOnlyImmature = watchImmatureBalance != 0;
+ bool showWatchOnly = (watchOnlyBalance != 0 || watchUnconfBalance != 0 || showWatchOnlyImmature);
+
+ // for symmetry reasons also show immature label when the watchonly one is shown
+ ui->labelImmature->setVisible(showImmature || showWatchOnlyImmature);
+ ui->labelImmatureText->setVisible(showImmature || showWatchOnlyImmature);
+ ui->labelWatchonly->setVisible(showWatchOnly); // show Watchonly label
+ ui->lineWatchBalance->setVisible(showWatchOnly); // show watchonly balance separator line
+ ui->labelWatchAvailable->setVisible(showWatchOnly); // show watchonly available balance
+ ui->labelWatchImmature->setVisible(showWatchOnlyImmature); // show watchonly immature balance
+ ui->labelWatchPending->setVisible(showWatchOnly); // show watchonly pending balance
+ ui->labelWatchTotal->setVisible(showWatchOnly); // show watchonly total balance
}
void OverviewPage::setClientModel(ClientModel *model)
@@ -182,8 +202,9 @@ void OverviewPage::setWalletModel(WalletModel *model)
ui->listTransactions->setModelColumn(TransactionTableModel::ToAddress);
// Keep up to date with wallet
- setBalance(model->getBalance(), model->getUnconfirmedBalance(), model->getImmatureBalance());
- connect(model, SIGNAL(balanceChanged(qint64, qint64, qint64)), this, SLOT(setBalance(qint64, qint64, qint64)));
+ setBalance(model->getBalance(), model->getUnconfirmedBalance(), model->getImmatureBalance(),
+ model->getWatchBalance(), model->getWatchUnconfirmedBalance(), model->getWatchImmatureBalance());
+ connect(model, SIGNAL(balanceChanged(qint64, qint64, qint64, qint64, qint64, qint64)), this, SLOT(setBalance(qint64, qint64, qint64, qint64, qint64, qint64)));
connect(model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit()));
}
@@ -197,7 +218,8 @@ void OverviewPage::updateDisplayUnit()
if(walletModel && walletModel->getOptionsModel())
{
if(currentBalance != -1)
- setBalance(currentBalance, currentUnconfirmedBalance, currentImmatureBalance);
+ setBalance(currentBalance, currentUnconfirmedBalance, currentImmatureBalance,
+ currentWatchOnlyBalance, currentWatchUnconfBalance, currentWatchImmatureBalance);
// Update txdelegate->unit with the current unit
txdelegate->unit = walletModel->getOptionsModel()->getDisplayUnit();
diff --git a/src/qt/overviewpage.h b/src/qt/overviewpage.h
index 2507a3fb31..fe00106770 100644
--- a/src/qt/overviewpage.h
+++ b/src/qt/overviewpage.h
@@ -34,7 +34,8 @@ public:
void showOutOfSyncWarning(bool fShow);
public slots:
- void setBalance(qint64 balance, qint64 unconfirmedBalance, qint64 immatureBalance);
+ void setBalance(qint64 balance, qint64 unconfirmedBalance, qint64 immatureBalance,
+ qint64 watchOnlyBalance, qint64 watchUnconfBalance, qint64 watchImmatureBalance);
signals:
void transactionClicked(const QModelIndex &index);
@@ -46,6 +47,9 @@ private:
qint64 currentBalance;
qint64 currentUnconfirmedBalance;
qint64 currentImmatureBalance;
+ qint64 currentWatchOnlyBalance;
+ qint64 currentWatchUnconfBalance;
+ qint64 currentWatchImmatureBalance;
TxViewDelegate *txdelegate;
TransactionFilterProxy *filter;
diff --git a/src/qt/paymentrequestplus.cpp b/src/qt/paymentrequestplus.cpp
index e369734a98..acce42e203 100644
--- a/src/qt/paymentrequestplus.cpp
+++ b/src/qt/paymentrequestplus.cpp
@@ -17,6 +17,7 @@
#include <QDebug>
#include <QSslCertificate>
+using namespace std;
class SSLVerifyError : public std::runtime_error
{
@@ -28,18 +29,18 @@ bool PaymentRequestPlus::parse(const QByteArray& data)
{
bool parseOK = paymentRequest.ParseFromArray(data.data(), data.size());
if (!parseOK) {
- qDebug() << "PaymentRequestPlus::parse : Error parsing payment request";
+ qWarning() << "PaymentRequestPlus::parse : Error parsing payment request";
return false;
}
if (paymentRequest.payment_details_version() > 1) {
- qDebug() << "PaymentRequestPlus::parse : Received up-version payment details, version=" << paymentRequest.payment_details_version();
+ qWarning() << "PaymentRequestPlus::parse : Received up-version payment details, version=" << paymentRequest.payment_details_version();
return false;
}
parseOK = details.ParseFromString(paymentRequest.serialized_payment_details());
if (!parseOK)
{
- qDebug() << "PaymentRequestPlus::parse : Error parsing payment details";
+ qWarning() << "PaymentRequestPlus::parse : Error parsing payment details";
paymentRequest.Clear();
return false;
}
@@ -79,17 +80,17 @@ bool PaymentRequestPlus::getMerchant(X509_STORE* certStore, QString& merchant) c
digestAlgorithm = EVP_sha1();
}
else if (paymentRequest.pki_type() == "none") {
- qDebug() << "PaymentRequestPlus::getMerchant : Payment request: pki_type == none";
+ qWarning() << "PaymentRequestPlus::getMerchant : Payment request: pki_type == none";
return false;
}
else {
- qDebug() << "PaymentRequestPlus::getMerchant : Payment request: unknown pki_type " << QString::fromStdString(paymentRequest.pki_type());
+ qWarning() << "PaymentRequestPlus::getMerchant : Payment request: unknown pki_type " << QString::fromStdString(paymentRequest.pki_type());
return false;
}
payments::X509Certificates certChain;
if (!certChain.ParseFromString(paymentRequest.pki_data())) {
- qDebug() << "PaymentRequestPlus::getMerchant : Payment request: error parsing pki_data";
+ qWarning() << "PaymentRequestPlus::getMerchant : Payment request: error parsing pki_data";
return false;
}
@@ -99,12 +100,12 @@ bool PaymentRequestPlus::getMerchant(X509_STORE* certStore, QString& merchant) c
QByteArray certData(certChain.certificate(i).data(), certChain.certificate(i).size());
QSslCertificate qCert(certData, QSsl::Der);
if (currentTime < qCert.effectiveDate() || currentTime > qCert.expiryDate()) {
- qDebug() << "PaymentRequestPlus::getMerchant : Payment request: certificate expired or not yet active: " << qCert;
+ qWarning() << "PaymentRequestPlus::getMerchant : Payment request: certificate expired or not yet active: " << qCert;
return false;
}
#if QT_VERSION >= 0x050000
if (qCert.isBlacklisted()) {
- qDebug() << "PaymentRequestPlus::getMerchant : Payment request: certificate blacklisted: " << qCert;
+ qWarning() << "PaymentRequestPlus::getMerchant : Payment request: certificate blacklisted: " << qCert;
return false;
}
#endif
@@ -114,7 +115,7 @@ bool PaymentRequestPlus::getMerchant(X509_STORE* certStore, QString& merchant) c
certs.push_back(cert);
}
if (certs.empty()) {
- qDebug() << "PaymentRequestPlus::getMerchant : Payment request: empty certificate chain";
+ qWarning() << "PaymentRequestPlus::getMerchant : Payment request: empty certificate chain";
return false;
}
@@ -130,7 +131,7 @@ bool PaymentRequestPlus::getMerchant(X509_STORE* certStore, QString& merchant) c
// load the signing cert into it and verify.
X509_STORE_CTX *store_ctx = X509_STORE_CTX_new();
if (!store_ctx) {
- qDebug() << "PaymentRequestPlus::getMerchant : Payment request: error creating X509_STORE_CTX";
+ qWarning() << "PaymentRequestPlus::getMerchant : Payment request: error creating X509_STORE_CTX";
return false;
}
@@ -182,7 +183,7 @@ bool PaymentRequestPlus::getMerchant(X509_STORE* certStore, QString& merchant) c
catch (SSLVerifyError& err)
{
fResult = false;
- qDebug() << "PaymentRequestPlus::getMerchant : SSL error: " << err.what();
+ qWarning() << "PaymentRequestPlus::getMerchant : SSL error: " << err.what();
}
if (website)
diff --git a/src/qt/paymentrequestplus.h b/src/qt/paymentrequestplus.h
index 8c126b1fad..3c4861a4d4 100644
--- a/src/qt/paymentrequestplus.h
+++ b/src/qt/paymentrequestplus.h
@@ -24,7 +24,7 @@ public:
PaymentRequestPlus() { }
bool parse(const QByteArray& data);
- bool SerializeToString(string* output) const;
+ bool SerializeToString(std::string* output) const;
bool IsInitialized() const;
QString getPKIType() const;
diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp
index ca6ae17990..5471625a67 100644
--- a/src/qt/paymentserver.cpp
+++ b/src/qt/paymentserver.cpp
@@ -44,6 +44,7 @@
#include <QUrlQuery>
#endif
+using namespace std;
using namespace boost;
const int BITCOIN_IPC_CONNECT_TIMEOUT = 1000; // milliseconds
@@ -89,7 +90,7 @@ static QList<QString> savedPaymentRequests;
static void ReportInvalidCertificate(const QSslCertificate& cert)
{
- qDebug() << "ReportInvalidCertificate : Payment server found an invalid certificate: " << cert.subjectInfo(QSslCertificate::CommonName);
+ qWarning() << "ReportInvalidCertificate : Payment server found an invalid certificate: " << cert.subjectInfo(QSslCertificate::CommonName);
}
//
@@ -160,7 +161,7 @@ void PaymentServer::LoadRootCAs(X509_STORE* _store)
continue;
}
}
- qDebug() << "PaymentServer::LoadRootCAs : Loaded " << nRootCerts << " root certificates";
+ qWarning() << "PaymentServer::LoadRootCAs : Loaded " << nRootCerts << " root certificates";
// Project for another day:
// Fetch certificate revocation lists, and add them to certStore.
@@ -178,6 +179,9 @@ void PaymentServer::LoadRootCAs(X509_STORE* _store)
// and the items in savedPaymentRequest will be handled
// when uiReady() is called.
//
+// Warning: ipcSendCommandLine() is called early in init,
+// so don't use "emit message()", but "QMessageBox::"!
+//
bool PaymentServer::ipcParseCommandLine(int argc, char* argv[])
{
for (int i = 1; i < argc; i++)
@@ -191,14 +195,14 @@ bool PaymentServer::ipcParseCommandLine(int argc, char* argv[])
savedPaymentRequests.append(arg);
SendCoinsRecipient r;
- if (GUIUtil::parseBitcoinURI(arg, &r))
+ if (GUIUtil::parseBitcoinURI(arg, &r) && !r.address.isEmpty())
{
CBitcoinAddress address(r.address.toStdString());
- SelectParams(CChainParams::MAIN);
+ SelectParams(CBaseChainParams::MAIN);
if (!address.IsValid())
{
- SelectParams(CChainParams::TESTNET);
+ SelectParams(CBaseChainParams::TESTNET);
}
}
}
@@ -210,16 +214,16 @@ bool PaymentServer::ipcParseCommandLine(int argc, char* argv[])
if (readPaymentRequest(arg, request))
{
if (request.getDetails().network() == "main")
- SelectParams(CChainParams::MAIN);
+ SelectParams(CBaseChainParams::MAIN);
else
- SelectParams(CChainParams::TESTNET);
+ SelectParams(CBaseChainParams::TESTNET);
}
}
else
{
// Printing to debug.log is about the best we can do here, the
// GUI hasn't started yet so we can't pop up a message box.
- qDebug() << "PaymentServer::ipcSendCommandLine : Payment request file does not exist: " << arg;
+ qWarning() << "PaymentServer::ipcSendCommandLine : Payment request file does not exist: " << arg;
}
}
return true;
@@ -337,20 +341,14 @@ void PaymentServer::initNetManager()
QNetworkProxy proxy;
- // Query active proxy (fails if no SOCKS5 proxy)
+ // Query active SOCKS5 proxy
if (optionsModel->getProxySettings(proxy)) {
- if (proxy.type() == QNetworkProxy::Socks5Proxy) {
- netManager->setProxy(proxy);
+ netManager->setProxy(proxy);
- qDebug() << "PaymentServer::initNetManager : Using SOCKS5 proxy" << proxy.hostName() << ":" << proxy.port();
- }
- else
- qDebug() << "PaymentServer::initNetManager : No active proxy server found.";
+ qDebug() << "PaymentServer::initNetManager : Using SOCKS5 proxy" << proxy.hostName() << ":" << proxy.port();
}
else
- emit message(tr("Net manager warning"),
- tr("Your active proxy doesn't support SOCKS5, which is required for payment requests via proxy."),
- CClientUIInterface::MSG_WARNING);
+ qDebug() << "PaymentServer::initNetManager : No active proxy server found.";
connect(netManager, SIGNAL(finished(QNetworkReply*)),
this, SLOT(netRequestFinished(QNetworkReply*)));
@@ -399,7 +397,7 @@ void PaymentServer::handleURIOrFile(const QString& s)
}
else
{
- qDebug() << "PaymentServer::handleURIOrFile : Invalid URL: " << fetchUrl;
+ qWarning() << "PaymentServer::handleURIOrFile : Invalid URL: " << fetchUrl;
emit message(tr("URI handling"),
tr("Payment request fetch URL is invalid: %1").arg(fetchUrl.toString()),
CClientUIInterface::ICON_WARNING);
@@ -411,7 +409,15 @@ void PaymentServer::handleURIOrFile(const QString& s)
{
SendCoinsRecipient recipient;
if (GUIUtil::parseBitcoinURI(s, &recipient))
- emit receivedPaymentRequest(recipient);
+ {
+ CBitcoinAddress address(recipient.address.toStdString());
+ if (!address.IsValid()) {
+ emit message(tr("URI handling"), tr("Invalid payment address %1").arg(recipient.address),
+ CClientUIInterface::MSG_ERROR);
+ }
+ else
+ emit receivedPaymentRequest(recipient);
+ }
else
emit message(tr("URI handling"),
tr("URI can not be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters."),
@@ -425,12 +431,14 @@ void PaymentServer::handleURIOrFile(const QString& s)
{
PaymentRequestPlus request;
SendCoinsRecipient recipient;
- if (readPaymentRequest(s, request) && processPaymentRequest(request, recipient))
- emit receivedPaymentRequest(recipient);
- else
+ if (!readPaymentRequest(s, request))
+ {
emit message(tr("Payment request file handling"),
- tr("Payment request file can not be read or processed! This can be caused by an invalid payment request file."),
+ tr("Payment request file can not be read! This can be caused by an invalid payment request file."),
CClientUIInterface::ICON_WARNING);
+ }
+ else if (processPaymentRequest(request, recipient))
+ emit receivedPaymentRequest(recipient);
return;
}
@@ -462,13 +470,13 @@ bool PaymentServer::readPaymentRequest(const QString& filename, PaymentRequestPl
QFile f(filename);
if (!f.open(QIODevice::ReadOnly))
{
- qDebug() << "PaymentServer::readPaymentRequest : Failed to open " << filename;
+ qWarning() << "PaymentServer::readPaymentRequest : Failed to open " << filename;
return false;
}
if (f.size() > MAX_PAYMENT_REQUEST_SIZE)
{
- qDebug() << "PaymentServer::readPaymentRequest : " << filename << " too large";
+ qWarning() << "PaymentServer::readPaymentRequest : " << filename << " too large";
return false;
}
@@ -482,6 +490,34 @@ bool PaymentServer::processPaymentRequest(PaymentRequestPlus& request, SendCoins
if (!optionsModel)
return false;
+ if (request.IsInitialized()) {
+ const payments::PaymentDetails& details = request.getDetails();
+
+ // Payment request network matches client network?
+ if (details.network() != Params().NetworkIDString())
+ {
+ emit message(tr("Payment request rejected"), tr("Payment request network doesn't match client network."),
+ CClientUIInterface::MSG_ERROR);
+
+ return false;
+ }
+
+ // Expired payment request?
+ if (details.has_expires() && (int64_t)details.expires() < GetTime())
+ {
+ emit message(tr("Payment request rejected"), tr("Payment request has expired."),
+ CClientUIInterface::MSG_ERROR);
+
+ return false;
+ }
+ }
+ else {
+ emit message(tr("Payment request error"), tr("Payment request is not initialized."),
+ CClientUIInterface::MSG_ERROR);
+
+ return false;
+ }
+
recipient.paymentRequest = request;
recipient.message = GUIUtil::HtmlEscape(request.getDetails().memo());
@@ -497,11 +533,11 @@ bool PaymentServer::processPaymentRequest(PaymentRequestPlus& request, SendCoins
// Append destination address
addresses.append(QString::fromStdString(CBitcoinAddress(dest).ToString()));
}
- else if (!recipient.authenticatedMerchant.isEmpty()){
+ else if (!recipient.authenticatedMerchant.isEmpty()) {
// Insecure payments to custom bitcoin addresses are not supported
// (there is no good way to tell the user where they are paying in a way
// they'd have a chance of understanding).
- emit message(tr("Payment request error"),
+ emit message(tr("Payment request rejected"),
tr("Unverified payment requests to custom payment scripts are unsupported."),
CClientUIInterface::MSG_ERROR);
return false;
@@ -509,12 +545,11 @@ bool PaymentServer::processPaymentRequest(PaymentRequestPlus& request, SendCoins
// Extract and check amounts
CTxOut txOut(sendingTo.second, sendingTo.first);
- if (txOut.IsDust(CTransaction::nMinRelayTxFee)) {
- QString msg = tr("Requested payment amount of %1 is too small (considered dust).")
- .arg(BitcoinUnits::formatWithUnit(optionsModel->getDisplayUnit(), sendingTo.second));
+ if (txOut.IsDust(::minRelayTxFee)) {
+ emit message(tr("Payment request error"), tr("Requested payment amount of %1 is too small (considered dust).")
+ .arg(BitcoinUnits::formatWithUnit(optionsModel->getDisplayUnit(), sendingTo.second)),
+ CClientUIInterface::MSG_ERROR);
- qDebug() << "PaymentServer::processPaymentRequest : " << msg;
- emit message(tr("Payment request error"), msg, CClientUIInterface::MSG_ERROR);
return false;
}
@@ -581,9 +616,9 @@ void PaymentServer::fetchPaymentACK(CWallet* wallet, SendCoinsRecipient recipien
refund_to->set_script(&s[0], s.size());
}
else {
- // This should never happen, because sending coins should have just unlocked the wallet
- // and refilled the keypool
- qDebug() << "PaymentServer::fetchPaymentACK : Error getting refund key, refund_to not set";
+ // This should never happen, because sending coins should have
+ // just unlocked the wallet and refilled the keypool.
+ qWarning() << "PaymentServer::fetchPaymentACK : Error getting refund key, refund_to not set";
}
}
@@ -594,8 +629,8 @@ void PaymentServer::fetchPaymentACK(CWallet* wallet, SendCoinsRecipient recipien
netManager->post(netRequest, serData);
}
else {
- // This should never happen, either:
- qDebug() << "PaymentServer::fetchPaymentACK : Error serializing payment message";
+ // This should never happen, either.
+ qWarning() << "PaymentServer::fetchPaymentACK : Error serializing payment message";
}
}
@@ -608,7 +643,7 @@ void PaymentServer::netRequestFinished(QNetworkReply* reply)
.arg(reply->request().url().toString())
.arg(reply->errorString());
- qDebug() << "PaymentServer::netRequestFinished : " << msg;
+ qWarning() << "PaymentServer::netRequestFinished : " << msg;
emit message(tr("Payment request error"), msg, CClientUIInterface::MSG_ERROR);
return;
}
@@ -620,17 +655,15 @@ void PaymentServer::netRequestFinished(QNetworkReply* reply)
{
PaymentRequestPlus request;
SendCoinsRecipient recipient;
- if (request.parse(data) && processPaymentRequest(request, recipient))
+ if (!request.parse(data))
{
- emit receivedPaymentRequest(recipient);
- }
- else
- {
- qDebug() << "PaymentServer::netRequestFinished : Error processing payment request";
+ qWarning() << "PaymentServer::netRequestFinished : Error parsing payment request";
emit message(tr("Payment request error"),
- tr("Payment request can not be parsed or processed!"),
+ tr("Payment request can not be parsed!"),
CClientUIInterface::MSG_ERROR);
}
+ else if (processPaymentRequest(request, recipient))
+ emit receivedPaymentRequest(recipient);
return;
}
@@ -642,7 +675,7 @@ void PaymentServer::netRequestFinished(QNetworkReply* reply)
QString msg = tr("Bad response from server %1")
.arg(reply->request().url().toString());
- qDebug() << "PaymentServer::netRequestFinished : " << msg;
+ qWarning() << "PaymentServer::netRequestFinished : " << msg;
emit message(tr("Payment request error"), msg, CClientUIInterface::MSG_ERROR);
}
else
@@ -658,7 +691,7 @@ void PaymentServer::reportSslErrors(QNetworkReply* reply, const QList<QSslError>
QString errString;
foreach (const QSslError& err, errs) {
- qDebug() << "PaymentServer::reportSslErrors : " << err;
+ qWarning() << "PaymentServer::reportSslErrors : " << err;
errString += err.errorString() + "\n";
}
emit message(tr("Network request error"), errString, CClientUIInterface::MSG_ERROR);
diff --git a/src/qt/peertablemodel.cpp b/src/qt/peertablemodel.cpp
new file mode 100644
index 0000000000..981d063c49
--- /dev/null
+++ b/src/qt/peertablemodel.cpp
@@ -0,0 +1,236 @@
+// Copyright (c) 2011-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 "peertablemodel.h"
+
+#include "clientmodel.h"
+
+#include "net.h"
+#include "sync.h"
+
+#include <QDebug>
+#include <QList>
+#include <QTimer>
+
+bool NodeLessThan::operator()(const CNodeCombinedStats &left, const CNodeCombinedStats &right) const
+{
+ const CNodeStats *pLeft = &(left.nodestats);
+ const CNodeStats *pRight = &(right.nodestats);
+
+ if (order == Qt::DescendingOrder)
+ std::swap(pLeft, pRight);
+
+ switch(column)
+ {
+ case PeerTableModel::Address:
+ return pLeft->addrName.compare(pRight->addrName) < 0;
+ case PeerTableModel::Subversion:
+ return pLeft->cleanSubVer.compare(pRight->cleanSubVer) < 0;
+ case PeerTableModel::Height:
+ return pLeft->nStartingHeight < pRight->nStartingHeight;
+ }
+
+ return false;
+}
+
+// private implementation
+class PeerTablePriv
+{
+public:
+ /** Local cache of peer information */
+ QList<CNodeCombinedStats> cachedNodeStats;
+ /** Column to sort nodes by */
+ int sortColumn;
+ /** Order (ascending or descending) to sort nodes by */
+ Qt::SortOrder sortOrder;
+ /** Index of rows by node ID */
+ std::map<NodeId, int> mapNodeRows;
+
+ /** Pull a full list of peers from vNodes into our cache */
+ void refreshPeers() {
+ {
+ TRY_LOCK(cs_vNodes, lockNodes);
+ if (!lockNodes)
+ {
+ // skip the refresh if we can't immediately get the lock
+ return;
+ }
+ cachedNodeStats.clear();
+#if QT_VERSION >= 0x040700
+ cachedNodeStats.reserve(vNodes.size());
+#endif
+ BOOST_FOREACH(CNode* pnode, vNodes)
+ {
+ CNodeCombinedStats stats;
+ stats.statestats.nMisbehavior = -1;
+ pnode->copyStats(stats.nodestats);
+ cachedNodeStats.append(stats);
+ }
+ }
+
+ // if we can, retrieve the CNodeStateStats for each node.
+ {
+ TRY_LOCK(cs_main, lockMain);
+ if (lockMain)
+ {
+ BOOST_FOREACH(CNodeCombinedStats &stats, cachedNodeStats)
+ {
+ GetNodeStateStats(stats.nodestats.nodeid, stats.statestats);
+ }
+ }
+ }
+
+ if (sortColumn >= 0)
+ // sort cacheNodeStats (use stable sort to prevent rows jumping around unneceesarily)
+ qStableSort(cachedNodeStats.begin(), cachedNodeStats.end(), NodeLessThan(sortColumn, sortOrder));
+
+ // build index map
+ mapNodeRows.clear();
+ int row = 0;
+ BOOST_FOREACH(CNodeCombinedStats &stats, cachedNodeStats)
+ {
+ mapNodeRows.insert(std::pair<NodeId, int>(stats.nodestats.nodeid, row++));
+ }
+ }
+
+ int size()
+ {
+ return cachedNodeStats.size();
+ }
+
+ CNodeCombinedStats *index(int idx)
+ {
+ if(idx >= 0 && idx < cachedNodeStats.size()) {
+ return &cachedNodeStats[idx];
+ }
+ else
+ {
+ return 0;
+ }
+ }
+};
+
+PeerTableModel::PeerTableModel(ClientModel *parent) :
+ QAbstractTableModel(parent),clientModel(parent),timer(0)
+{
+ columns << tr("Address") << tr("User Agent") << tr("Start Height");
+ priv = new PeerTablePriv();
+ // default to unsorted
+ priv->sortColumn = -1;
+
+ // set up timer for auto refresh
+ timer = new QTimer();
+ connect(timer, SIGNAL(timeout()), SLOT(refresh()));
+
+ // load initial data
+ refresh();
+}
+
+void PeerTableModel::startAutoRefresh(int msecs)
+{
+ timer->setInterval(1000);
+ timer->start();
+}
+
+void PeerTableModel::stopAutoRefresh()
+{
+ timer->stop();
+}
+
+int PeerTableModel::rowCount(const QModelIndex &parent) const
+{
+ Q_UNUSED(parent);
+ return priv->size();
+}
+
+int PeerTableModel::columnCount(const QModelIndex &parent) const
+{
+ Q_UNUSED(parent);
+ return 3;
+}
+
+QVariant PeerTableModel::data(const QModelIndex &index, int role) const
+{
+ if(!index.isValid())
+ return QVariant();
+
+ CNodeCombinedStats *rec = static_cast<CNodeCombinedStats*>(index.internalPointer());
+
+ if(role == Qt::DisplayRole)
+ {
+ switch(index.column())
+ {
+ case Address:
+ return QVariant(rec->nodestats.addrName.c_str());
+ case Subversion:
+ return QVariant(rec->nodestats.cleanSubVer.c_str());
+ case Height:
+ return rec->nodestats.nStartingHeight;
+ }
+ }
+ return QVariant();
+}
+
+QVariant PeerTableModel::headerData(int section, Qt::Orientation orientation, int role) const
+{
+ if(orientation == Qt::Horizontal)
+ {
+ if(role == Qt::DisplayRole && section < columns.size())
+ {
+ return columns[section];
+ }
+ }
+ return QVariant();
+}
+
+Qt::ItemFlags PeerTableModel::flags(const QModelIndex &index) const
+{
+ if(!index.isValid())
+ return 0;
+
+ Qt::ItemFlags retval = Qt::ItemIsSelectable | Qt::ItemIsEnabled;
+ return retval;
+}
+
+QModelIndex PeerTableModel::index(int row, int column, const QModelIndex &parent) const
+{
+ Q_UNUSED(parent);
+ CNodeCombinedStats *data = priv->index(row);
+
+ if (data)
+ {
+ return createIndex(row, column, data);
+ }
+ else
+ {
+ return QModelIndex();
+ }
+}
+
+const CNodeCombinedStats *PeerTableModel::getNodeStats(int idx) {
+ return priv->index(idx);
+}
+
+void PeerTableModel::refresh()
+{
+ emit layoutAboutToBeChanged();
+ priv->refreshPeers();
+ emit layoutChanged();
+}
+
+int PeerTableModel::getRowByNodeId(NodeId nodeid)
+{
+ std::map<NodeId, int>::iterator it = priv->mapNodeRows.find(nodeid);
+ if (it == priv->mapNodeRows.end())
+ return -1;
+
+ return it->second;
+}
+
+void PeerTableModel::sort(int column, Qt::SortOrder order)
+{
+ priv->sortColumn = column;
+ priv->sortOrder = order;
+ refresh();
+}
diff --git a/src/qt/peertablemodel.h b/src/qt/peertablemodel.h
new file mode 100644
index 0000000000..385bf0e0c1
--- /dev/null
+++ b/src/qt/peertablemodel.h
@@ -0,0 +1,80 @@
+// Copyright (c) 2011-2013 The Bitcoin developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef PEERTABLEMODEL_H
+#define PEERTABLEMODEL_H
+
+#include "main.h"
+#include "net.h"
+
+#include <QAbstractTableModel>
+#include <QStringList>
+
+class ClientModel;
+class PeerTablePriv;
+
+QT_BEGIN_NAMESPACE
+class QTimer;
+QT_END_NAMESPACE
+
+struct CNodeCombinedStats {
+ CNodeStats nodestats;
+ CNodeStateStats statestats;
+};
+
+class NodeLessThan
+{
+public:
+ NodeLessThan(int nColumn, Qt::SortOrder fOrder) :
+ column(nColumn), order(fOrder) {}
+ bool operator()(const CNodeCombinedStats &left, const CNodeCombinedStats &right) const;
+
+private:
+ int column;
+ Qt::SortOrder order;
+};
+
+/**
+ Qt model providing information about connected peers, similar to the
+ "getpeerinfo" RPC call. Used by the rpc console UI.
+ */
+class PeerTableModel : public QAbstractTableModel
+{
+ Q_OBJECT
+
+public:
+ explicit PeerTableModel(ClientModel *parent = 0);
+ const CNodeCombinedStats *getNodeStats(int idx);
+ int getRowByNodeId(NodeId nodeid);
+ void startAutoRefresh(int msecs);
+ void stopAutoRefresh();
+
+ enum ColumnIndex {
+ Address = 0,
+ Subversion = 1,
+ Height = 2
+ };
+
+ /** @name Methods overridden from QAbstractTableModel
+ @{*/
+ int rowCount(const QModelIndex &parent) const;
+ int columnCount(const QModelIndex &parent) const;
+ QVariant data(const QModelIndex &index, int role) const;
+ QVariant headerData(int section, Qt::Orientation orientation, int role) const;
+ QModelIndex index(int row, int column, const QModelIndex &parent) const;
+ Qt::ItemFlags flags(const QModelIndex &index) const;
+ void sort(int column, Qt::SortOrder order);
+ /*@}*/
+
+public slots:
+ void refresh();
+
+private:
+ ClientModel *clientModel;
+ QStringList columns;
+ PeerTablePriv *priv;
+ QTimer *timer;
+};
+
+#endif // PEERTABLEMODEL_H
diff --git a/src/qt/receiverequestdialog.cpp b/src/qt/receiverequestdialog.cpp
index 062638f2bc..cc2f00916f 100644
--- a/src/qt/receiverequestdialog.cpp
+++ b/src/qt/receiverequestdialog.cpp
@@ -13,16 +13,16 @@
#include <QClipboard>
#include <QDrag>
+#include <QMenu>
#include <QMimeData>
#include <QMouseEvent>
#include <QPixmap>
-#include <QMenu>
#if QT_VERSION < 0x050000
#include <QUrl>
#endif
#if defined(HAVE_CONFIG_H)
-#include "bitcoin-config.h" /* for USE_QRCODE */
+#include "config/bitcoin-config.h" /* for USE_QRCODE */
#endif
#ifdef USE_QRCODE
diff --git a/src/qt/receiverequestdialog.h b/src/qt/receiverequestdialog.h
index 5614ac635a..9b78e495c3 100644
--- a/src/qt/receiverequestdialog.h
+++ b/src/qt/receiverequestdialog.h
@@ -11,10 +11,12 @@
#include <QImage>
#include <QLabel>
+class OptionsModel;
+
namespace Ui {
class ReceiveRequestDialog;
}
-class OptionsModel;
+
QT_BEGIN_NAMESPACE
class QMenu;
QT_END_NAMESPACE
diff --git a/src/qt/recentrequeststablemodel.cpp b/src/qt/recentrequeststablemodel.cpp
index 844d62518c..b5a998f9f5 100644
--- a/src/qt/recentrequeststablemodel.cpp
+++ b/src/qt/recentrequeststablemodel.cpp
@@ -21,7 +21,9 @@ RecentRequestsTableModel::RecentRequestsTableModel(CWallet *wallet, WalletModel
addNewRequest(request);
/* These columns must match the indices in the ColumnIndex enumeration */
- columns << tr("Date") << tr("Label") << tr("Message") << tr("Amount");
+ columns << tr("Date") << tr("Label") << tr("Message") << getAmountTitle();
+
+ connect(walletModel->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit()));
}
RecentRequestsTableModel::~RecentRequestsTableModel()
@@ -101,6 +103,24 @@ QVariant RecentRequestsTableModel::headerData(int section, Qt::Orientation orien
return QVariant();
}
+/** Updates the column title to "Amount (DisplayUnit)" and emits headerDataChanged() signal for table headers to react. */
+void RecentRequestsTableModel::updateAmountColumnTitle()
+{
+ columns[Amount] = getAmountTitle();
+ emit headerDataChanged(Qt::Horizontal,Amount,Amount);
+}
+
+/** Gets title for amount column including current display unit if optionsModel reference available. */
+QString RecentRequestsTableModel::getAmountTitle()
+{
+ QString amountTitle = tr("Amount");
+ if (this->walletModel->getOptionsModel() != NULL)
+ {
+ amountTitle += " ("+BitcoinUnits::name(this->walletModel->getOptionsModel()->getDisplayUnit()) + ")";
+ }
+ return amountTitle;
+}
+
QModelIndex RecentRequestsTableModel::index(int row, int column, const QModelIndex &parent) const
{
Q_UNUSED(parent);
@@ -185,6 +205,11 @@ void RecentRequestsTableModel::sort(int column, Qt::SortOrder order)
emit dataChanged(index(0, 0, QModelIndex()), index(list.size() - 1, NUMBER_OF_COLUMNS - 1, QModelIndex()));
}
+void RecentRequestsTableModel::updateDisplayUnit()
+{
+ updateAmountColumnTitle();
+}
+
bool RecentRequestEntryLessThan::operator()(RecentRequestEntry &left, RecentRequestEntry &right) const
{
RecentRequestEntry *pLeft = &left;
diff --git a/src/qt/recentrequeststablemodel.h b/src/qt/recentrequeststablemodel.h
index d4cc5078aa..4f0b241259 100644
--- a/src/qt/recentrequeststablemodel.h
+++ b/src/qt/recentrequeststablemodel.h
@@ -91,12 +91,18 @@ public:
public slots:
void sort(int column, Qt::SortOrder order = Qt::AscendingOrder);
+ void updateDisplayUnit();
private:
WalletModel *walletModel;
QStringList columns;
QList<RecentRequestEntry> list;
int64_t nReceiveRequestsMaxId;
+
+ /** Updates the column title to "Amount (DisplayUnit)" and emits headerDataChanged() signal for table headers to react. */
+ void updateAmountColumnTitle();
+ /** Gets title for amount column including current display unit if optionsModel reference available. */
+ QString getAmountTitle();
};
#endif
diff --git a/src/qt/res/bitcoin-qt-res.rc b/src/qt/res/bitcoin-qt-res.rc
index ee23ae9b78..809235be5f 100644
--- a/src/qt/res/bitcoin-qt-res.rc
+++ b/src/qt/res/bitcoin-qt-res.rc
@@ -8,7 +8,6 @@ IDI_ICON2 ICON DISCARDABLE "icons/bitcoin_testnet.ico"
#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
diff --git a/src/qt/res/icons/unit_btc.png b/src/qt/res/icons/unit_btc.png
new file mode 100644
index 0000000000..ec3497435c
--- /dev/null
+++ b/src/qt/res/icons/unit_btc.png
Binary files differ
diff --git a/src/qt/res/icons/unit_mbtc.png b/src/qt/res/icons/unit_mbtc.png
new file mode 100644
index 0000000000..32bf2f2ca0
--- /dev/null
+++ b/src/qt/res/icons/unit_mbtc.png
Binary files differ
diff --git a/src/qt/res/icons/unit_ubtc.png b/src/qt/res/icons/unit_ubtc.png
new file mode 100644
index 0000000000..d5a154882b
--- /dev/null
+++ b/src/qt/res/icons/unit_ubtc.png
Binary files differ
diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp
index 0a46a722e4..e1f40ddd09 100644
--- a/src/qt/rpcconsole.cpp
+++ b/src/qt/rpcconsole.cpp
@@ -7,12 +7,19 @@
#include "clientmodel.h"
#include "guiutil.h"
+#include "peertablemodel.h"
+#include "main.h"
#include "rpcserver.h"
#include "rpcclient.h"
+#include "util.h"
#include "json/json_spirit_value.h"
+#ifdef ENABLE_WALLET
+#include <db_cxx.h>
+#endif
#include <openssl/crypto.h>
+
#include <QKeyEvent>
#include <QScrollBar>
#include <QThread>
@@ -195,6 +202,10 @@ RPCConsole::RPCConsole(QWidget *parent) :
clientModel(0),
historyPtr(0)
{
+ detailNodeStats = CNodeCombinedStats();
+ detailNodeStats.nodestats.nodeid = -1;
+ detailNodeStats.statestats.nMisbehavior = -1;
+
ui->setupUi(this);
GUIUtil::restoreWindowGeometry("nRPCConsoleWindow", this->size(), this);
@@ -209,12 +220,20 @@ RPCConsole::RPCConsole(QWidget *parent) :
connect(ui->clearButton, SIGNAL(clicked()), this, SLOT(clear()));
connect(ui->btnClearTrafficGraph, SIGNAL(clicked()), ui->trafficGraph, SLOT(clear()));
- // set OpenSSL version label
+ // set library version labels
ui->openSSLVersion->setText(SSLeay_version(SSLEAY_VERSION));
+#ifdef ENABLE_WALLET
+ ui->berkeleyDBVersion->setText(DbEnv::version(0, 0, 0));
+#else
+ ui->label_berkeleyDBVersion->hide();
+ ui->berkeleyDBVersion->hide();
+#endif
startExecutor();
setTrafficGraphRange(INITIAL_TRAFFIC_GRAPH_MINS);
+ ui->detailWidget->hide();
+
clear();
}
@@ -277,13 +296,28 @@ void RPCConsole::setClientModel(ClientModel *model)
updateTrafficStats(model->getTotalBytesRecv(), model->getTotalBytesSent());
connect(model, SIGNAL(bytesChanged(quint64,quint64)), this, SLOT(updateTrafficStats(quint64, quint64)));
+ // set up peer table
+ ui->peerWidget->setModel(model->getPeerTableModel());
+ ui->peerWidget->verticalHeader()->hide();
+ ui->peerWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
+ ui->peerWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
+ ui->peerWidget->setSelectionMode(QAbstractItemView::SingleSelection);
+ ui->peerWidget->setColumnWidth(PeerTableModel::Address, ADDRESS_COLUMN_WIDTH);
+ columnResizingFixer = new GUIUtil::TableViewLastColumnResizingFixer(ui->peerWidget, MINIMUM_COLUMN_WIDTH, MINIMUM_COLUMN_WIDTH);
+
+ // connect the peerWidget's selection model to our peerSelected() handler
+ QItemSelectionModel *peerSelectModel = ui->peerWidget->selectionModel();
+ connect(peerSelectModel, SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)),
+ this, SLOT(peerSelected(const QItemSelection &, const QItemSelection &)));
+ connect(model->getPeerTableModel(), SIGNAL(layoutChanged()), this, SLOT(peerLayoutChanged()));
+
// Provide initial values
ui->clientVersion->setText(model->formatFullVersion());
ui->clientName->setText(model->clientName());
ui->buildDate->setText(model->formatBuildDate());
ui->startupTime->setText(model->formatClientStartupTime());
- ui->networkName->setText(model->getNetworkName());
+ ui->networkName->setText(QString::fromStdString(Params().NetworkIDString()));
}
}
@@ -382,8 +416,8 @@ void RPCConsole::on_lineEdit_returnPressed()
{
message(CMD_REQUEST, cmd);
emit cmdRequest(cmd);
- // Truncate history from current position
- history.erase(history.begin() + historyPtr, history.end());
+ // Remove command, if already in history
+ history.removeOne(cmd);
// Append command to history
history.append(cmd);
// Enforce maximum history size
@@ -474,17 +508,7 @@ QString RPCConsole::FormatBytes(quint64 bytes)
void RPCConsole::setTrafficGraphRange(int mins)
{
ui->trafficGraph->setGraphRangeMins(mins);
- if(mins < 60) {
- ui->lblGraphRange->setText(QString(tr("%1 m")).arg(mins));
- } else {
- int hours = mins / 60;
- int minsLeft = mins % 60;
- if(minsLeft == 0) {
- ui->lblGraphRange->setText(QString(tr("%1 h")).arg(hours));
- } else {
- ui->lblGraphRange->setText(QString(tr("%1 h %2 m")).arg(hours).arg(minsLeft));
- }
- }
+ ui->lblGraphRange->setText(GUIUtil::formatDurationStr(mins * 60));
}
void RPCConsole::updateTrafficStats(quint64 totalBytesIn, quint64 totalBytesOut)
@@ -492,3 +516,161 @@ void RPCConsole::updateTrafficStats(quint64 totalBytesIn, quint64 totalBytesOut)
ui->lblBytesIn->setText(FormatBytes(totalBytesIn));
ui->lblBytesOut->setText(FormatBytes(totalBytesOut));
}
+
+void RPCConsole::peerSelected(const QItemSelection &selected, const QItemSelection &deselected)
+{
+ Q_UNUSED(deselected);
+
+ if (selected.indexes().isEmpty())
+ return;
+
+ // mark the cached banscore as unknown
+ detailNodeStats.statestats.nMisbehavior = -1;
+
+ const CNodeCombinedStats *stats = clientModel->getPeerTableModel()->getNodeStats(selected.indexes().first().row());
+
+ if (stats)
+ {
+ detailNodeStats.nodestats.nodeid = stats->nodestats.nodeid;
+ updateNodeDetail(stats);
+ ui->detailWidget->show();
+ ui->detailWidget->setDisabled(false);
+ }
+}
+
+void RPCConsole::peerLayoutChanged()
+{
+ const CNodeCombinedStats *stats = NULL;
+ bool fUnselect = false, fReselect = false, fDisconnected = false;
+
+ if (detailNodeStats.nodestats.nodeid == -1)
+ // no node selected yet
+ return;
+
+ // find the currently selected row
+ int selectedRow;
+ QModelIndexList selectedModelIndex = ui->peerWidget->selectionModel()->selectedIndexes();
+ if (selectedModelIndex.isEmpty())
+ selectedRow = -1;
+ else
+ selectedRow = selectedModelIndex.first().row();
+
+ // check if our detail node has a row in the table (it may not necessarily
+ // be at selectedRow since its position can change after a layout change)
+ int detailNodeRow = clientModel->getPeerTableModel()->getRowByNodeId(detailNodeStats.nodestats.nodeid);
+
+ if (detailNodeRow < 0)
+ {
+ // detail node dissapeared from table (node disconnected)
+ fUnselect = true;
+ fDisconnected = true;
+ detailNodeStats.nodestats.nodeid = 0;
+ }
+ else
+ {
+ if (detailNodeRow != selectedRow)
+ {
+ // detail node moved position
+ fUnselect = true;
+ fReselect = true;
+ }
+
+ // get fresh stats on the detail node.
+ stats = clientModel->getPeerTableModel()->getNodeStats(detailNodeRow);
+ }
+
+ if (fUnselect && selectedRow >= 0)
+ {
+ ui->peerWidget->selectionModel()->select(QItemSelection(selectedModelIndex.first(), selectedModelIndex.last()),
+ QItemSelectionModel::Deselect);
+ }
+
+ if (fReselect)
+ {
+ ui->peerWidget->selectRow(detailNodeRow);
+ }
+
+ if (stats)
+ updateNodeDetail(stats);
+
+ if (fDisconnected)
+ {
+ ui->peerHeading->setText(QString(tr("Peer Disconnected")));
+ ui->detailWidget->setDisabled(true);
+ QDateTime dt = QDateTime::fromTime_t(detailNodeStats.nodestats.nLastSend);
+ if (detailNodeStats.nodestats.nLastSend)
+ ui->peerLastSend->setText(dt.toString("yyyy-MM-dd hh:mm:ss"));
+ dt.setTime_t(detailNodeStats.nodestats.nLastRecv);
+ if (detailNodeStats.nodestats.nLastRecv)
+ ui->peerLastRecv->setText(dt.toString("yyyy-MM-dd hh:mm:ss"));
+ dt.setTime_t(detailNodeStats.nodestats.nTimeConnected);
+ ui->peerConnTime->setText(dt.toString("yyyy-MM-dd hh:mm:ss"));
+ }
+}
+
+void RPCConsole::updateNodeDetail(const CNodeCombinedStats *combinedStats)
+{
+ CNodeStats stats = combinedStats->nodestats;
+
+ // keep a copy of timestamps, used to display dates upon disconnect
+ detailNodeStats.nodestats.nLastSend = stats.nLastSend;
+ detailNodeStats.nodestats.nLastRecv = stats.nLastRecv;
+ detailNodeStats.nodestats.nTimeConnected = stats.nTimeConnected;
+
+ // update the detail ui with latest node information
+ ui->peerHeading->setText(QString("<b>%1</b>").arg(tr("Node Detail")));
+ ui->peerAddr->setText(QString(stats.addrName.c_str()));
+ ui->peerServices->setText(GUIUtil::formatServicesStr(stats.nServices));
+ ui->peerLastSend->setText(stats.nLastSend ? GUIUtil::formatDurationStr(GetTime() - stats.nLastSend) : tr("never"));
+ ui->peerLastRecv->setText(stats.nLastRecv ? GUIUtil::formatDurationStr(GetTime() - stats.nLastRecv) : tr("never"));
+ ui->peerBytesSent->setText(FormatBytes(stats.nSendBytes));
+ ui->peerBytesRecv->setText(FormatBytes(stats.nRecvBytes));
+ ui->peerConnTime->setText(GUIUtil::formatDurationStr(GetTime() - stats.nTimeConnected));
+ ui->peerPingTime->setText(stats.dPingTime == 0 ? tr("N/A") : QString(tr("%1 secs")).arg(QString::number(stats.dPingTime, 'f', 3)));
+ ui->peerVersion->setText(QString("%1").arg(stats.nVersion));
+ ui->peerSubversion->setText(QString(stats.cleanSubVer.c_str()));
+ ui->peerDirection->setText(stats.fInbound ? tr("Inbound") : tr("Outbound"));
+ ui->peerHeight->setText(QString("%1").arg(stats.nStartingHeight));
+ ui->peerSyncNode->setText(stats.fSyncNode ? tr("Yes") : tr("No"));
+
+ // if we can, display the peer's ban score
+ CNodeStateStats statestats = combinedStats->statestats;
+ if (statestats.nMisbehavior >= 0)
+ {
+ // we have a new nMisbehavor value - update the cache
+ detailNodeStats.statestats.nMisbehavior = statestats.nMisbehavior;
+ }
+
+ // pull the ban score from cache. -1 means it hasn't been retrieved yet (lock busy).
+ if (detailNodeStats.statestats.nMisbehavior >= 0)
+ ui->peerBanScore->setText(QString("%1").arg(detailNodeStats.statestats.nMisbehavior));
+ else
+ ui->peerBanScore->setText(tr("Fetching..."));
+}
+
+// We override the virtual resizeEvent of the QWidget to adjust tables column
+// sizes as the tables width is proportional to the dialogs width.
+void RPCConsole::resizeEvent(QResizeEvent *event)
+{
+ QWidget::resizeEvent(event);
+ columnResizingFixer->stretchColumnWidth(PeerTableModel::Address);
+}
+
+void RPCConsole::showEvent(QShowEvent *event)
+{
+ QWidget::showEvent(event);
+
+ // peerWidget needs a resize in case the dialog has non-default geometry
+ columnResizingFixer->stretchColumnWidth(PeerTableModel::Address);
+
+ // start PeerTableModel auto refresh
+ clientModel->getPeerTableModel()->startAutoRefresh(1000);
+}
+
+void RPCConsole::hideEvent(QHideEvent *event)
+{
+ QWidget::hideEvent(event);
+
+ // stop PeerTableModel auto refresh
+ clientModel->getPeerTableModel()->stopAutoRefresh();
+}
diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h
index 091a6d294f..3aeff3eace 100644
--- a/src/qt/rpcconsole.h
+++ b/src/qt/rpcconsole.h
@@ -5,10 +5,19 @@
#ifndef RPCCONSOLE_H
#define RPCCONSOLE_H
+#include "guiutil.h"
+#include "peertablemodel.h"
+
+#include "net.h"
+
#include <QDialog>
class ClientModel;
+QT_BEGIN_NAMESPACE
+class QItemSelection;
+QT_END_NAMESPACE
+
namespace Ui {
class RPCConsole;
}
@@ -35,6 +44,19 @@ public:
protected:
virtual bool eventFilter(QObject* obj, QEvent *event);
+private:
+ /** show detailed information on ui about selected node */
+ void updateNodeDetail(const CNodeCombinedStats *combinedStats);
+
+ enum ColumnWidths
+ {
+ ADDRESS_COLUMN_WIDTH = 250,
+ MINIMUM_COLUMN_WIDTH = 120
+ };
+
+ /** track the node that we are currently viewing detail on in the peers tab */
+ CNodeCombinedStats detailNodeStats;
+
private slots:
void on_lineEdit_returnPressed();
void on_tabWidget_currentChanged(int index);
@@ -44,6 +66,9 @@ private slots:
void on_sldGraphRange_valueChanged(int value);
/** update traffic statistics */
void updateTrafficStats(quint64 totalBytesIn, quint64 totalBytesOut);
+ void resizeEvent(QResizeEvent *event);
+ void showEvent(QShowEvent *event);
+ void hideEvent(QHideEvent *event);
public slots:
void clear();
@@ -57,6 +82,10 @@ public slots:
void browseHistory(int offset);
/** Scroll console view to end */
void scrollToEnd();
+ /** Handle selection of peer in peers list */
+ void peerSelected(const QItemSelection &selected, const QItemSelection &deselected);
+ /** Handle updated peer information */
+ void peerLayoutChanged();
signals:
// For RPC command executor
@@ -70,6 +99,7 @@ private:
Ui::RPCConsole *ui;
ClientModel *clientModel;
QStringList history;
+ GUIUtil::TableViewLastColumnResizingFixer *columnResizingFixer;
int historyPtr;
void startExecutor();
diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp
index 33621e54b0..6f10ed5b0b 100644
--- a/src/qt/sendcoinsdialog.cpp
+++ b/src/qt/sendcoinsdialog.cpp
@@ -53,7 +53,7 @@ SendCoinsDialog::SendCoinsDialog(QWidget *parent) :
QAction *clipboardAfterFeeAction = new QAction(tr("Copy after fee"), this);
QAction *clipboardBytesAction = new QAction(tr("Copy bytes"), this);
QAction *clipboardPriorityAction = new QAction(tr("Copy priority"), this);
- QAction *clipboardLowOutputAction = new QAction(tr("Copy low output"), this);
+ QAction *clipboardLowOutputAction = new QAction(tr("Copy dust"), this);
QAction *clipboardChangeAction = new QAction(tr("Copy change"), this);
connect(clipboardQuantityAction, SIGNAL(triggered()), this, SLOT(coinControlClipboardQuantity()));
connect(clipboardAmountAction, SIGNAL(triggered()), this, SLOT(coinControlClipboardAmount()));
@@ -90,8 +90,9 @@ void SendCoinsDialog::setModel(WalletModel *model)
}
}
- setBalance(model->getBalance(), model->getUnconfirmedBalance(), model->getImmatureBalance());
- connect(model, SIGNAL(balanceChanged(qint64, qint64, qint64)), this, SLOT(setBalance(qint64, qint64, qint64)));
+ setBalance(model->getBalance(), model->getUnconfirmedBalance(), model->getImmatureBalance(),
+ model->getWatchBalance(), model->getWatchUnconfirmedBalance(), model->getWatchImmatureBalance());
+ connect(model, SIGNAL(balanceChanged(qint64, qint64, qint64, qint64, qint64, qint64)), this, SLOT(setBalance(qint64, qint64, qint64, qint64, qint64, qint64)));
connect(model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit()));
// Coin Control
@@ -377,34 +378,20 @@ void SendCoinsDialog::pasteEntry(const SendCoinsRecipient &rv)
bool SendCoinsDialog::handlePaymentRequest(const SendCoinsRecipient &rv)
{
- QString strSendCoins = tr("Send Coins");
- if (rv.paymentRequest.IsInitialized()) {
- // Expired payment request?
- const payments::PaymentDetails& details = rv.paymentRequest.getDetails();
- if (details.has_expires() && (int64_t)details.expires() < GetTime())
- {
- emit message(strSendCoins, tr("Payment request expired"),
- CClientUIInterface::MSG_WARNING);
- return false;
- }
- }
- else {
- CBitcoinAddress address(rv.address.toStdString());
- if (!address.IsValid()) {
- emit message(strSendCoins, tr("Invalid payment address %1").arg(rv.address),
- CClientUIInterface::MSG_WARNING);
- return false;
- }
- }
-
+ // Just paste the entry, all pre-checks
+ // are done in paymentserver.cpp.
pasteEntry(rv);
return true;
}
-void SendCoinsDialog::setBalance(qint64 balance, qint64 unconfirmedBalance, qint64 immatureBalance)
+void SendCoinsDialog::setBalance(qint64 balance, qint64 unconfirmedBalance, qint64 immatureBalance,
+ qint64 watchBalance, qint64 watchUnconfirmedBalance, qint64 watchImmatureBalance)
{
Q_UNUSED(unconfirmedBalance);
Q_UNUSED(immatureBalance);
+ Q_UNUSED(watchBalance);
+ Q_UNUSED(watchUnconfirmedBalance);
+ Q_UNUSED(watchImmatureBalance);
if(model && model->getOptionsModel())
{
@@ -414,7 +401,7 @@ void SendCoinsDialog::setBalance(qint64 balance, qint64 unconfirmedBalance, qint
void SendCoinsDialog::updateDisplayUnit()
{
- setBalance(model->getBalance(), 0, 0);
+ setBalance(model->getBalance(), 0, 0, 0, 0, 0);
}
void SendCoinsDialog::processSendCoinsReturn(const WalletModel::SendCoinsReturn &sendCoinsReturn, const QString &msgArg)
@@ -496,7 +483,7 @@ void SendCoinsDialog::coinControlClipboardPriority()
GUIUtil::setClipboard(ui->labelCoinControlPriority->text());
}
-// Coin Control: copy label "Low output" to clipboard
+// Coin Control: copy label "Dust" to clipboard
void SendCoinsDialog::coinControlClipboardLowOutput()
{
GUIUtil::setClipboard(ui->labelCoinControlLowOutput->text());
diff --git a/src/qt/sendcoinsdialog.h b/src/qt/sendcoinsdialog.h
index fcae26c720..6cdf4a00c8 100644
--- a/src/qt/sendcoinsdialog.h
+++ b/src/qt/sendcoinsdialog.h
@@ -47,7 +47,8 @@ public slots:
void accept();
SendCoinsEntry *addEntry();
void updateTabsAndLabels();
- void setBalance(qint64 balance, qint64 unconfirmedBalance, qint64 immatureBalance);
+ void setBalance(qint64 balance, qint64 unconfirmedBalance, qint64 immatureBalance,
+ qint64 watchOnlyBalance, qint64 watchUnconfBalance, qint64 watchImmatureBalance);
private:
Ui::SendCoinsDialog *ui;
diff --git a/src/qt/signverifymessagedialog.cpp b/src/qt/signverifymessagedialog.cpp
index 3e56412c7c..d4d021e21c 100644
--- a/src/qt/signverifymessagedialog.cpp
+++ b/src/qt/signverifymessagedialog.cpp
@@ -27,7 +27,6 @@ SignVerifyMessageDialog::SignVerifyMessageDialog(QWidget *parent) :
#if QT_VERSION >= 0x040700
ui->signatureOut_SM->setPlaceholderText(tr("Click \"Sign Message\" to generate signature"));
- ui->addressIn_VM->setPlaceholderText(tr("Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)"));
#endif
GUIUtil::setupAddressWidget(ui->addressIn_SM, this);
diff --git a/src/qt/splashscreen.cpp b/src/qt/splashscreen.cpp
index 7c79b0efd0..1162e2d87f 100644
--- a/src/qt/splashscreen.cpp
+++ b/src/qt/splashscreen.cpp
@@ -129,6 +129,7 @@ void SplashScreen::subscribeToCoreSignals()
{
// Connect signals to client
uiInterface.InitMessage.connect(boost::bind(InitMessage, this, _1));
+ uiInterface.ShowProgress.connect(boost::bind(ShowProgress, this, _1, _2));
#ifdef ENABLE_WALLET
uiInterface.LoadWallet.connect(boost::bind(ConnectWallet, this, _1));
#endif
@@ -138,6 +139,7 @@ void SplashScreen::unsubscribeFromCoreSignals()
{
// Disconnect signals from client
uiInterface.InitMessage.disconnect(boost::bind(InitMessage, this, _1));
+ uiInterface.ShowProgress.disconnect(boost::bind(ShowProgress, this, _1, _2));
#ifdef ENABLE_WALLET
if(pwalletMain)
pwalletMain->ShowProgress.disconnect(boost::bind(ShowProgress, this, _1, _2));
diff --git a/src/qt/test/Makefile b/src/qt/test/Makefile
new file mode 100644
index 0000000000..a02f86b62a
--- /dev/null
+++ b/src/qt/test/Makefile
@@ -0,0 +1,6 @@
+all:
+ $(MAKE) -C ../../ test_bitcoin_qt
+clean:
+ $(MAKE) -C ../../ test_bitcoin_qt_clean
+check:
+ $(MAKE) -C ../../ test_bitcoin_qt_check
diff --git a/src/qt/test/Makefile.am b/src/qt/test/Makefile.am
deleted file mode 100644
index 2461b5ff4d..0000000000
--- a/src/qt/test/Makefile.am
+++ /dev/null
@@ -1,46 +0,0 @@
-include $(top_srcdir)/src/Makefile.include
-
-AM_CPPFLAGS += -I$(top_srcdir)/src \
- -I$(top_srcdir)/src/qt \
- -I$(top_builddir)/src/qt \
- $(PROTOBUF_CFLAGS) \
- $(QR_CFLAGS)
-bin_PROGRAMS = test_bitcoin-qt
-TESTS = test_bitcoin-qt
-
-TEST_QT_MOC_CPP = moc_uritests.cpp
-
-if ENABLE_WALLET
-TEST_QT_MOC_CPP += moc_paymentservertests.cpp
-endif
-
-TEST_QT_H = \
- uritests.h \
- paymentrequestdata.h \
- paymentservertests.h
-
-BUILT_SOURCES = $(TEST_QT_MOC_CPP)
-
-test_bitcoin_qt_CPPFLAGS = $(AM_CPPFLAGS) $(QT_INCLUDES) $(QT_TEST_INCLUDES)
-
-test_bitcoin_qt_SOURCES = \
- test_main.cpp \
- uritests.cpp \
- $(TEST_QT_H)
-if ENABLE_WALLET
-test_bitcoin_qt_SOURCES += \
- paymentservertests.cpp
-endif
-
-nodist_test_bitcoin_qt_SOURCES = $(TEST_QT_MOC_CPP)
-
-test_bitcoin_qt_LDADD = $(LIBBITCOINQT) $(LIBBITCOIN_SERVER)
-if ENABLE_WALLET
-test_bitcoin_qt_LDADD += $(LIBBITCOIN_WALLET)
-endif
-test_bitcoin_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBLEVELDB) \
- $(LIBMEMENV) $(BOOST_LIBS) $(QT_DBUS_LIBS) $(QT_TEST_LIBS) $(QT_LIBS) \
- $(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS)
-test_bitcoin_qt_LDFLAGS = $(QT_LDFLAGS)
-
-CLEANFILES = $(BUILT_SOURCES) *.gcda *.gcno
diff --git a/src/qt/test/paymentservertests.cpp b/src/qt/test/paymentservertests.cpp
index 7dee7a9cda..e92a7d2b1a 100644
--- a/src/qt/test/paymentservertests.cpp
+++ b/src/qt/test/paymentservertests.cpp
@@ -56,6 +56,7 @@ static SendCoinsRecipient handleRequest(PaymentServer* server, std::vector<unsig
void PaymentServerTests::paymentServerTests()
{
+ SelectParams(CBaseChainParams::MAIN);
OptionsModel optionsModel;
PaymentServer* server = new PaymentServer(NULL, false);
X509_STORE* caStore = X509_STORE_new();
diff --git a/src/qt/test/test_main.cpp b/src/qt/test/test_main.cpp
index a2adb00327..03a2381c06 100644
--- a/src/qt/test/test_main.cpp
+++ b/src/qt/test/test_main.cpp
@@ -1,6 +1,5 @@
-#include "bitcoin-config.h"
#if defined(HAVE_CONFIG_H)
-#include "bitcoin-config.h"
+#include "config/bitcoin-config.h"
#endif
#ifdef ENABLE_WALLET
diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp
index 45fb3d40c2..36e4d50e30 100644
--- a/src/qt/transactiondesc.cpp
+++ b/src/qt/transactiondesc.cpp
@@ -12,12 +12,16 @@
#include "main.h"
#include "paymentserver.h"
#include "transactionrecord.h"
+#include "timedata.h"
#include "ui_interface.h"
#include "wallet.h"
+#include "script.h"
#include <stdint.h>
#include <string>
+using namespace std;
+
QString TransactionDesc::FormatTxStatus(const CWalletTx& wtx)
{
AssertLockHeld(cs_main);
@@ -42,7 +46,7 @@ QString TransactionDesc::FormatTxStatus(const CWalletTx& wtx)
}
}
-QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, int vout, int unit)
+QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionRecord *rec, int unit)
{
QString strHTML;
@@ -51,8 +55,8 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, int vout, int u
strHTML += "<html><font face='verdana, arial, helvetica, sans-serif'>";
int64_t nTime = wtx.GetTxTime();
- int64_t nCredit = wtx.GetCredit();
- int64_t nDebit = wtx.GetDebit();
+ int64_t nCredit = wtx.GetCredit(ISMINE_ALL);
+ int64_t nDebit = wtx.GetDebit(ISMINE_ALL);
int64_t nNet = nCredit - nDebit;
strHTML += "<b>" + tr("Status") + ":</b> " + FormatTxStatus(wtx);
@@ -86,26 +90,20 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, int vout, int u
if (nNet > 0)
{
// Credit
- BOOST_FOREACH(const CTxOut& txout, wtx.vout)
+ if (CBitcoinAddress(rec->address).IsValid())
{
- if (wallet->IsMine(txout))
+ CTxDestination address = CBitcoinAddress(rec->address).Get();
+ if (wallet->mapAddressBook.count(address))
{
- CTxDestination address;
- if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*wallet, address))
- {
- if (wallet->mapAddressBook.count(address))
- {
- strHTML += "<b>" + tr("From") + ":</b> " + tr("unknown") + "<br>";
- strHTML += "<b>" + tr("To") + ":</b> ";
- strHTML += GUIUtil::HtmlEscape(CBitcoinAddress(address).ToString());
- if (!wallet->mapAddressBook[address].name.empty())
- strHTML += " (" + tr("own address") + ", " + tr("label") + ": " + GUIUtil::HtmlEscape(wallet->mapAddressBook[address].name) + ")";
- else
- strHTML += " (" + tr("own address") + ")";
- strHTML += "<br>";
- }
- }
- break;
+ strHTML += "<b>" + tr("From") + ":</b> " + tr("unknown") + "<br>";
+ strHTML += "<b>" + tr("To") + ":</b> ";
+ strHTML += GUIUtil::HtmlEscape(rec->address);
+ QString addressOwned = (::IsMine(*wallet, address) == ISMINE_SPENDABLE) ? tr("own address") : tr("watch-only");
+ if (!wallet->mapAddressBook[address].name.empty())
+ strHTML += " (" + addressOwned + ", " + tr("label") + ": " + GUIUtil::HtmlEscape(wallet->mapAddressBook[address].name) + ")";
+ else
+ strHTML += " (" + addressOwned + ")";
+ strHTML += "<br>";
}
}
}
@@ -135,7 +133,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, int vout, int u
//
int64_t nUnmatured = 0;
BOOST_FOREACH(const CTxOut& txout, wtx.vout)
- nUnmatured += wallet->GetCredit(txout);
+ nUnmatured += wallet->GetCredit(txout, ISMINE_ALL);
strHTML += "<b>" + tr("Credit") + ":</b> ";
if (wtx.IsInMainChain())
strHTML += BitcoinUnits::formatWithUnit(unit, nUnmatured)+ " (" + tr("matures in %n more block(s)", "", wtx.GetBlocksToMaturity()) + ")";
@@ -152,22 +150,33 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, int vout, int u
}
else
{
- bool fAllFromMe = true;
+ isminetype fAllFromMe = ISMINE_SPENDABLE;
BOOST_FOREACH(const CTxIn& txin, wtx.vin)
- fAllFromMe = fAllFromMe && wallet->IsMine(txin);
+ {
+ isminetype mine = wallet->IsMine(txin);
+ if(fAllFromMe > mine) fAllFromMe = mine;
+ }
- bool fAllToMe = true;
+ isminetype fAllToMe = ISMINE_SPENDABLE;
BOOST_FOREACH(const CTxOut& txout, wtx.vout)
- fAllToMe = fAllToMe && wallet->IsMine(txout);
+ {
+ isminetype mine = wallet->IsMine(txout);
+ if(fAllToMe > mine) fAllToMe = mine;
+ }
if (fAllFromMe)
{
+ if(fAllFromMe == ISMINE_WATCH_ONLY)
+ strHTML += "<b>" + tr("From") + ":</b> " + tr("watch-only") + "<br>";
+
//
// Debit
//
BOOST_FOREACH(const CTxOut& txout, wtx.vout)
{
- if (wallet->IsMine(txout))
+ // Ignore change
+ isminetype toSelf = wallet->IsMine(txout);
+ if ((toSelf == ISMINE_SPENDABLE) && (fAllFromMe == ISMINE_SPENDABLE))
continue;
if (!wtx.mapValue.count("to") || wtx.mapValue["to"].empty())
@@ -180,11 +189,17 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, int vout, int u
if (wallet->mapAddressBook.count(address) && !wallet->mapAddressBook[address].name.empty())
strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[address].name) + " ";
strHTML += GUIUtil::HtmlEscape(CBitcoinAddress(address).ToString());
+ if(toSelf == ISMINE_SPENDABLE)
+ strHTML += " (own address)";
+ else if(toSelf == ISMINE_WATCH_ONLY)
+ strHTML += " (watch-only)";
strHTML += "<br>";
}
}
strHTML += "<b>" + tr("Debit") + ":</b> " + BitcoinUnits::formatWithUnit(unit, -txout.nValue) + "<br>";
+ if(toSelf)
+ strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatWithUnit(unit, txout.nValue) + "<br>";
}
if (fAllToMe)
@@ -192,8 +207,8 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, int vout, int u
// Payment to self
int64_t nChange = wtx.GetChange();
int64_t nValue = nCredit - nChange;
- strHTML += "<b>" + tr("Debit") + ":</b> " + BitcoinUnits::formatWithUnit(unit, -nValue) + "<br>";
- strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatWithUnit(unit, nValue) + "<br>";
+ strHTML += "<b>" + tr("Total debit") + ":</b> " + BitcoinUnits::formatWithUnit(unit, -nValue) + "<br>";
+ strHTML += "<b>" + tr("Total credit") + ":</b> " + BitcoinUnits::formatWithUnit(unit, nValue) + "<br>";
}
int64_t nTxFee = nDebit - wtx.GetValueOut();
@@ -207,10 +222,10 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, int vout, int u
//
BOOST_FOREACH(const CTxIn& txin, wtx.vin)
if (wallet->IsMine(txin))
- strHTML += "<b>" + tr("Debit") + ":</b> " + BitcoinUnits::formatWithUnit(unit, -wallet->GetDebit(txin)) + "<br>";
+ strHTML += "<b>" + tr("Debit") + ":</b> " + BitcoinUnits::formatWithUnit(unit, -wallet->GetDebit(txin, ISMINE_ALL)) + "<br>";
BOOST_FOREACH(const CTxOut& txout, wtx.vout)
if (wallet->IsMine(txout))
- strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatWithUnit(unit, wallet->GetCredit(txout)) + "<br>";
+ strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatWithUnit(unit, wallet->GetCredit(txout, ISMINE_ALL)) + "<br>";
}
}
@@ -224,7 +239,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, int vout, int u
if (wtx.mapValue.count("comment") && !wtx.mapValue["comment"].empty())
strHTML += "<br><b>" + tr("Comment") + ":</b><br>" + GUIUtil::HtmlEscape(wtx.mapValue["comment"], true) + "<br>";
- strHTML += "<b>" + tr("Transaction ID") + ":</b> " + TransactionRecord::formatSubTxId(wtx.GetHash(), vout) + "<br>";
+ strHTML += "<b>" + tr("Transaction ID") + ":</b> " + TransactionRecord::formatSubTxId(wtx.GetHash(), rec->idx) + "<br>";
// Message from normal bitcoin:URI (bitcoin:123...?message=example)
foreach (const PAIRTYPE(string, string)& r, wtx.vOrderForm)
@@ -260,10 +275,10 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, int vout, int u
strHTML += "<hr><br>" + tr("Debug information") + "<br><br>";
BOOST_FOREACH(const CTxIn& txin, wtx.vin)
if(wallet->IsMine(txin))
- strHTML += "<b>" + tr("Debit") + ":</b> " + BitcoinUnits::formatWithUnit(unit, -wallet->GetDebit(txin)) + "<br>";
+ strHTML += "<b>" + tr("Debit") + ":</b> " + BitcoinUnits::formatWithUnit(unit, -wallet->GetDebit(txin, ISMINE_ALL)) + "<br>";
BOOST_FOREACH(const CTxOut& txout, wtx.vout)
if(wallet->IsMine(txout))
- strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatWithUnit(unit, wallet->GetCredit(txout)) + "<br>";
+ strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatWithUnit(unit, wallet->GetCredit(txout, ISMINE_ALL)) + "<br>";
strHTML += "<br><b>" + tr("Transaction") + ":</b><br>";
strHTML += GUIUtil::HtmlEscape(wtx.ToString(), true);
@@ -290,7 +305,8 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, int vout, int u
strHTML += QString::fromStdString(CBitcoinAddress(address).ToString());
}
strHTML = strHTML + " " + tr("Amount") + "=" + BitcoinUnits::formatWithUnit(unit, vout.nValue);
- strHTML = strHTML + " IsMine=" + (wallet->IsMine(vout) ? tr("true") : tr("false")) + "</li>";
+ strHTML = strHTML + " IsMine=" + (wallet->IsMine(vout) & ISMINE_SPENDABLE ? tr("true") : tr("false")) + "</li>";
+ strHTML = strHTML + " IsWatchOnly=" + (wallet->IsMine(vout) & ISMINE_WATCH_ONLY ? tr("true") : tr("false")) + "</li>";
}
}
}
diff --git a/src/qt/transactiondesc.h b/src/qt/transactiondesc.h
index 92d093b3eb..4bd4293210 100644
--- a/src/qt/transactiondesc.h
+++ b/src/qt/transactiondesc.h
@@ -8,6 +8,8 @@
#include <QObject>
#include <QString>
+class TransactionRecord;
+
class CWallet;
class CWalletTx;
@@ -18,7 +20,7 @@ class TransactionDesc: public QObject
Q_OBJECT
public:
- static QString toHTML(CWallet *wallet, CWalletTx &wtx, int vout, int unit);
+ static QString toHTML(CWallet *wallet, CWalletTx &wtx, TransactionRecord *rec, int unit);
private:
TransactionDesc() {}
diff --git a/src/qt/transactionfilterproxy.cpp b/src/qt/transactionfilterproxy.cpp
index f9546fddb5..7293029787 100644
--- a/src/qt/transactionfilterproxy.cpp
+++ b/src/qt/transactionfilterproxy.cpp
@@ -24,7 +24,7 @@ TransactionFilterProxy::TransactionFilterProxy(QObject *parent) :
typeFilter(ALL_TYPES),
minAmount(0),
limitRows(-1),
- showInactive(true)
+ showInactive(false)
{
}
@@ -39,7 +39,7 @@ bool TransactionFilterProxy::filterAcceptsRow(int sourceRow, const QModelIndex &
qint64 amount = llabs(index.data(TransactionTableModel::AmountRole).toLongLong());
int status = index.data(TransactionTableModel::StatusRole).toInt();
- if(!showInactive && status == TransactionStatus::Conflicted)
+ if(!showInactive && status == TransactionStatus::Conflicted && type == TransactionRecord::Other)
return false;
if(!(TYPE(type) & typeFilter))
return false;
diff --git a/src/qt/transactionrecord.cpp b/src/qt/transactionrecord.cpp
index 5a3728f498..7d29c212b3 100644
--- a/src/qt/transactionrecord.cpp
+++ b/src/qt/transactionrecord.cpp
@@ -5,6 +5,7 @@
#include "transactionrecord.h"
#include "base58.h"
+#include "timedata.h"
#include "wallet.h"
#include <stdint.h>
@@ -32,7 +33,7 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet *
QList<TransactionRecord> parts;
int64_t nTime = wtx.GetTxTime();
int64_t nCredit = wtx.GetCredit(true);
- int64_t nDebit = wtx.GetDebit();
+ int64_t nDebit = wtx.GetDebit(ISMINE_ALL);
int64_t nNet = nCredit - nDebit;
uint256 hash = wtx.GetHash();
std::map<std::string, std::string> mapValue = wtx.mapValue;
@@ -44,12 +45,14 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet *
//
BOOST_FOREACH(const CTxOut& txout, wtx.vout)
{
- if(wallet->IsMine(txout))
+ isminetype mine = wallet->IsMine(txout);
+ if(mine)
{
TransactionRecord sub(hash, nTime);
CTxDestination address;
sub.idx = parts.size(); // sequence number
sub.credit = txout.nValue;
+ sub.involvesWatchAddress = mine == ISMINE_WATCH_ONLY;
if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*wallet, address))
{
// Received by Bitcoin Address
@@ -74,13 +77,22 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet *
}
else
{
- bool fAllFromMe = true;
+ bool involvesWatchAddress = false;
+ isminetype fAllFromMe = ISMINE_SPENDABLE;
BOOST_FOREACH(const CTxIn& txin, wtx.vin)
- fAllFromMe = fAllFromMe && wallet->IsMine(txin);
+ {
+ isminetype mine = wallet->IsMine(txin);
+ if(mine == ISMINE_WATCH_ONLY) involvesWatchAddress = true;
+ if(fAllFromMe > mine) fAllFromMe = mine;
+ }
- bool fAllToMe = true;
+ isminetype fAllToMe = ISMINE_SPENDABLE;
BOOST_FOREACH(const CTxOut& txout, wtx.vout)
- fAllToMe = fAllToMe && wallet->IsMine(txout);
+ {
+ isminetype mine = wallet->IsMine(txout);
+ if(mine == ISMINE_WATCH_ONLY) involvesWatchAddress = true;
+ if(fAllToMe > mine) fAllToMe = mine;
+ }
if (fAllFromMe && fAllToMe)
{
@@ -89,6 +101,7 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet *
parts.append(TransactionRecord(hash, nTime, TransactionRecord::SendToSelf, "",
-(nDebit - nChange), nCredit - nChange));
+ parts.last().involvesWatchAddress = involvesWatchAddress; // maybe pass to TransactionRecord as constructor argument
}
else if (fAllFromMe)
{
@@ -102,6 +115,7 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet *
const CTxOut& txout = wtx.vout[nOut];
TransactionRecord sub(hash, nTime);
sub.idx = parts.size();
+ sub.involvesWatchAddress = involvesWatchAddress;
if(wallet->IsMine(txout))
{
@@ -142,6 +156,7 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet *
// Mixed debit transaction, can't break down payees
//
parts.append(TransactionRecord(hash, nTime, TransactionRecord::Other, "", nNet, 0));
+ parts.last().involvesWatchAddress = involvesWatchAddress;
}
}
@@ -169,6 +184,8 @@ void TransactionRecord::updateStatus(const CWalletTx &wtx)
status.depth = wtx.GetDepthInMainChain();
status.cur_num_blocks = chainActive.Height();
+ status.hasConflicting = false;
+
if (!IsFinalTx(wtx, chainActive.Height() + 1))
{
if (wtx.nLockTime < LOCKTIME_THRESHOLD)
@@ -212,6 +229,7 @@ void TransactionRecord::updateStatus(const CWalletTx &wtx)
if (status.depth < 0)
{
status.status = TransactionStatus::Conflicted;
+ status.hasConflicting = !(wtx.GetConflicts(false).empty());
}
else if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0)
{
@@ -220,6 +238,7 @@ void TransactionRecord::updateStatus(const CWalletTx &wtx)
else if (status.depth == 0)
{
status.status = TransactionStatus::Unconfirmed;
+ status.hasConflicting = !(wtx.GetConflicts(false).empty());
}
else if (status.depth < RecommendedNumConfirmations)
{
@@ -230,13 +249,13 @@ void TransactionRecord::updateStatus(const CWalletTx &wtx)
status.status = TransactionStatus::Confirmed;
}
}
-
}
-bool TransactionRecord::statusUpdateNeeded()
+bool TransactionRecord::statusUpdateNeeded(int64_t nConflictsReceived)
{
AssertLockHeld(cs_main);
- return status.cur_num_blocks != chainActive.Height();
+ return (status.cur_num_blocks != chainActive.Height() ||
+ status.cur_num_conflicts != nConflictsReceived);
}
QString TransactionRecord::getTxID() const
diff --git a/src/qt/transactionrecord.h b/src/qt/transactionrecord.h
index af6fd403b3..d3cfa77d97 100644
--- a/src/qt/transactionrecord.h
+++ b/src/qt/transactionrecord.h
@@ -19,9 +19,17 @@ class TransactionStatus
{
public:
TransactionStatus():
- countsForBalance(false), sortKey(""),
- matures_in(0), status(Offline), depth(0), open_for(0), cur_num_blocks(-1)
- { }
+ countsForBalance(false),
+ sortKey(""),
+ matures_in(0),
+ status(Offline),
+ hasConflicting(false),
+ depth(0),
+ open_for(0),
+ cur_num_blocks(-1),
+ cur_num_conflicts(-1)
+ {
+ }
enum Status {
Confirmed, /**< Have 6 or more confirmations (normal tx) or fully mature (mined tx) **/
@@ -51,6 +59,10 @@ public:
/** @name Reported status
@{*/
Status status;
+
+ // Has conflicting transactions spending same prevout
+ bool hasConflicting;
+
qint64 depth;
qint64 open_for; /**< Timestamp if status==OpenUntilDate, otherwise number
of additional blocks that need to be mined before
@@ -59,6 +71,10 @@ public:
/** Current number of blocks (to know whether cached status is still valid) */
int cur_num_blocks;
+
+ /** Number of conflicts received into wallet as of last status update */
+ int64_t cur_num_conflicts;
+
};
/** UI model for a transaction. A core transaction can be represented by multiple UI transactions if it has
@@ -121,6 +137,9 @@ public:
/** Status: can change with block chain update */
TransactionStatus status;
+ /** Whether the transaction was sent/received with a watch-only address */
+ bool involvesWatchAddress;
+
/** Return the unique identifier for this transaction (part) */
QString getTxID() const;
@@ -133,7 +152,7 @@ public:
/** Return whether a status update is needed.
*/
- bool statusUpdateNeeded();
+ bool statusUpdateNeeded(int64_t nConflictsReceived);
};
#endif // TRANSACTIONRECORD_H
diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp
index 8cf2b0a1b1..3605cc1bad 100644
--- a/src/qt/transactiontablemodel.cpp
+++ b/src/qt/transactiontablemodel.cpp
@@ -130,12 +130,12 @@ public:
case CT_NEW:
if(inModel)
{
- qDebug() << "TransactionTablePriv::updateWallet : Warning: Got CT_NEW, but transaction is already in model";
+ qWarning() << "TransactionTablePriv::updateWallet : Warning: Got CT_NEW, but transaction is already in model";
break;
}
if(!inWallet)
{
- qDebug() << "TransactionTablePriv::updateWallet : Warning: Got CT_NEW, but transaction is not in wallet";
+ qWarning() << "TransactionTablePriv::updateWallet : Warning: Got CT_NEW, but transaction is not in wallet";
break;
}
if(showTransaction)
@@ -159,7 +159,7 @@ public:
case CT_DELETED:
if(!inModel)
{
- qDebug() << "TransactionTablePriv::updateWallet : Warning: Got CT_DELETED, but transaction is not in model";
+ qWarning() << "TransactionTablePriv::updateWallet : Warning: Got CT_DELETED, but transaction is not in model";
break;
}
// Removed -- remove entire transaction from table
@@ -168,8 +168,7 @@ public:
parent->endRemoveRows();
break;
case CT_UPDATED:
- // Miscellaneous updates -- nothing to do, status update will take care of this, and is only computed for
- // visible transactions.
+ emit parent->dataChanged(parent->index(lowerIndex, parent->Status), parent->index(upperIndex-1, parent->Amount));
break;
}
}
@@ -190,20 +189,21 @@ public:
// stuck if the core is holding the locks for a longer time - for
// example, during a wallet rescan.
//
- // If a status update is needed (blocks came in since last check),
- // update the status of this transaction from the wallet. Otherwise,
+ // If a status update is needed (blocks or conflicts came in since last check),
+ // update the status of this transaction from the wallet. Otherwise,
// simply re-use the cached status.
TRY_LOCK(cs_main, lockMain);
if(lockMain)
{
TRY_LOCK(wallet->cs_wallet, lockWallet);
- if(lockWallet && rec->statusUpdateNeeded())
+ if(lockWallet && rec->statusUpdateNeeded(wallet->nConflictsReceived))
{
std::map<uint256, CWalletTx>::iterator mi = wallet->mapWallet.find(rec->hash);
if(mi != wallet->mapWallet.end())
{
rec->updateStatus(mi->second);
+ rec->status.cur_num_conflicts = wallet->nConflictsReceived;
}
}
}
@@ -222,7 +222,7 @@ public:
std::map<uint256, CWalletTx>::iterator mi = wallet->mapWallet.find(rec->hash);
if(mi != wallet->mapWallet.end())
{
- return TransactionDesc::toHTML(wallet, mi->second, rec->idx, unit);
+ return TransactionDesc::toHTML(wallet, mi->second, rec, unit);
}
}
return QString("");
@@ -235,8 +235,7 @@ TransactionTableModel::TransactionTableModel(CWallet* wallet, WalletModel *paren
walletModel(parent),
priv(new TransactionTablePriv(wallet, this))
{
- columns << QString() << tr("Date") << tr("Type") << tr("Address") << tr("Amount");
-
+ columns << QString() << tr("Date") << tr("Type") << tr("Address") << BitcoinUnits::getAmountColumnTitle(walletModel->getOptionsModel()->getDisplayUnit());
priv->refreshWallet();
connect(walletModel->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit()));
@@ -247,6 +246,13 @@ TransactionTableModel::~TransactionTableModel()
delete priv;
}
+/** Updates the column title to "Amount (DisplayUnit)" and emits headerDataChanged() signal for table headers to react. */
+void TransactionTableModel::updateAmountColumnTitle()
+{
+ columns[Amount] = BitcoinUnits::getAmountColumnTitle(walletModel->getOptionsModel()->getDisplayUnit());
+ emit headerDataChanged(Qt::Horizontal,Amount,Amount);
+}
+
void TransactionTableModel::updateTransaction(const QString &hash, int status)
{
uint256 updated;
@@ -363,6 +369,8 @@ QString TransactionTableModel::formatTxType(const TransactionRecord *wtx) const
return tr("Payment to yourself");
case TransactionRecord::Generated:
return tr("Mined");
+ case TransactionRecord::Other:
+ return tr("Other");
default:
return QString();
}
@@ -388,19 +396,22 @@ QVariant TransactionTableModel::txAddressDecoration(const TransactionRecord *wtx
QString TransactionTableModel::formatTxToAddress(const TransactionRecord *wtx, bool tooltip) const
{
+ // mark transactions involving watch-only addresses:
+ QString watchAddress = wtx->involvesWatchAddress ? " (w) " : "";
+
switch(wtx->type)
{
case TransactionRecord::RecvFromOther:
- return QString::fromStdString(wtx->address);
+ return QString::fromStdString(wtx->address) + watchAddress;
case TransactionRecord::RecvWithAddress:
case TransactionRecord::SendToAddress:
case TransactionRecord::Generated:
- return lookupAddress(wtx->address, tooltip);
+ return lookupAddress(wtx->address, tooltip) + watchAddress;
case TransactionRecord::SendToOther:
- return QString::fromStdString(wtx->address);
+ return QString::fromStdString(wtx->address) + watchAddress;
case TransactionRecord::SendToSelf:
default:
- return tr("(n/a)");
+ return tr("(n/a)") + watchAddress;
}
}
@@ -535,7 +546,13 @@ QVariant TransactionTableModel::data(const QModelIndex &index, int role) const
return formatTooltip(rec);
case Qt::TextAlignmentRole:
return column_alignments[index.column()];
+ case Qt::BackgroundColorRole:
+ if (rec->status.hasConflicting)
+ return COLOR_HASCONFLICTING_BG;
+ break;
case Qt::ForegroundRole:
+ if (rec->status.hasConflicting)
+ return COLOR_HASCONFLICTING;
// Non-confirmed (but not immature) as transactions are grey
if(!rec->status.countsForBalance && rec->status.status != TransactionStatus::Immature)
{
@@ -624,5 +641,6 @@ QModelIndex TransactionTableModel::index(int row, int column, const QModelIndex
void TransactionTableModel::updateDisplayUnit()
{
// emit dataChanged to update Amount column with the current unit
+ updateAmountColumnTitle();
emit dataChanged(index(0, Amount), index(priv->size()-1, Amount));
}
diff --git a/src/qt/transactiontablemodel.h b/src/qt/transactiontablemodel.h
index 333e6bc6ed..e8b6ed065d 100644
--- a/src/qt/transactiontablemodel.h
+++ b/src/qt/transactiontablemodel.h
@@ -87,6 +87,8 @@ public slots:
void updateTransaction(const QString &hash, int status);
void updateConfirmations();
void updateDisplayUnit();
+ /** Updates the column title to "Amount (DisplayUnit)" and emits headerDataChanged() signal for table headers to react. */
+ void updateAmountColumnTitle();
friend class TransactionTablePriv;
};
diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp
index d4d29416ca..d6d210a561 100644
--- a/src/qt/transactionview.cpp
+++ b/src/qt/transactionview.cpp
@@ -309,7 +309,7 @@ void TransactionView::exportClicked()
writer.addColumn(tr("Type"), TransactionTableModel::Type, Qt::EditRole);
writer.addColumn(tr("Label"), 0, TransactionTableModel::LabelRole);
writer.addColumn(tr("Address"), 0, TransactionTableModel::AddressRole);
- writer.addColumn(tr("Amount"), 0, TransactionTableModel::FormattedAmountRole);
+ writer.addColumn(BitcoinUnits::getAmountColumnTitle(model->getOptionsModel()->getDisplayUnit()), 0, TransactionTableModel::FormattedAmountRole);
writer.addColumn(tr("ID"), 0, TransactionTableModel::TxIDRole);
if(!writer.write()) {
diff --git a/src/qt/utilitydialog.cpp b/src/qt/utilitydialog.cpp
index 01b710e876..5fb0da145d 100644
--- a/src/qt/utilitydialog.cpp
+++ b/src/qt/utilitydialog.cpp
@@ -4,7 +4,6 @@
#include "utilitydialog.h"
-#include "ui_aboutdialog.h"
#include "ui_helpmessagedialog.h"
#include "bitcoingui.h"
@@ -16,72 +15,64 @@
#include "util.h"
#include <QLabel>
+#include <QRegExp>
#include <QVBoxLayout>
-/** "About" dialog box */
-AboutDialog::AboutDialog(QWidget *parent) :
+/** "Help message" or "About" dialog box */
+HelpMessageDialog::HelpMessageDialog(QWidget *parent, bool about) :
QDialog(parent),
- ui(new Ui::AboutDialog)
+ ui(new Ui::HelpMessageDialog)
{
ui->setupUi(this);
+ GUIUtil::restoreWindowGeometry("nHelpMessageDialogWindow", this->size(), this);
- // Set current copyright year
- ui->copyrightLabel->setText(tr("Copyright") + QString(" &copy; 2009-%1 ").arg(COPYRIGHT_YEAR) + tr("The Bitcoin Core developers"));
-}
-
-void AboutDialog::setModel(ClientModel *model)
-{
- if(model)
- {
- QString version = model->formatFullVersion();
- /* On x86 add a bit specifier to the version so that users can distinguish between
- * 32 and 64 bit builds. On other architectures, 32/64 bit may be more ambigious.
- */
+ QString version = tr("Bitcoin Core") + " " + tr("version") + " " + QString::fromStdString(FormatFullVersion());
+ /* On x86 add a bit specifier to the version so that users can distinguish between
+ * 32 and 64 bit builds. On other architectures, 32/64 bit may be more ambigious.
+ */
#if defined(__x86_64__)
- version += " " + tr("(%1-bit)").arg(64);
+ version += " " + tr("(%1-bit)").arg(64);
#elif defined(__i386__ )
- version += " " + tr("(%1-bit)").arg(32);
+ version += " " + tr("(%1-bit)").arg(32);
#endif
- ui->versionLabel->setText(version);
- }
-}
-
-AboutDialog::~AboutDialog()
-{
- delete ui;
-}
-
-void AboutDialog::on_buttonBox_accepted()
-{
- close();
-}
-
-/** "Help message" dialog box */
-HelpMessageDialog::HelpMessageDialog(QWidget *parent) :
- QDialog(parent),
- ui(new Ui::HelpMessageDialog)
-{
- ui->setupUi(this);
- GUIUtil::restoreWindowGeometry("nHelpMessageDialogWindow", this->size(), this);
-
- header = tr("Bitcoin Core") + " " + tr("version") + " " +
- QString::fromStdString(FormatFullVersion()) + "\n\n" +
- tr("Usage:") + "\n" +
- " bitcoin-qt [" + tr("command-line options") + "] " + "\n";
-
- coreOptions = QString::fromStdString(HelpMessage(HMM_BITCOIN_QT));
-
- uiOptions = tr("UI options") + ":\n" +
- " -choosedatadir " + tr("Choose data directory on startup (default: 0)") + "\n" +
- " -lang=<lang> " + tr("Set language, for example \"de_DE\" (default: system locale)") + "\n" +
- " -min " + tr("Start minimized") + "\n" +
- " -rootcertificates=<file> " + tr("Set SSL root certificates for payment request (default: -system-)") + "\n" +
- " -splash " + tr("Show splash screen on startup (default: 1)");
- ui->helpMessageLabel->setFont(GUIUtil::bitcoinAddressFont());
-
- // Set help message text
- ui->helpMessageLabel->setText(header + "\n" + coreOptions + "\n" + uiOptions);
+ if (about)
+ {
+ setWindowTitle(tr("About Bitcoin Core"));
+
+ /// HTML-format the license message from the core
+ QString licenseInfo = QString::fromStdString(LicenseInfo());
+ QString licenseInfoHTML = licenseInfo;
+ // Make URLs clickable
+ QRegExp uri("<(.*)>", Qt::CaseSensitive, QRegExp::RegExp2);
+ uri.setMinimal(true); // use non-greedy matching
+ licenseInfoHTML.replace(uri, "<a href=\"\\1\">\\1</a>");
+ // Replace newlines with HTML breaks
+ licenseInfoHTML.replace("\n\n", "<br><br>");
+
+ ui->helpMessageLabel->setTextFormat(Qt::RichText);
+ ui->scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
+ text = version + "\n" + licenseInfo;
+ ui->helpMessageLabel->setText(version + "<br><br>" + licenseInfoHTML);
+ ui->helpMessageLabel->setWordWrap(true);
+ } else {
+ setWindowTitle(tr("Command-line options"));
+ QString header = tr("Usage:") + "\n" +
+ " bitcoin-qt [" + tr("command-line options") + "] " + "\n";
+
+ QString coreOptions = QString::fromStdString(HelpMessage(HMM_BITCOIN_QT));
+
+ QString uiOptions = tr("UI options") + ":\n" +
+ " -choosedatadir " + tr("Choose data directory on startup (default: 0)") + "\n" +
+ " -lang=<lang> " + tr("Set language, for example \"de_DE\" (default: system locale)") + "\n" +
+ " -min " + tr("Start minimized") + "\n" +
+ " -rootcertificates=<file> " + tr("Set SSL root certificates for payment request (default: -system-)") + "\n" +
+ " -splash " + tr("Show splash screen on startup (default: 1)");
+
+ ui->helpMessageLabel->setFont(GUIUtil::bitcoinAddressFont());
+ text = version + "\n" + header + "\n" + coreOptions + "\n" + uiOptions;
+ ui->helpMessageLabel->setText(text);
+ }
}
HelpMessageDialog::~HelpMessageDialog()
@@ -93,18 +84,17 @@ HelpMessageDialog::~HelpMessageDialog()
void HelpMessageDialog::printToConsole()
{
// On other operating systems, the expected action is to print the message to the console.
- QString strUsage = header + "\n" + coreOptions + "\n" + uiOptions + "\n";
- fprintf(stdout, "%s", strUsage.toStdString().c_str());
+ fprintf(stdout, "%s\n", qPrintable(text));
}
void HelpMessageDialog::showOrPrint()
{
#if defined(WIN32)
- // On Windows, show a message box, as there is no stderr/stdout in windowed applications
- exec();
+ // On Windows, show a message box, as there is no stderr/stdout in windowed applications
+ exec();
#else
- // On other operating systems, print help text to console
- printToConsole();
+ // On other operating systems, print help text to console
+ printToConsole();
#endif
}
@@ -127,6 +117,7 @@ void ShutdownWindow::showShutdownWindow(BitcoinGUI *window)
tr("Bitcoin Core is shutting down...") + "<br /><br />" +
tr("Do not shut down the computer until this window disappears.")));
shutdownWindow->setLayout(layout);
+ shutdownWindow->setWindowTitle(window->windowTitle());
// Center shutdown window at where main window was
const QPoint global = window->mapToGlobal(window->rect().center());
diff --git a/src/qt/utilitydialog.h b/src/qt/utilitydialog.h
index 874daf6a7f..154bb70b8b 100644
--- a/src/qt/utilitydialog.h
+++ b/src/qt/utilitydialog.h
@@ -12,35 +12,16 @@ class BitcoinGUI;
class ClientModel;
namespace Ui {
- class AboutDialog;
class HelpMessageDialog;
}
-/** "About" dialog box */
-class AboutDialog : public QDialog
-{
- Q_OBJECT
-
-public:
- explicit AboutDialog(QWidget *parent);
- ~AboutDialog();
-
- void setModel(ClientModel *model);
-
-private:
- Ui::AboutDialog *ui;
-
-private slots:
- void on_buttonBox_accepted();
-};
-
/** "Help message" dialog box */
class HelpMessageDialog : public QDialog
{
Q_OBJECT
public:
- explicit HelpMessageDialog(QWidget *parent);
+ explicit HelpMessageDialog(QWidget *parent, bool about);
~HelpMessageDialog();
void printToConsole();
@@ -48,9 +29,7 @@ public:
private:
Ui::HelpMessageDialog *ui;
- QString header;
- QString coreOptions;
- QString uiOptions;
+ QString text;
private slots:
void on_okButton_accepted();
diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp
index 37d82ec063..7317c32766 100644
--- a/src/qt/walletmodel.cpp
+++ b/src/qt/walletmodel.cpp
@@ -24,6 +24,8 @@
#include <QSet>
#include <QTimer>
+using namespace std;
+
WalletModel::WalletModel(CWallet *wallet, OptionsModel *optionsModel, QObject *parent) :
QObject(parent), wallet(wallet), optionsModel(optionsModel), addressTableModel(0),
transactionTableModel(0),
@@ -58,7 +60,8 @@ qint64 WalletModel::getBalance(const CCoinControl *coinControl) const
std::vector<COutput> vCoins;
wallet->AvailableCoins(vCoins, true, coinControl);
BOOST_FOREACH(const COutput& out, vCoins)
- nBalance += out.tx->vout[out.i].nValue;
+ if(out.fSpendable)
+ nBalance += out.tx->vout[out.i].nValue;
return nBalance;
}
@@ -76,6 +79,21 @@ qint64 WalletModel::getImmatureBalance() const
return wallet->GetImmatureBalance();
}
+qint64 WalletModel::getWatchBalance() const
+{
+ return wallet->GetWatchOnlyBalance();
+}
+
+qint64 WalletModel::getWatchUnconfirmedBalance() const
+{
+ return wallet->GetUnconfirmedWatchOnlyBalance();
+}
+
+qint64 WalletModel::getWatchImmatureBalance() const
+{
+ return wallet->GetImmatureWatchOnlyBalance();
+}
+
int WalletModel::getNumTransactions() const
{
int numTransactions = 0;
@@ -124,18 +142,34 @@ void WalletModel::checkBalanceChanged()
qint64 newBalance = getBalance();
qint64 newUnconfirmedBalance = getUnconfirmedBalance();
qint64 newImmatureBalance = getImmatureBalance();
+ qint64 newWatchOnlyBalance = getWatchBalance();
+ qint64 newWatchUnconfBalance = getWatchUnconfirmedBalance();
+ qint64 newWatchImmatureBalance = getWatchImmatureBalance();
- if(cachedBalance != newBalance || cachedUnconfirmedBalance != newUnconfirmedBalance || cachedImmatureBalance != newImmatureBalance)
+ if(cachedBalance != newBalance || cachedUnconfirmedBalance != newUnconfirmedBalance || cachedImmatureBalance != newImmatureBalance ||
+ cachedWatchOnlyBalance != newWatchOnlyBalance || cachedWatchUnconfBalance != newWatchUnconfBalance || cachedWatchImmatureBalance != newWatchImmatureBalance)
{
cachedBalance = newBalance;
cachedUnconfirmedBalance = newUnconfirmedBalance;
cachedImmatureBalance = newImmatureBalance;
- emit balanceChanged(newBalance, newUnconfirmedBalance, newImmatureBalance);
+ cachedWatchOnlyBalance = newWatchOnlyBalance;
+ cachedWatchUnconfBalance = newWatchUnconfBalance;
+ cachedWatchImmatureBalance = newWatchImmatureBalance;
+ emit balanceChanged(newBalance, newUnconfirmedBalance, newImmatureBalance,
+ newWatchOnlyBalance, newWatchUnconfBalance, newWatchImmatureBalance);
}
}
void WalletModel::updateTransaction(const QString &hash, int status)
{
+ if (status == CT_GOT_CONFLICT)
+ {
+ emit message(tr("Conflict Received"),
+ tr("WARNING: Transaction may never be confirmed. Its input was seen being spent by another transaction on the network. Wait for confirmation!"),
+ CClientUIInterface::MSG_WARNING);
+ return;
+ }
+
if(transactionTableModel)
transactionTableModel->updateTransaction(hash, status);
@@ -231,12 +265,6 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact
return AmountExceedsBalance;
}
- if((total + nTransactionFee) > nBalance)
- {
- transaction.setTransactionFee(nTransactionFee);
- return SendCoinsReturn(AmountWithFeeExceedsBalance);
- }
-
{
LOCK2(cs_main, wallet->cs_wallet);
@@ -539,7 +567,7 @@ void WalletModel::getOutputs(const std::vector<COutPoint>& vOutpoints, std::vect
if (!wallet->mapWallet.count(outpoint.hash)) continue;
int nDepth = wallet->mapWallet[outpoint.hash].GetDepthInMainChain();
if (nDepth < 0) continue;
- COutput out(&wallet->mapWallet[outpoint.hash], outpoint.n, nDepth);
+ COutput out(&wallet->mapWallet[outpoint.hash], outpoint.n, nDepth, true);
vOutputs.push_back(out);
}
}
@@ -566,7 +594,7 @@ void WalletModel::listCoins(std::map<QString, std::vector<COutput> >& mapCoins)
if (!wallet->mapWallet.count(outpoint.hash)) continue;
int nDepth = wallet->mapWallet[outpoint.hash].GetDepthInMainChain();
if (nDepth < 0) continue;
- COutput out(&wallet->mapWallet[outpoint.hash], outpoint.n, nDepth);
+ COutput out(&wallet->mapWallet[outpoint.hash], outpoint.n, nDepth, true);
vCoins.push_back(out);
}
@@ -577,11 +605,12 @@ void WalletModel::listCoins(std::map<QString, std::vector<COutput> >& mapCoins)
while (wallet->IsChange(cout.tx->vout[cout.i]) && cout.tx->vin.size() > 0 && wallet->IsMine(cout.tx->vin[0]))
{
if (!wallet->mapWallet.count(cout.tx->vin[0].prevout.hash)) break;
- cout = COutput(&wallet->mapWallet[cout.tx->vin[0].prevout.hash], cout.tx->vin[0].prevout.n, 0);
+ cout = COutput(&wallet->mapWallet[cout.tx->vin[0].prevout.hash], cout.tx->vin[0].prevout.n, 0, true);
}
CTxDestination address;
- if(!ExtractDestination(cout.tx->vout[cout.i].scriptPubKey, address)) continue;
+ if(!out.fSpendable || !ExtractDestination(cout.tx->vout[cout.i].scriptPubKey, address))
+ continue;
mapCoins[CBitcoinAddress(address).ToString().c_str()].push_back(out);
}
}
diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h
index ccf590aaed..7ad54ff8e6 100644
--- a/src/qt/walletmodel.h
+++ b/src/qt/walletmodel.h
@@ -128,6 +128,9 @@ public:
qint64 getBalance(const CCoinControl *coinControl = NULL) const;
qint64 getUnconfirmedBalance() const;
qint64 getImmatureBalance() const;
+ qint64 getWatchBalance() const;
+ qint64 getWatchUnconfirmedBalance() const;
+ qint64 getWatchImmatureBalance() const;
int getNumTransactions() const;
EncryptionStatus getEncryptionStatus() const;
@@ -206,6 +209,9 @@ private:
qint64 cachedBalance;
qint64 cachedUnconfirmedBalance;
qint64 cachedImmatureBalance;
+ qint64 cachedWatchOnlyBalance;
+ qint64 cachedWatchUnconfBalance;
+ qint64 cachedWatchImmatureBalance;
qint64 cachedNumTransactions;
EncryptionStatus cachedEncryptionStatus;
int cachedNumBlocks;
@@ -218,7 +224,8 @@ private:
signals:
// Signal that balance in wallet changed
- void balanceChanged(qint64 balance, qint64 unconfirmedBalance, qint64 immatureBalance);
+ void balanceChanged(qint64 balance, qint64 unconfirmedBalance, qint64 immatureBalance,
+ qint64 watchOnlyBalance, qint64 watchUnconfBalance, qint64 watchImmatureBalance);
// Number of transactions in wallet changed
void numTransactionsChanged(int count);
diff --git a/src/qt/winshutdownmonitor.cpp b/src/qt/winshutdownmonitor.cpp
index b7526f0ae4..a06f42f66e 100644
--- a/src/qt/winshutdownmonitor.cpp
+++ b/src/qt/winshutdownmonitor.cpp
@@ -6,11 +6,14 @@
#if defined(Q_OS_WIN) && QT_VERSION >= 0x050000
#include "init.h"
+#include "util.h"
#include <windows.h>
#include <QDebug>
+#include <openssl/rand.h>
+
// If we don't want a message to be processed by Qt, return true and set result to
// the value that the window procedure should return. Otherwise return false.
bool WinShutdownMonitor::nativeEventFilter(const QByteArray &eventType, void *pMessage, long *pnResult)
@@ -19,6 +22,16 @@ bool WinShutdownMonitor::nativeEventFilter(const QByteArray &eventType, void *pM
MSG *pMsg = static_cast<MSG *>(pMessage);
+ // Seed OpenSSL PRNG with Windows event data (e.g. mouse movements and other user interactions)
+ if (RAND_event(pMsg->message, pMsg->wParam, pMsg->lParam) == 0) {
+ // Warn only once as this is performance-critical
+ static bool warned = false;
+ if (!warned) {
+ LogPrint("%s: OpenSSL RAND_event() failed to seed OpenSSL PRNG with enough data.\n", __func__);
+ warned = true;
+ }
+ }
+
switch(pMsg->message)
{
case WM_QUERYENDSESSION:
@@ -45,13 +58,13 @@ void WinShutdownMonitor::registerShutdownBlockReason(const QString& strReason, c
typedef BOOL (WINAPI *PSHUTDOWNBRCREATE)(HWND, LPCWSTR);
PSHUTDOWNBRCREATE shutdownBRCreate = (PSHUTDOWNBRCREATE)GetProcAddress(GetModuleHandleA("User32.dll"), "ShutdownBlockReasonCreate");
if (shutdownBRCreate == NULL) {
- qDebug() << "registerShutdownBlockReason : GetProcAddress for ShutdownBlockReasonCreate failed";
+ qWarning() << "registerShutdownBlockReason: GetProcAddress for ShutdownBlockReasonCreate failed";
return;
}
if (shutdownBRCreate(mainWinId, strReason.toStdWString().c_str()))
- qDebug() << "registerShutdownBlockReason : Successfully registered: " + strReason;
+ qWarning() << "registerShutdownBlockReason: Successfully registered: " + strReason;
else
- qDebug() << "registerShutdownBlockReason : Failed to register: " + strReason;
+ qWarning() << "registerShutdownBlockReason: Failed to register: " + strReason;
}
#endif
diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp
index a303b5d3ef..a67f266a13 100644
--- a/src/rpcblockchain.cpp
+++ b/src/rpcblockchain.cpp
@@ -3,10 +3,10 @@
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "rpcserver.h"
+#include "checkpoints.h"
#include "main.h"
+#include "rpcserver.h"
#include "sync.h"
-#include "checkpoints.h"
#include <stdint.h>
@@ -66,7 +66,7 @@ Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex)
result.push_back(Pair("tx", txs));
result.push_back(Pair("time", block.GetBlockTime()));
result.push_back(Pair("nonce", (uint64_t)block.nNonce));
- result.push_back(Pair("bits", HexBits(block.nBits)));
+ result.push_back(Pair("bits", strprintf("%08x", block.nBits)));
result.push_back(Pair("difficulty", GetDifficulty(blockindex)));
result.push_back(Pair("chainwork", blockindex->nChainWork.GetHex()));
@@ -427,7 +427,7 @@ Value verifychain(const Array& params, bool fHelp)
if (params.size() > 1)
nCheckDepth = params[1].get_int();
- return VerifyDB(nCheckLevel, nCheckDepth);
+ return CVerifyDB().VerifyDB(nCheckLevel, nCheckDepth);
}
Value getblockchaininfo(const Array& params, bool fHelp)
@@ -438,7 +438,7 @@ Value getblockchaininfo(const Array& params, bool fHelp)
"Returns an object containing various state info regarding block chain processing.\n"
"\nResult:\n"
"{\n"
- " \"chain\": \"xxxx\", (string) current chain (main, testnet3, regtest)\n"
+ " \"chain\": \"xxxx\", (string) current network name as defined in BIP70 (main, test, regtest)\n"
" \"blocks\": xxxxxx, (numeric) the current number of blocks processed in the server\n"
" \"bestblockhash\": \"...\", (string) the hash of the currently best block\n"
" \"difficulty\": xxxxxx, (numeric) the current difficulty\n"
@@ -450,18 +450,12 @@ Value getblockchaininfo(const Array& params, bool fHelp)
+ HelpExampleRpc("getblockchaininfo", "")
);
- proxyType proxy;
- GetProxy(NET_IPV4, proxy);
-
Object obj;
- std::string chain = Params().DataDir();
- if(chain.empty())
- chain = "main";
- obj.push_back(Pair("chain", chain));
- obj.push_back(Pair("blocks", (int)chainActive.Height()));
- obj.push_back(Pair("bestblockhash", chainActive.Tip()->GetBlockHash().GetHex()));
- obj.push_back(Pair("difficulty", (double)GetDifficulty()));
- obj.push_back(Pair("verificationprogress", Checkpoints::GuessVerificationProgress(chainActive.Tip())));
- obj.push_back(Pair("chainwork", chainActive.Tip()->nChainWork.GetHex()));
+ obj.push_back(Pair("chain", Params().NetworkIDString()));
+ obj.push_back(Pair("blocks", (int)chainActive.Height()));
+ obj.push_back(Pair("bestblockhash", chainActive.Tip()->GetBlockHash().GetHex()));
+ obj.push_back(Pair("difficulty", (double)GetDifficulty()));
+ obj.push_back(Pair("verificationprogress", Checkpoints::GuessVerificationProgress(chainActive.Tip())));
+ obj.push_back(Pair("chainwork", chainActive.Tip()->nChainWork.GetHex()));
return obj;
}
diff --git a/src/rpcclient.cpp b/src/rpcclient.cpp
index 4f3c39ce9b..5edeecf933 100644
--- a/src/rpcclient.cpp
+++ b/src/rpcclient.cpp
@@ -3,6 +3,7 @@
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include <set>
#include "rpcclient.h"
#include "rpcprotocol.h"
@@ -12,269 +13,128 @@
#include <stdint.h>
-#include <boost/algorithm/string.hpp>
-#include <boost/asio.hpp>
-#include <boost/asio/ssl.hpp>
-#include <boost/bind.hpp>
-#include <boost/filesystem.hpp>
-#include <boost/foreach.hpp>
-#include <boost/iostreams/concepts.hpp>
-#include <boost/iostreams/stream.hpp>
-#include <boost/shared_ptr.hpp>
-#include "json/json_spirit_writer_template.h"
-
using namespace std;
-using namespace boost;
-using namespace boost::asio;
using namespace json_spirit;
-Object CallRPC(const string& strMethod, const Array& params)
+class CRPCConvertParam
{
- if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
- throw runtime_error(strprintf(
- _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
- "If the file does not exist, create it with owner-readable-only file permissions."),
- GetConfigFile().string().c_str()));
-
- // Connect to localhost
- bool fUseSSL = GetBoolArg("-rpcssl", false);
- asio::io_service io_service;
- ssl::context context(io_service, ssl::context::sslv23);
- context.set_options(ssl::context::no_sslv2);
- asio::ssl::stream<asio::ip::tcp::socket> sslStream(io_service, context);
- SSLIOStreamDevice<asio::ip::tcp> d(sslStream, fUseSSL);
- iostreams::stream< SSLIOStreamDevice<asio::ip::tcp> > stream(d);
-
- bool fWait = GetBoolArg("-rpcwait", false); // -rpcwait means try until server has started
- do {
- bool fConnected = d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", itostr(Params().RPCPort())));
- if (fConnected) break;
- if (fWait)
- MilliSleep(1000);
- else
- throw runtime_error("couldn't connect to server");
- } while (fWait);
-
- // HTTP basic authentication
- string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
- map<string, string> mapRequestHeaders;
- mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
-
- // Send request
- string strRequest = JSONRPCRequest(strMethod, params, 1);
- string strPost = HTTPPost(strRequest, mapRequestHeaders);
- stream << strPost << std::flush;
+public:
+ std::string methodName; // method whose params want conversion
+ int paramIdx; // 0-based idx of param to convert
+};
- // Receive HTTP reply status
- int nProto = 0;
- int nStatus = ReadHTTPStatus(stream, nProto);
-
- // Receive HTTP reply message headers and body
- map<string, string> mapHeaders;
- string strReply;
- ReadHTTPMessage(stream, mapHeaders, strReply, nProto);
-
- if (nStatus == HTTP_UNAUTHORIZED)
- throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
- else if (nStatus >= 400 && nStatus != HTTP_BAD_REQUEST && nStatus != HTTP_NOT_FOUND && nStatus != HTTP_INTERNAL_SERVER_ERROR)
- throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
- else if (strReply.empty())
- throw runtime_error("no response from server");
+static const CRPCConvertParam vRPCConvertParams[] =
+{
+ { "stop", 0 },
+ { "getaddednodeinfo", 0 },
+ { "setgenerate", 0 },
+ { "setgenerate", 1 },
+ { "getnetworkhashps", 0 },
+ { "getnetworkhashps", 1 },
+ { "sendtoaddress", 1 },
+ { "settxfee", 0 },
+ { "getreceivedbyaddress", 1 },
+ { "getreceivedbyaccount", 1 },
+ { "listreceivedbyaddress", 0 },
+ { "listreceivedbyaddress", 1 },
+ { "listreceivedbyaddress", 2 },
+ { "listreceivedbyaccount", 0 },
+ { "listreceivedbyaccount", 1 },
+ { "listreceivedbyaccount", 2 },
+ { "getbalance", 1 },
+ { "getbalance", 2 },
+ { "getblockhash", 0 },
+ { "move", 2 },
+ { "move", 3 },
+ { "sendfrom", 2 },
+ { "sendfrom", 3 },
+ { "listtransactions", 1 },
+ { "listtransactions", 2 },
+ { "listtransactions", 3 },
+ { "listaccounts", 0 },
+ { "listaccounts", 1 },
+ { "walletpassphrase", 1 },
+ { "getblocktemplate", 0 },
+ { "listsinceblock", 1 },
+ { "listsinceblock", 2 },
+ { "sendmany", 1 },
+ { "sendmany", 2 },
+ { "addmultisigaddress", 0 },
+ { "addmultisigaddress", 1 },
+ { "createmultisig", 0 },
+ { "createmultisig", 1 },
+ { "listunspent", 0 },
+ { "listunspent", 1 },
+ { "listunspent", 2 },
+ { "getblock", 1 },
+ { "getrawtransaction", 1 },
+ { "createrawtransaction", 0 },
+ { "createrawtransaction", 1 },
+ { "signrawtransaction", 1 },
+ { "signrawtransaction", 2 },
+ { "sendrawtransaction", 1 },
+ { "gettxout", 1 },
+ { "gettxout", 2 },
+ { "lockunspent", 0 },
+ { "lockunspent", 1 },
+ { "importprivkey", 2 },
+ { "importaddress", 2 },
+ { "verifychain", 0 },
+ { "verifychain", 1 },
+ { "keypoolrefill", 0 },
+ { "getrawmempool", 0 },
+ { "estimatefee", 0 },
+ { "estimatepriority", 0 },
+};
+
+class CRPCConvertTable
+{
+private:
+ std::set<std::pair<std::string, int> > members;
- // Parse reply
- Value valReply;
- if (!read_string(strReply, valReply))
- throw runtime_error("couldn't parse reply from server");
- const Object& reply = valReply.get_obj();
- if (reply.empty())
- throw runtime_error("expected reply to have result, error and id properties");
+public:
+ CRPCConvertTable();
- return reply;
-}
+ bool convert(const std::string& method, int idx) {
+ return (members.count(std::make_pair(method, idx)) > 0);
+ }
+};
-template<typename T>
-void ConvertTo(Value& value, bool fAllowNull=false)
+CRPCConvertTable::CRPCConvertTable()
{
- if (fAllowNull && value.type() == null_type)
- return;
- if (value.type() == str_type)
- {
- // reinterpret string as unquoted json value
- Value value2;
- string strJSON = value.get_str();
- if (!read_string(strJSON, value2))
- throw runtime_error(string("Error parsing JSON:")+strJSON);
- ConvertTo<T>(value2, fAllowNull);
- value = value2;
- }
- else
- {
- value = value.get_value<T>();
+ const unsigned int n_elem =
+ (sizeof(vRPCConvertParams) / sizeof(vRPCConvertParams[0]));
+
+ for (unsigned int i = 0; i < n_elem; i++) {
+ members.insert(std::make_pair(vRPCConvertParams[i].methodName,
+ vRPCConvertParams[i].paramIdx));
}
}
+static CRPCConvertTable rpcCvtTable;
+
// Convert strings to command-specific RPC representation
Array RPCConvertValues(const std::string &strMethod, const std::vector<std::string> &strParams)
{
Array params;
- BOOST_FOREACH(const std::string &param, strParams)
- params.push_back(param);
-
- int n = params.size();
- //
- // Special case non-string parameter types
- //
- if (strMethod == "stop" && n > 0) ConvertTo<bool>(params[0]);
- if (strMethod == "getaddednodeinfo" && n > 0) ConvertTo<bool>(params[0]);
- if (strMethod == "setgenerate" && n > 0) ConvertTo<bool>(params[0]);
- if (strMethod == "setgenerate" && n > 1) ConvertTo<int64_t>(params[1]);
- if (strMethod == "getnetworkhashps" && n > 0) ConvertTo<int64_t>(params[0]);
- if (strMethod == "getnetworkhashps" && n > 1) ConvertTo<int64_t>(params[1]);
- if (strMethod == "sendtoaddress" && n > 1) ConvertTo<double>(params[1]);
- if (strMethod == "settxfee" && n > 0) ConvertTo<double>(params[0]);
- if (strMethod == "getreceivedbyaddress" && n > 1) ConvertTo<int64_t>(params[1]);
- if (strMethod == "getreceivedbyaccount" && n > 1) ConvertTo<int64_t>(params[1]);
- if (strMethod == "listreceivedbyaddress" && n > 0) ConvertTo<int64_t>(params[0]);
- if (strMethod == "listreceivedbyaddress" && n > 1) ConvertTo<bool>(params[1]);
- if (strMethod == "listreceivedbyaccount" && n > 0) ConvertTo<int64_t>(params[0]);
- if (strMethod == "listreceivedbyaccount" && n > 1) ConvertTo<bool>(params[1]);
- if (strMethod == "getbalance" && n > 1) ConvertTo<int64_t>(params[1]);
- if (strMethod == "getblockhash" && n > 0) ConvertTo<int64_t>(params[0]);
- if (strMethod == "move" && n > 2) ConvertTo<double>(params[2]);
- if (strMethod == "move" && n > 3) ConvertTo<int64_t>(params[3]);
- if (strMethod == "sendfrom" && n > 2) ConvertTo<double>(params[2]);
- if (strMethod == "sendfrom" && n > 3) ConvertTo<int64_t>(params[3]);
- if (strMethod == "listtransactions" && n > 1) ConvertTo<int64_t>(params[1]);
- if (strMethod == "listtransactions" && n > 2) ConvertTo<int64_t>(params[2]);
- if (strMethod == "listaccounts" && n > 0) ConvertTo<int64_t>(params[0]);
- if (strMethod == "walletpassphrase" && n > 1) ConvertTo<int64_t>(params[1]);
- if (strMethod == "getblocktemplate" && n > 0) ConvertTo<Object>(params[0]);
- if (strMethod == "listsinceblock" && n > 1) ConvertTo<int64_t>(params[1]);
- if (strMethod == "sendmany" && n > 1) ConvertTo<Object>(params[1]);
- if (strMethod == "sendmany" && n > 2) ConvertTo<int64_t>(params[2]);
- if (strMethod == "addmultisigaddress" && n > 0) ConvertTo<int64_t>(params[0]);
- if (strMethod == "addmultisigaddress" && n > 1) ConvertTo<Array>(params[1]);
- if (strMethod == "createmultisig" && n > 0) ConvertTo<int64_t>(params[0]);
- if (strMethod == "createmultisig" && n > 1) ConvertTo<Array>(params[1]);
- if (strMethod == "listunspent" && n > 0) ConvertTo<int64_t>(params[0]);
- if (strMethod == "listunspent" && n > 1) ConvertTo<int64_t>(params[1]);
- if (strMethod == "listunspent" && n > 2) ConvertTo<Array>(params[2]);
- if (strMethod == "getblock" && n > 1) ConvertTo<bool>(params[1]);
- if (strMethod == "getrawtransaction" && n > 1) ConvertTo<int64_t>(params[1]);
- if (strMethod == "createrawtransaction" && n > 0) ConvertTo<Array>(params[0]);
- if (strMethod == "createrawtransaction" && n > 1) ConvertTo<Object>(params[1]);
- if (strMethod == "signrawtransaction" && n > 1) ConvertTo<Array>(params[1], true);
- if (strMethod == "signrawtransaction" && n > 2) ConvertTo<Array>(params[2], true);
- if (strMethod == "sendrawtransaction" && n > 1) ConvertTo<bool>(params[1], true);
- if (strMethod == "gettxout" && n > 1) ConvertTo<int64_t>(params[1]);
- if (strMethod == "gettxout" && n > 2) ConvertTo<bool>(params[2]);
- if (strMethod == "lockunspent" && n > 0) ConvertTo<bool>(params[0]);
- if (strMethod == "lockunspent" && n > 1) ConvertTo<Array>(params[1]);
- if (strMethod == "importprivkey" && n > 2) ConvertTo<bool>(params[2]);
- if (strMethod == "verifychain" && n > 0) ConvertTo<int64_t>(params[0]);
- if (strMethod == "verifychain" && n > 1) ConvertTo<int64_t>(params[1]);
- if (strMethod == "keypoolrefill" && n > 0) ConvertTo<int64_t>(params[0]);
- if (strMethod == "getrawmempool" && n > 0) ConvertTo<bool>(params[0]);
+ for (unsigned int idx = 0; idx < strParams.size(); idx++) {
+ const std::string& strVal = strParams[idx];
- return params;
-}
-
-int CommandLineRPC(int argc, char *argv[])
-{
- string strPrint;
- int nRet = 0;
- try
- {
- // Skip switches
- while (argc > 1 && IsSwitchChar(argv[1][0]))
- {
- argc--;
- argv++;
+ // insert string value directly
+ if (!rpcCvtTable.convert(strMethod, idx)) {
+ params.push_back(strVal);
}
- // Method
- if (argc < 2)
- throw runtime_error("too few parameters");
- string strMethod = argv[1];
-
- // Parameters default to strings
- std::vector<std::string> strParams(&argv[2], &argv[argc]);
- Array params = RPCConvertValues(strMethod, strParams);
-
- // Execute
- Object reply = CallRPC(strMethod, params);
-
- // Parse reply
- const Value& result = find_value(reply, "result");
- const Value& error = find_value(reply, "error");
-
- if (error.type() != null_type)
- {
- // Error
- strPrint = "error: " + write_string(error, false);
- int code = find_value(error.get_obj(), "code").get_int();
- nRet = abs(code);
- }
- else
- {
- // Result
- if (result.type() == null_type)
- strPrint = "";
- else if (result.type() == str_type)
- strPrint = result.get_str();
- else
- strPrint = write_string(result, true);
+ // parse string as JSON, insert bool/number/object/etc. value
+ else {
+ Value jVal;
+ if (!read_string(strVal, jVal))
+ throw runtime_error(string("Error parsing JSON:")+strVal);
+ params.push_back(jVal);
}
}
- catch (boost::thread_interrupted) {
- throw;
- }
- catch (std::exception& e) {
- strPrint = string("error: ") + e.what();
- nRet = abs(RPC_MISC_ERROR);
- }
- catch (...) {
- PrintExceptionContinue(NULL, "CommandLineRPC()");
- throw;
- }
- if (strPrint != "")
- {
- fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
- }
- return nRet;
-}
-
-std::string HelpMessageCli(bool mainProgram)
-{
- string strUsage;
- if(mainProgram)
- {
- strUsage += _("Options:") + "\n";
- strUsage += " -? " + _("This help message") + "\n";
- strUsage += " -conf=<file> " + _("Specify configuration file (default: bitcoin.conf)") + "\n";
- strUsage += " -datadir=<dir> " + _("Specify data directory") + "\n";
- strUsage += " -testnet " + _("Use the test network") + "\n";
- strUsage += " -regtest " + _("Enter regression test mode, which uses a special chain in which blocks can be "
- "solved instantly. This is intended for regression testing tools and app development.") + "\n";
- } else {
- strUsage += _("RPC client options:") + "\n";
- }
-
- strUsage += " -rpcconnect=<ip> " + _("Send commands to node running on <ip> (default: 127.0.0.1)") + "\n";
- strUsage += " -rpcport=<port> " + _("Connect to JSON-RPC on <port> (default: 8332 or testnet: 18332)") + "\n";
- strUsage += " -rpcwait " + _("Wait for RPC server to start") + "\n";
-
- if(mainProgram)
- {
- strUsage += " -rpcuser=<user> " + _("Username for JSON-RPC connections") + "\n";
- strUsage += " -rpcpassword=<pw> " + _("Password for JSON-RPC connections") + "\n";
-
- strUsage += "\n" + _("SSL options: (see the Bitcoin Wiki for SSL setup instructions)") + "\n";
- strUsage += " -rpcssl " + _("Use OpenSSL (https) for JSON-RPC connections") + "\n";
- }
-
- return strUsage;
+ return params;
}
diff --git a/src/rpcclient.h b/src/rpcclient.h
index e101d22ec5..840890e34b 100644
--- a/src/rpcclient.h
+++ b/src/rpcclient.h
@@ -10,16 +10,6 @@
#include "json/json_spirit_utils.h"
#include "json/json_spirit_writer_template.h"
-int CommandLineRPC(int argc, char *argv[]);
-
json_spirit::Array RPCConvertValues(const std::string &strMethod, const std::vector<std::string> &strParams);
-/** Show help message for bitcoin-cli.
- * The mainProgram argument is used to determine whether to show this message as main program
- * (and include some common options) or as sub-header of another help message.
- *
- * @note the argument can be removed once bitcoin-cli functionality is removed from bitcoind
- */
-std::string HelpMessageCli(bool mainProgram);
-
#endif
diff --git a/src/rpcdump.cpp b/src/rpcdump.cpp
index 593e0d2b6b..4193f41b49 100644
--- a/src/rpcdump.cpp
+++ b/src/rpcdump.cpp
@@ -133,6 +133,60 @@ Value importprivkey(const Array& params, bool fHelp)
return Value::null;
}
+Value importaddress(const Array& params, bool fHelp)
+{
+ if (fHelp || params.size() < 1 || params.size() > 3)
+ throw runtime_error(
+ "importaddress <address> [label] [rescan=true]\n"
+ "Adds an address or script (in hex) that can be watched as if it were in your wallet but cannot be used to spend.");
+
+ CScript script;
+
+ CBitcoinAddress address(params[0].get_str());
+ if (address.IsValid()) {
+ script.SetDestination(address.Get());
+ } else if (IsHex(params[0].get_str())) {
+ std::vector<unsigned char> data(ParseHex(params[0].get_str()));
+ script = CScript(data.begin(), data.end());
+ } else {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address or script");
+ }
+
+ string strLabel = "";
+ if (params.size() > 1)
+ strLabel = params[1].get_str();
+
+ // Whether to perform rescan after import
+ bool fRescan = true;
+ if (params.size() > 2)
+ fRescan = params[2].get_bool();
+
+ {
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
+ // add to address book or update label
+ if (address.IsValid())
+ pwalletMain->SetAddressBook(address.Get(), strLabel, "receive");
+
+ // Don't throw error in case an address is already there
+ if (pwalletMain->HaveWatchOnly(script))
+ return Value::null;
+
+ pwalletMain->MarkDirty();
+
+ if (!pwalletMain->AddWatchOnly(script))
+ throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
+
+ if (fRescan)
+ {
+ pwalletMain->ScanForWalletTransactions(chainActive.Genesis(), true);
+ pwalletMain->ReacceptWalletTransactions();
+ }
+ }
+
+ return Value::null;
+}
+
Value importwallet(const Array& params, bool fHelp)
{
if (fHelp || params.size() != 1)
@@ -157,7 +211,7 @@ Value importwallet(const Array& params, bool fHelp)
if (!file.is_open())
throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot open wallet dump file");
- int64_t nTimeBegin = chainActive.Tip()->nTime;
+ int64_t nTimeBegin = chainActive.Tip()->GetBlockTime();
bool fGood = true;
@@ -215,7 +269,7 @@ Value importwallet(const Array& params, bool fHelp)
pwalletMain->ShowProgress("", 100); // hide progress dialog in GUI
CBlockIndex *pindex = chainActive.Tip();
- while (pindex && pindex->pprev && pindex->nTime > nTimeBegin - 7200)
+ while (pindex && pindex->pprev && pindex->GetBlockTime() > nTimeBegin - 7200)
pindex = pindex->pprev;
if (!pwalletMain->nTimeFirstKey || nTimeBegin < pwalletMain->nTimeFirstKey)
@@ -301,7 +355,7 @@ Value dumpwallet(const Array& params, bool fHelp)
file << strprintf("# Wallet dump created by Bitcoin %s (%s)\n", CLIENT_BUILD, CLIENT_DATE);
file << strprintf("# * Created on %s\n", EncodeDumpTime(GetTime()));
file << strprintf("# * Best block at time of backup was %i (%s),\n", chainActive.Height(), chainActive.Tip()->GetBlockHash().ToString());
- file << strprintf("# mined on %s\n", EncodeDumpTime(chainActive.Tip()->nTime));
+ file << strprintf("# mined on %s\n", EncodeDumpTime(chainActive.Tip()->GetBlockTime()));
file << "\n";
for (std::vector<std::pair<int64_t, CKeyID> >::const_iterator it = vKeyBirth.begin(); it != vKeyBirth.end(); it++) {
const CKeyID &keyid = it->second;
diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp
index 23876c603d..c7621dc137 100644
--- a/src/rpcmining.cpp
+++ b/src/rpcmining.cpp
@@ -9,48 +9,22 @@
#include "net.h"
#include "main.h"
#include "miner.h"
+#include "pow.h"
#ifdef ENABLE_WALLET
#include "db.h"
#include "wallet.h"
#endif
+
#include <stdint.h>
+#include <boost/assign/list_of.hpp>
+
#include "json/json_spirit_utils.h"
#include "json/json_spirit_value.h"
using namespace json_spirit;
using namespace std;
-#ifdef ENABLE_WALLET
-// Key used by getwork miners.
-// Allocated in InitRPCMining, free'd in ShutdownRPCMining
-static CReserveKey* pMiningKey = NULL;
-
-void InitRPCMining()
-{
- if (!pwalletMain)
- return;
-
- // getwork/getblocktemplate mining rewards paid here:
- pMiningKey = new CReserveKey(pwalletMain);
-}
-
-void ShutdownRPCMining()
-{
- if (!pMiningKey)
- return;
-
- delete pMiningKey; pMiningKey = NULL;
-}
-#else
-void InitRPCMining()
-{
-}
-void ShutdownRPCMining()
-{
-}
-#endif
-
// Return average network hashes per second based on the last 'lookup' blocks,
// or from the last difficulty change if 'lookup' is nonpositive.
// If 'height' is nonnegative, compute the estimate at the time when a given block was found.
@@ -128,9 +102,6 @@ Value getgenerate(const Array& params, bool fHelp)
+ HelpExampleRpc("getgenerate", "")
);
- if (!pMiningKey)
- return false;
-
return GetBoolArg("-gen", false);
}
@@ -174,7 +145,7 @@ Value setgenerate(const Array& params, bool fHelp)
}
// -regtest mode: don't return until nGenProcLimit blocks are generated
- if (fGenerate && Params().NetworkID() == CChainParams::REGTEST)
+ if (fGenerate && Params().MineBlocksOnDemand())
{
int nHeightStart = 0;
int nHeightEnd = 0;
@@ -250,6 +221,7 @@ Value getmininginfo(const Array& params, bool fHelp)
" \"hashespersec\": n (numeric) The hashes per second of the generation, or 0 if no generation.\n"
" \"pooledtx\": n (numeric) The size of the mem pool\n"
" \"testnet\": true|false (boolean) If using testnet or not\n"
+ " \"chain\": \"xxxx\", (string) current network name as defined in BIP70 (main, test, regtest)\n"
"}\n"
"\nExamples:\n"
+ HelpExampleCli("getmininginfo", "")
@@ -265,7 +237,8 @@ Value getmininginfo(const Array& params, bool fHelp)
obj.push_back(Pair("genproclimit", (int)GetArg("-genproclimit", -1)));
obj.push_back(Pair("networkhashps", getnetworkhashps(params, false)));
obj.push_back(Pair("pooledtx", (uint64_t)mempool.size()));
- obj.push_back(Pair("testnet", TestNet()));
+ obj.push_back(Pair("testnet", Params().NetworkID() == CBaseChainParams::TESTNET));
+ obj.push_back(Pair("chain", Params().NetworkIDString()));
#ifdef ENABLE_WALLET
obj.push_back(Pair("generate", getgenerate(params, false)));
obj.push_back(Pair("hashespersec", gethashespersec(params, false)));
@@ -274,131 +247,19 @@ Value getmininginfo(const Array& params, bool fHelp)
}
-#ifdef ENABLE_WALLET
-Value getwork(const Array& params, bool fHelp)
+Value prioritisetransaction(const Array& params, bool fHelp)
{
- if (fHelp || params.size() > 1)
+ if (fHelp || params.size() != 3)
throw runtime_error(
- "getwork ( \"data\" )\n"
- "\nIf 'data' is not specified, it returns the formatted hash data to work on.\n"
- "If 'data' is specified, tries to solve the block and returns true if it was successful.\n"
- "\nArguments:\n"
- "1. \"data\" (string, optional) The hex encoded data to solve\n"
- "\nResult (when 'data' is not specified):\n"
- "{\n"
- " \"midstate\" : \"xxxx\", (string) The precomputed hash state after hashing the first half of the data (DEPRECATED)\n" // deprecated
- " \"data\" : \"xxxxx\", (string) The block data\n"
- " \"hash1\" : \"xxxxx\", (string) The formatted hash buffer for second hash (DEPRECATED)\n" // deprecated
- " \"target\" : \"xxxx\" (string) The little endian hash target\n"
- "}\n"
- "\nResult (when 'data' is specified):\n"
- "true|false (boolean) If solving the block specified in the 'data' was successfull\n"
- "\nExamples:\n"
- + HelpExampleCli("getwork", "")
- + HelpExampleRpc("getwork", "")
- );
-
- if (vNodes.empty())
- throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, "Bitcoin is not connected!");
-
- if (IsInitialBlockDownload())
- throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "Bitcoin is downloading blocks...");
-
- typedef map<uint256, pair<CBlock*, CScript> > mapNewBlock_t;
- static mapNewBlock_t mapNewBlock; // FIXME: thread safety
- static vector<CBlockTemplate*> vNewBlockTemplate;
-
- if (params.size() == 0)
- {
- // Update block
- static unsigned int nTransactionsUpdatedLast;
- static CBlockIndex* pindexPrev;
- static int64_t nStart;
- static CBlockTemplate* pblocktemplate;
- if (pindexPrev != chainActive.Tip() ||
- (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 60))
- {
- if (pindexPrev != chainActive.Tip())
- {
- // Deallocate old blocks since they're obsolete now
- mapNewBlock.clear();
- BOOST_FOREACH(CBlockTemplate* pblocktemplate, vNewBlockTemplate)
- delete pblocktemplate;
- vNewBlockTemplate.clear();
- }
+ "prioritisetransaction <txid> <priority delta> <fee delta>\n"
+ "Accepts the transaction into mined blocks at a higher (or lower) priority");
- // Clear pindexPrev so future getworks make a new block, despite any failures from here on
- pindexPrev = NULL;
-
- // Store the pindexBest used before CreateNewBlock, to avoid races
- nTransactionsUpdatedLast = mempool.GetTransactionsUpdated();
- CBlockIndex* pindexPrevNew = chainActive.Tip();
- nStart = GetTime();
-
- // Create new block
- pblocktemplate = CreateNewBlockWithKey(*pMiningKey);
- if (!pblocktemplate)
- throw JSONRPCError(RPC_OUT_OF_MEMORY, "Out of memory");
- vNewBlockTemplate.push_back(pblocktemplate);
-
- // Need to update only after we know CreateNewBlock succeeded
- pindexPrev = pindexPrevNew;
- }
- CBlock* pblock = &pblocktemplate->block; // pointer for convenience
-
- // Update nTime
- UpdateTime(*pblock, pindexPrev);
- pblock->nNonce = 0;
-
- // Update nExtraNonce
- static unsigned int nExtraNonce = 0;
- IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
-
- // Save
- mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, pblock->vtx[0].vin[0].scriptSig);
-
- // Pre-build hash buffers
- char pmidstate[32];
- char pdata[128];
- char phash1[64];
- FormatHashBuffers(pblock, pmidstate, pdata, phash1);
-
- uint256 hashTarget = uint256().SetCompact(pblock->nBits);
-
- Object result;
- result.push_back(Pair("midstate", HexStr(BEGIN(pmidstate), END(pmidstate)))); // deprecated
- result.push_back(Pair("data", HexStr(BEGIN(pdata), END(pdata))));
- result.push_back(Pair("hash1", HexStr(BEGIN(phash1), END(phash1)))); // deprecated
- result.push_back(Pair("target", HexStr(BEGIN(hashTarget), END(hashTarget))));
- return result;
- }
- else
- {
- // Parse parameters
- vector<unsigned char> vchData = ParseHex(params[0].get_str());
- if (vchData.size() != 128)
- throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter");
- CBlock* pdata = (CBlock*)&vchData[0];
-
- // Byte reverse
- for (int i = 0; i < 128/4; i++)
- ((unsigned int*)pdata)[i] = ByteReverse(((unsigned int*)pdata)[i]);
-
- // Get saved block
- if (!mapNewBlock.count(pdata->hashMerkleRoot))
- return false;
- CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first;
-
- pblock->nTime = pdata->nTime;
- pblock->nNonce = pdata->nNonce;
- pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second;
- pblock->hashMerkleRoot = pblock->BuildMerkleTree();
-
- assert(pwalletMain != NULL);
- return CheckWork(pblock, *pwalletMain, *pMiningKey);
- }
+ uint256 hash;
+ hash.SetHex(params[0].get_str());
+ mempool.PrioritiseTransaction(hash, params[0].get_str(), params[1].get_real(), params[2].get_int64());
+ return true;
}
-#endif
+
Value getblocktemplate(const Array& params, bool fHelp)
{
@@ -581,8 +442,8 @@ Value getblocktemplate(const Array& params, bool fHelp)
result.push_back(Pair("noncerange", "00000000ffffffff"));
result.push_back(Pair("sigoplimit", (int64_t)MAX_BLOCK_SIGOPS));
result.push_back(Pair("sizelimit", (int64_t)MAX_BLOCK_SIZE));
- result.push_back(Pair("curtime", (int64_t)pblock->nTime));
- result.push_back(Pair("bits", HexBits(pblock->nBits)));
+ result.push_back(Pair("curtime", pblock->GetBlockTime()));
+ result.push_back(Pair("bits", strprintf("%08x", pblock->nBits)));
result.push_back(Pair("height", (int64_t)(pindexPrev->nHeight+1)));
return result;
@@ -626,3 +487,63 @@ Value submitblock(const Array& params, bool fHelp)
return Value::null;
}
+
+Value estimatefee(const Array& params, bool fHelp)
+{
+ if (fHelp || params.size() != 1)
+ throw runtime_error(
+ "estimatefee nblocks\n"
+ "\nEstimates the approximate fee per kilobyte\n"
+ "needed for a transaction to get confirmed\n"
+ "within nblocks blocks.\n"
+ "\nArguments:\n"
+ "1. nblocks (numeric)\n"
+ "\nResult:\n"
+ "n : (numeric) estimated fee-per-kilobyte\n"
+ "\n"
+ "-1.0 is returned if not enough transactions and\n"
+ "blocks have been observed to make an estimate.\n"
+ "\nExample:\n"
+ + HelpExampleCli("estimatefee", "6")
+ );
+
+ RPCTypeCheck(params, boost::assign::list_of(int_type));
+
+ int nBlocks = params[0].get_int();
+ if (nBlocks < 1)
+ nBlocks = 1;
+
+ CFeeRate feeRate = mempool.estimateFee(nBlocks);
+ if (feeRate == CFeeRate(0))
+ return -1.0;
+
+ return ValueFromAmount(feeRate.GetFeePerK());
+}
+
+Value estimatepriority(const Array& params, bool fHelp)
+{
+ if (fHelp || params.size() != 1)
+ throw runtime_error(
+ "estimatepriority nblocks\n"
+ "\nEstimates the approximate priority\n"
+ "a zero-fee transaction needs to get confirmed\n"
+ "within nblocks blocks.\n"
+ "\nArguments:\n"
+ "1. nblocks (numeric)\n"
+ "\nResult:\n"
+ "n : (numeric) estimated priority\n"
+ "\n"
+ "-1.0 is returned if not enough transactions and\n"
+ "blocks have been observed to make an estimate.\n"
+ "\nExample:\n"
+ + HelpExampleCli("estimatepriority", "6")
+ );
+
+ RPCTypeCheck(params, boost::assign::list_of(int_type));
+
+ int nBlocks = params[0].get_int();
+ if (nBlocks < 1)
+ nBlocks = 1;
+
+ return mempool.estimatePriority(nBlocks);
+}
diff --git a/src/rpcmisc.cpp b/src/rpcmisc.cpp
index 27d6d61a36..cff795bdf4 100644
--- a/src/rpcmisc.cpp
+++ b/src/rpcmisc.cpp
@@ -9,6 +9,7 @@
#include "net.h"
#include "netbase.h"
#include "rpcserver.h"
+#include "timedata.h"
#include "util.h"
#ifdef ENABLE_WALLET
#include "wallet.h"
@@ -21,10 +22,10 @@
#include "json/json_spirit_utils.h"
#include "json/json_spirit_value.h"
-using namespace std;
using namespace boost;
using namespace boost::assign;
using namespace json_spirit;
+using namespace std;
Value getinfo(const Array& params, bool fHelp)
{
@@ -71,9 +72,9 @@ Value getinfo(const Array& params, bool fHelp)
obj.push_back(Pair("blocks", (int)chainActive.Height()));
obj.push_back(Pair("timeoffset", GetTimeOffset()));
obj.push_back(Pair("connections", (int)vNodes.size()));
- obj.push_back(Pair("proxy", (proxy.first.IsValid() ? proxy.first.ToStringIPPort() : string())));
+ obj.push_back(Pair("proxy", (proxy.IsValid() ? proxy.ToStringIPPort() : string())));
obj.push_back(Pair("difficulty", (double)GetDifficulty()));
- obj.push_back(Pair("testnet", TestNet()));
+ obj.push_back(Pair("testnet", Params().NetworkID() == CBaseChainParams::TESTNET));
#ifdef ENABLE_WALLET
if (pwalletMain) {
obj.push_back(Pair("keypoololdest", pwalletMain->GetOldestKeyPoolTime()));
@@ -81,9 +82,9 @@ Value getinfo(const Array& params, bool fHelp)
}
if (pwalletMain && pwalletMain->IsCrypted())
obj.push_back(Pair("unlocked_until", nWalletUnlockTime));
- obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee)));
+ obj.push_back(Pair("paytxfee", ValueFromAmount(payTxFee.GetFeePerK())));
#endif
- obj.push_back(Pair("relayfee", ValueFromAmount(CTransaction::nMinRelayTxFee)));
+ obj.push_back(Pair("relayfee", ValueFromAmount(::minRelayTxFee.GetFeePerK())));
obj.push_back(Pair("errors", GetWarnings("statusbar")));
return obj;
}
@@ -91,36 +92,45 @@ Value getinfo(const Array& params, bool fHelp)
#ifdef ENABLE_WALLET
class DescribeAddressVisitor : public boost::static_visitor<Object>
{
+private:
+ isminetype mine;
+
public:
+ DescribeAddressVisitor(isminetype mineIn) : mine(mineIn) {}
+
Object operator()(const CNoDestination &dest) const { return Object(); }
Object operator()(const CKeyID &keyID) const {
Object obj;
CPubKey vchPubKey;
- pwalletMain->GetPubKey(keyID, vchPubKey);
obj.push_back(Pair("isscript", false));
- obj.push_back(Pair("pubkey", HexStr(vchPubKey)));
- obj.push_back(Pair("iscompressed", vchPubKey.IsCompressed()));
+ if (mine == ISMINE_SPENDABLE) {
+ pwalletMain->GetPubKey(keyID, vchPubKey);
+ obj.push_back(Pair("pubkey", HexStr(vchPubKey)));
+ obj.push_back(Pair("iscompressed", vchPubKey.IsCompressed()));
+ }
return obj;
}
Object operator()(const CScriptID &scriptID) const {
Object obj;
obj.push_back(Pair("isscript", true));
- CScript subscript;
- pwalletMain->GetCScript(scriptID, subscript);
- std::vector<CTxDestination> addresses;
- txnouttype whichType;
- int nRequired;
- ExtractDestinations(subscript, whichType, addresses, nRequired);
- obj.push_back(Pair("script", GetTxnOutputType(whichType)));
- obj.push_back(Pair("hex", HexStr(subscript.begin(), subscript.end())));
- Array a;
- BOOST_FOREACH(const CTxDestination& addr, addresses)
- a.push_back(CBitcoinAddress(addr).ToString());
- obj.push_back(Pair("addresses", a));
- if (whichType == TX_MULTISIG)
- obj.push_back(Pair("sigsrequired", nRequired));
+ if (mine != ISMINE_NO) {
+ CScript subscript;
+ pwalletMain->GetCScript(scriptID, subscript);
+ std::vector<CTxDestination> addresses;
+ txnouttype whichType;
+ int nRequired;
+ ExtractDestinations(subscript, whichType, addresses, nRequired);
+ obj.push_back(Pair("script", GetTxnOutputType(whichType)));
+ obj.push_back(Pair("hex", HexStr(subscript.begin(), subscript.end())));
+ Array a;
+ BOOST_FOREACH(const CTxDestination& addr, addresses)
+ a.push_back(CBitcoinAddress(addr).ToString());
+ obj.push_back(Pair("addresses", a));
+ if (whichType == TX_MULTISIG)
+ obj.push_back(Pair("sigsrequired", nRequired));
+ }
return obj;
}
};
@@ -160,10 +170,11 @@ Value validateaddress(const Array& params, bool fHelp)
string currentAddress = address.ToString();
ret.push_back(Pair("address", currentAddress));
#ifdef ENABLE_WALLET
- bool fMine = pwalletMain ? IsMine(*pwalletMain, dest) : false;
- ret.push_back(Pair("ismine", fMine));
- if (fMine) {
- Object detail = boost::apply_visitor(DescribeAddressVisitor(), dest);
+ isminetype mine = pwalletMain ? IsMine(*pwalletMain, dest) : ISMINE_NO;
+ ret.push_back(Pair("ismine", (mine & ISMINE_SPENDABLE) ? true : false));
+ if (mine != ISMINE_NO) {
+ ret.push_back(Pair("iswatchonly", (mine & ISMINE_WATCH_ONLY) ? true: false));
+ Object detail = boost::apply_visitor(DescribeAddressVisitor(mine), dest);
ret.insert(ret.end(), detail.begin(), detail.end());
}
if (pwalletMain && pwalletMain->mapAddressBook.count(dest))
diff --git a/src/rpcnet.cpp b/src/rpcnet.cpp
index 024f6a09de..cf2c293caf 100644
--- a/src/rpcnet.cpp
+++ b/src/rpcnet.cpp
@@ -9,6 +9,7 @@
#include "netbase.h"
#include "protocol.h"
#include "sync.h"
+#include "timedata.h"
#include "util.h"
#include <boost/foreach.hpp>
@@ -80,7 +81,7 @@ Value getpeerinfo(const Array& params, bool fHelp)
" {\n"
" \"addr\":\"host:port\", (string) The ip address and port of the peer\n"
" \"addrlocal\":\"ip:port\", (string) local address\n"
- " \"services\":\"00000001\", (string) The services\n"
+ " \"services\":\"xxxxxxxxxxxxxxxx\", (string) The services offered\n"
" \"lastsend\": ttt, (numeric) The time in seconds since epoch (Jan 1 1970 GMT) of the last send\n"
" \"lastrecv\": ttt, (numeric) The time in seconds since epoch (Jan 1 1970 GMT) of the last receive\n"
" \"bytessent\": n, (numeric) The total bytes sent\n"
@@ -115,7 +116,7 @@ Value getpeerinfo(const Array& params, bool fHelp)
obj.push_back(Pair("addr", stats.addrName));
if (!(stats.addrLocal.empty()))
obj.push_back(Pair("addrlocal", stats.addrLocal));
- obj.push_back(Pair("services", strprintf("%08x", stats.nServices)));
+ obj.push_back(Pair("services", strprintf("%016x", stats.nServices)));
obj.push_back(Pair("lastsend", stats.nLastSend));
obj.push_back(Pair("lastrecv", stats.nLastRecv));
obj.push_back(Pair("bytessent", stats.nSendBytes));
@@ -133,6 +134,7 @@ Value getpeerinfo(const Array& params, bool fHelp)
obj.push_back(Pair("startingheight", stats.nStartingHeight));
if (fStateStats) {
obj.push_back(Pair("banscore", statestats.nMisbehavior));
+ obj.push_back(Pair("syncheight", statestats.nSyncHeight));
}
obj.push_back(Pair("syncnode", stats.fSyncNode));
@@ -166,7 +168,7 @@ Value addnode(const Array& params, bool fHelp)
if (strCommand == "onetry")
{
CAddress addr;
- ConnectNode(addr, strNode.c_str());
+ OpenNetworkConnection(addr, NULL, strNode.c_str());
return Value::null;
}
@@ -344,6 +346,7 @@ Value getnetworkinfo(const Array& params, bool fHelp)
"{\n"
" \"version\": xxxxx, (numeric) the server version\n"
" \"protocolversion\": xxxxx, (numeric) the protocol version\n"
+ " \"localservices\": \"xxxxxxxxxxxxxxxx\", (string) the services we offer to the network\n"
" \"timeoffset\": xxxxx, (numeric) the time offset\n"
" \"connections\": xxxxx, (numeric) the number of connections\n"
" \"proxy\": \"host:port\", (string, optional) the proxy used by the server\n"
@@ -365,10 +368,11 @@ Value getnetworkinfo(const Array& params, bool fHelp)
Object obj;
obj.push_back(Pair("version", (int)CLIENT_VERSION));
obj.push_back(Pair("protocolversion",(int)PROTOCOL_VERSION));
+ obj.push_back(Pair("localservices", strprintf("%016x", nLocalServices)));
obj.push_back(Pair("timeoffset", GetTimeOffset()));
obj.push_back(Pair("connections", (int)vNodes.size()));
- obj.push_back(Pair("proxy", (proxy.first.IsValid() ? proxy.first.ToStringIPPort() : string())));
- obj.push_back(Pair("relayfee", ValueFromAmount(CTransaction::nMinRelayTxFee)));
+ obj.push_back(Pair("proxy", (proxy.IsValid() ? proxy.ToStringIPPort() : string())));
+ obj.push_back(Pair("relayfee", ValueFromAmount(::minRelayTxFee.GetFeePerK())));
Array localAddresses;
{
LOCK(cs_mapLocalHost);
diff --git a/src/rpcprotocol.cpp b/src/rpcprotocol.cpp
index 5cbaa535ab..9e18ca847e 100644
--- a/src/rpcprotocol.cpp
+++ b/src/rpcprotocol.cpp
@@ -25,6 +25,9 @@ using namespace boost;
using namespace boost::asio;
using namespace json_spirit;
+// Number of bytes to allocate and read at most at once in post data
+const size_t POST_READ_SIZE = 256 * 1024;
+
//
// HTTP protocol
//
@@ -51,18 +54,22 @@ string HTTPPost(const string& strMsg, const map<string,string>& mapRequestHeader
static string rfc1123Time()
{
- char buffer[64];
- time_t now;
- time(&now);
- struct tm* now_gmt = gmtime(&now);
- string locale(setlocale(LC_TIME, NULL));
- setlocale(LC_TIME, "C"); // we want POSIX (aka "C") weekday/month strings
- strftime(buffer, sizeof(buffer), "%a, %d %b %Y %H:%M:%S +0000", now_gmt);
- setlocale(LC_TIME, locale.c_str());
- return string(buffer);
+ return DateTimeStrFormat("%a, %d %b %Y %H:%M:%S +0000", GetTime());
+}
+
+static const char *httpStatusDescription(int nStatus)
+{
+ switch (nStatus) {
+ case HTTP_OK: return "OK";
+ case HTTP_BAD_REQUEST: return "Bad Request";
+ case HTTP_FORBIDDEN: return "Forbidden";
+ case HTTP_NOT_FOUND: return "Not Found";
+ case HTTP_INTERNAL_SERVER_ERROR: return "Internal Server Error";
+ default: return "";
+ }
}
-string HTTPReply(int nStatus, const string& strMsg, bool keepalive)
+string HTTPError(int nStatus, bool keepalive, bool headersOnly)
{
if (nStatus == HTTP_UNAUTHORIZED)
return strprintf("HTTP/1.0 401 Authorization Required\r\n"
@@ -81,29 +88,32 @@ string HTTPReply(int nStatus, const string& strMsg, bool keepalive)
"</HEAD>\r\n"
"<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
"</HTML>\r\n", rfc1123Time(), FormatFullVersion());
- const char *cStatus;
- if (nStatus == HTTP_OK) cStatus = "OK";
- else if (nStatus == HTTP_BAD_REQUEST) cStatus = "Bad Request";
- else if (nStatus == HTTP_FORBIDDEN) cStatus = "Forbidden";
- else if (nStatus == HTTP_NOT_FOUND) cStatus = "Not Found";
- else if (nStatus == HTTP_INTERNAL_SERVER_ERROR) cStatus = "Internal Server Error";
- else cStatus = "";
+
+ return HTTPReply(nStatus, httpStatusDescription(nStatus), keepalive,
+ headersOnly, "text/plain");
+}
+
+string HTTPReply(int nStatus, const string& strMsg, bool keepalive,
+ bool headersOnly, const char *contentType)
+{
return strprintf(
"HTTP/1.1 %d %s\r\n"
"Date: %s\r\n"
"Connection: %s\r\n"
"Content-Length: %u\r\n"
- "Content-Type: application/json\r\n"
+ "Content-Type: %s\r\n"
"Server: bitcoin-json-rpc/%s\r\n"
"\r\n"
"%s",
nStatus,
- cStatus,
+ httpStatusDescription(nStatus),
rfc1123Time(),
keepalive ? "keep-alive" : "close",
- strMsg.size(),
+ (headersOnly ? 0 : strMsg.size()),
+ contentType,
FormatFullVersion(),
- strMsg);
+ (headersOnly ? "" : strMsg.c_str())
+ );
}
bool ReadHTTPRequestLine(std::basic_istream<char>& stream, int &proto,
@@ -197,8 +207,17 @@ int ReadHTTPMessage(std::basic_istream<char>& stream, map<string,
// Read message
if (nLen > 0)
{
- vector<char> vch(nLen);
- stream.read(&vch[0], nLen);
+ vector<char> vch;
+ size_t ptr = 0;
+ while (ptr < (size_t)nLen)
+ {
+ size_t bytes_to_read = std::min((size_t)nLen - ptr, POST_READ_SIZE);
+ vch.resize(ptr + bytes_to_read);
+ stream.read(&vch[ptr], bytes_to_read);
+ if (!stream) // Connection lost while reading
+ return HTTP_INTERNAL_SERVER_ERROR;
+ ptr += bytes_to_read;
+ }
strMessageRet = string(vch.begin(), vch.end());
}
diff --git a/src/rpcprotocol.h b/src/rpcprotocol.h
index 11bdd171d9..5627077bfb 100644
--- a/src/rpcprotocol.h
+++ b/src/rpcprotocol.h
@@ -141,7 +141,11 @@ private:
};
std::string HTTPPost(const std::string& strMsg, const std::map<std::string,std::string>& mapRequestHeaders);
-std::string HTTPReply(int nStatus, const std::string& strMsg, bool keepalive);
+std::string HTTPError(int nStatus, bool keepalive,
+ bool headerOnly = false);
+std::string HTTPReply(int nStatus, const std::string& strMsg, bool keepalive,
+ bool headerOnly = false,
+ const char *contentType = "application/json");
bool ReadHTTPRequestLine(std::basic_istream<char>& stream, int &proto,
std::string& http_method, std::string& http_uri);
int ReadHTTPStatus(std::basic_istream<char>& stream, int &proto);
diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp
index dee7daeb2a..2306b1b883 100644
--- a/src/rpcrawtransaction.cpp
+++ b/src/rpcrawtransaction.cpp
@@ -99,8 +99,8 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry)
if (chainActive.Contains(pindex))
{
entry.push_back(Pair("confirmations", 1 + chainActive.Height() - pindex->nHeight));
- entry.push_back(Pair("time", (int64_t)pindex->nTime));
- entry.push_back(Pair("blocktime", (int64_t)pindex->nTime));
+ entry.push_back(Pair("time", pindex->GetBlockTime()));
+ entry.push_back(Pair("blocktime", pindex->GetBlockTime()));
}
else
entry.push_back(Pair("confirmations", 0));
@@ -304,6 +304,7 @@ Value listunspent(const Array& params, bool fHelp)
}
entry.push_back(Pair("amount",ValueFromAmount(nValue)));
entry.push_back(Pair("confirmations",out.nDepth));
+ entry.push_back(Pair("spendable", out.fSpendable));
results.push_back(entry);
}
@@ -349,7 +350,7 @@ Value createrawtransaction(const Array& params, bool fHelp)
Array inputs = params[0].get_array();
Object sendTo = params[1].get_obj();
- CTransaction rawTx;
+ CMutableTransaction rawTx;
BOOST_FOREACH(const Value& input, inputs)
{
@@ -554,11 +555,11 @@ Value signrawtransaction(const Array& params, bool fHelp)
vector<unsigned char> txData(ParseHexV(params[0], "argument 1"));
CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
- vector<CTransaction> txVariants;
+ vector<CMutableTransaction> txVariants;
while (!ssData.empty())
{
try {
- CTransaction tx;
+ CMutableTransaction tx;
ssData >> tx;
txVariants.push_back(tx);
}
@@ -572,7 +573,7 @@ Value signrawtransaction(const Array& params, bool fHelp)
// mergedTx will end up with all the signatures; it
// starts as a clone of the rawtx:
- CTransaction mergedTx(txVariants[0]);
+ CMutableTransaction mergedTx(txVariants[0]);
bool fComplete = true;
// Fetch previous transactions (inputs):
@@ -713,7 +714,7 @@ Value signrawtransaction(const Array& params, bool fHelp)
SignSignature(keystore, prevPubKey, mergedTx, i, nHashType);
// ... and merge in other signatures:
- BOOST_FOREACH(const CTransaction& txv, txVariants)
+ BOOST_FOREACH(const CMutableTransaction& txv, txVariants)
{
txin.scriptSig = CombineSignatures(prevPubKey, mergedTx, i, txin.scriptSig, txv.vin[i].scriptSig);
}
@@ -770,7 +771,7 @@ Value sendrawtransaction(const Array& params, bool fHelp)
catch (std::exception &e) {
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
}
- uint256 hashTx = tx.GetHash();
+ const uint256 &hashTx = tx.GetHash();
CCoinsViewCache &view = *pcoinsTip;
CCoins existingCoins;
@@ -780,7 +781,7 @@ Value sendrawtransaction(const Array& params, bool fHelp)
// push to local node and sync with wallets
CValidationState state;
if (AcceptToMemoryPool(mempool, state, tx, false, NULL, !fOverrideFees))
- SyncWithWallets(hashTx, tx, NULL);
+ SyncWithWallets(tx, NULL);
else {
if(state.IsInvalid())
throw JSONRPCError(RPC_TRANSACTION_REJECTED, strprintf("%i: %s", state.GetRejectCode(), state.GetRejectReason()));
@@ -790,7 +791,7 @@ Value sendrawtransaction(const Array& params, bool fHelp)
} else if (fHaveChain) {
throw JSONRPCError(RPC_TRANSACTION_ALREADY_IN_CHAIN, "transaction already in block chain");
}
- RelayTransaction(tx, hashTx);
+ RelayTransaction(tx);
return hashTx.GetHex();
}
diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp
index 2534a9dcf4..18fa075101 100644
--- a/src/rpcserver.cpp
+++ b/src/rpcserver.cpp
@@ -25,10 +25,10 @@
#include <boost/shared_ptr.hpp>
#include "json/json_spirit_writer_template.h"
-using namespace std;
using namespace boost;
using namespace boost::asio;
using namespace json_spirit;
+using namespace std;
static std::string strRPCUserColonPass;
@@ -97,16 +97,6 @@ Value ValueFromAmount(int64_t amount)
return (double)amount / (double)COIN;
}
-std::string HexBits(unsigned int nBits)
-{
- union {
- int32_t nBits;
- char cBits[4];
- } uBits;
- uBits.nBits = htonl((int32_t)nBits);
- return HexStr(BEGIN(uBits.cBits), END(uBits.cBits));
-}
-
uint256 ParseHashV(const Value& v, string strName)
{
string strHex;
@@ -254,7 +244,8 @@ static const CRPCCommand vRPCCommands[] =
{ "getblocktemplate", &getblocktemplate, true, false, false },
{ "getmininginfo", &getmininginfo, true, false, false },
{ "getnetworkhashps", &getnetworkhashps, true, false, false },
- { "submitblock", &submitblock, false, false, false },
+ { "prioritisetransaction", &prioritisetransaction, true, false, false },
+ { "submitblock", &submitblock, false, true, false },
/* Raw transactions */
{ "createrawtransaction", &createrawtransaction, false, false, false },
@@ -268,6 +259,8 @@ static const CRPCCommand vRPCCommands[] =
{ "createmultisig", &createmultisig, true, true , false },
{ "validateaddress", &validateaddress, true, false, false }, /* uses wallet if enabled */
{ "verifymessage", &verifymessage, false, false, false },
+ { "estimatefee", &estimatefee, true, true, false },
+ { "estimatepriority", &estimatepriority, true, true, false },
#ifdef ENABLE_WALLET
/* Wallet */
@@ -289,6 +282,7 @@ static const CRPCCommand vRPCCommands[] =
{ "getwalletinfo", &getwalletinfo, true, false, true },
{ "importprivkey", &importprivkey, false, false, true },
{ "importwallet", &importwallet, false, false, true },
+ { "importaddress", &importaddress, false, false, true },
{ "keypoolrefill", &keypoolrefill, true, false, true },
{ "listaccounts", &listaccounts, false, false, true },
{ "listaddressgroupings", &listaddressgroupings, false, false, true },
@@ -313,7 +307,6 @@ static const CRPCCommand vRPCCommands[] =
/* Wallet-enabled mining */
{ "getgenerate", &getgenerate, true, false, false },
{ "gethashespersec", &gethashespersec, true, false, false },
- { "getwork", &getwork, true, false, true },
{ "setgenerate", &setgenerate, true, true, false },
#endif // ENABLE_WALLET
};
@@ -391,16 +384,6 @@ bool ClientAllowed(const boost::asio::ip::address& address)
return false;
}
-class AcceptedConnection
-{
-public:
- virtual ~AcceptedConnection() {}
-
- virtual std::iostream& stream() = 0;
- virtual std::string peer_address_to_string() const = 0;
- virtual void close() = 0;
-};
-
template <typename Protocol>
class AcceptedConnectionImpl : public AcceptedConnection
{
@@ -499,7 +482,7 @@ static void RPCAcceptHandler(boost::shared_ptr< basic_socket_acceptor<Protocol,
{
// Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
if (!fUseSSL)
- conn->stream() << HTTPReply(HTTP_FORBIDDEN, "", false) << std::flush;
+ conn->stream() << HTTPError(HTTP_FORBIDDEN, false) << std::flush;
conn->close();
}
else {
@@ -530,7 +513,7 @@ void StartRPCThreads()
if(!subnet.IsValid())
{
uiInterface.ThreadSafeMessageBox(
- strprintf("Invalid -rpcallowip subnet specification: %s", strAllow),
+ strprintf("Invalid -rpcallowip subnet specification: %s. Valid are a single IP (e.g. 1.2.3.4), a network/netmask (e.g. 1.2.3.4/255.255.255.0) or a network/CIDR (e.g. 1.2.3.4/24).", strAllow),
"", CClientUIInterface::MSG_ERROR);
StartShutdown();
return;
@@ -599,7 +582,7 @@ void StartRPCThreads()
std::vector<ip::tcp::endpoint> vEndpoints;
bool bBindAny = false;
- int defaultPort = GetArg("-rpcport", Params().RPCPort());
+ int defaultPort = GetArg("-rpcport", BaseParams().RPCPort());
if (!mapArgs.count("-rpcallowip")) // Default to loopback if not allowing external IPs
{
vEndpoints.push_back(ip::tcp::endpoint(asio::ip::address_v6::loopback(), defaultPort));
@@ -640,7 +623,6 @@ void StartRPCThreads()
LogPrintf("Binding RPC on address %s port %i (IPv4+IPv6 bind any: %i)\n", bindAddress.to_string(), endpoint.port(), bBindAny);
boost::system::error_code v6_only_error;
boost::shared_ptr<ip::tcp::acceptor> acceptor(new ip::tcp::acceptor(*rpc_io_service));
- rpc_acceptors.push_back(acceptor);
try {
acceptor->open(endpoint.protocol());
@@ -656,6 +638,7 @@ void StartRPCThreads()
RPCListen(acceptor, *rpc_ssl_context, fUseSSL);
fListening = true;
+ rpc_acceptors.push_back(acceptor);
// If dual IPv6/IPv4 bind succesful, skip binding to IPv4 separately
if(bBindAny && bindAddress == asio::ip::address_v6::any() && !v6_only_error)
break;
@@ -698,11 +681,20 @@ void StopRPCThreads()
// First, cancel all timers and acceptors
// This is not done automatically by ->stop(), and in some cases the destructor of
// asio::io_service can hang if this is skipped.
+ boost::system::error_code ec;
BOOST_FOREACH(const boost::shared_ptr<ip::tcp::acceptor> &acceptor, rpc_acceptors)
- acceptor->cancel();
+ {
+ acceptor->cancel(ec);
+ if (ec)
+ LogPrintf("%s: Warning: %s when cancelling acceptor", __func__, ec.message());
+ }
rpc_acceptors.clear();
BOOST_FOREACH(const PAIRTYPE(std::string, boost::shared_ptr<deadline_timer>) &timer, deadlineTimers)
- timer.second->cancel();
+ {
+ timer.second->cancel(ec);
+ if (ec)
+ LogPrintf("%s: Warning: %s when cancelling timer", __func__, ec.message());
+ }
deadlineTimers.clear();
rpc_io_service->stop();
@@ -761,7 +753,7 @@ void JSONRequest::parse(const Value& valRequest)
if (valMethod.type() != str_type)
throw JSONRPCError(RPC_INVALID_REQUEST, "Method must be a string");
strMethod = valMethod.get_str();
- if (strMethod != "getwork" && strMethod != "getblocktemplate")
+ if (strMethod != "getblocktemplate")
LogPrint("rpc", "ThreadRPCServer method=%s\n", strMethod);
// Parse params
@@ -808,6 +800,71 @@ static string JSONRPCExecBatch(const Array& vReq)
return write_string(Value(ret), false) + "\n";
}
+static bool HTTPReq_JSONRPC(AcceptedConnection *conn,
+ string& strRequest,
+ map<string, string>& mapHeaders,
+ bool fRun)
+{
+ // Check authorization
+ if (mapHeaders.count("authorization") == 0)
+ {
+ conn->stream() << HTTPError(HTTP_UNAUTHORIZED, false) << std::flush;
+ return false;
+ }
+
+ if (!HTTPAuthorized(mapHeaders))
+ {
+ LogPrintf("ThreadRPCServer incorrect password attempt from %s\n", conn->peer_address_to_string());
+ /* Deter brute-forcing short passwords.
+ If this results in a DoS the user really
+ shouldn't have their RPC port exposed. */
+ if (mapArgs["-rpcpassword"].size() < 20)
+ MilliSleep(250);
+
+ conn->stream() << HTTPError(HTTP_UNAUTHORIZED, false) << std::flush;
+ return false;
+ }
+
+ JSONRequest jreq;
+ try
+ {
+ // Parse request
+ Value valRequest;
+ if (!read_string(strRequest, valRequest))
+ throw JSONRPCError(RPC_PARSE_ERROR, "Parse error");
+
+ string strReply;
+
+ // singleton request
+ if (valRequest.type() == obj_type) {
+ jreq.parse(valRequest);
+
+ Value result = tableRPC.execute(jreq.strMethod, jreq.params);
+
+ // Send reply
+ strReply = JSONRPCReply(result, Value::null, jreq.id);
+
+ // array of requests
+ } else if (valRequest.type() == array_type)
+ strReply = JSONRPCExecBatch(valRequest.get_array());
+ else
+ throw JSONRPCError(RPC_PARSE_ERROR, "Top-level object parse error");
+
+ conn->stream() << HTTPReply(HTTP_OK, strReply, fRun) << std::flush;
+ }
+ catch (Object& objError)
+ {
+ ErrorReply(conn->stream(), objError, jreq.id);
+ return false;
+ }
+ catch (std::exception& e)
+ {
+ ErrorReply(conn->stream(), JSONRPCError(RPC_PARSE_ERROR, e.what()), jreq.id);
+ return false;
+ }
+ return true;
+}
+
void ServiceConnection(AcceptedConnection *conn)
{
bool fRun = true;
@@ -824,67 +881,15 @@ void ServiceConnection(AcceptedConnection *conn)
// Read HTTP message headers and body
ReadHTTPMessage(conn->stream(), mapHeaders, strRequest, nProto);
- if (strURI != "/") {
- conn->stream() << HTTPReply(HTTP_NOT_FOUND, "", false) << std::flush;
- break;
- }
-
- // Check authorization
- if (mapHeaders.count("authorization") == 0)
- {
- conn->stream() << HTTPReply(HTTP_UNAUTHORIZED, "", false) << std::flush;
- break;
- }
- if (!HTTPAuthorized(mapHeaders))
- {
- LogPrintf("ThreadRPCServer incorrect password attempt from %s\n", conn->peer_address_to_string());
- /* Deter brute-forcing short passwords.
- If this results in a DoS the user really
- shouldn't have their RPC port exposed. */
- if (mapArgs["-rpcpassword"].size() < 20)
- MilliSleep(250);
-
- conn->stream() << HTTPReply(HTTP_UNAUTHORIZED, "", false) << std::flush;
- break;
- }
+ // HTTP Keep-Alive is false; close connection immediately
if (mapHeaders["connection"] == "close")
fRun = false;
- JSONRequest jreq;
- try
- {
- // Parse request
- Value valRequest;
- if (!read_string(strRequest, valRequest))
- throw JSONRPCError(RPC_PARSE_ERROR, "Parse error");
-
- string strReply;
-
- // singleton request
- if (valRequest.type() == obj_type) {
- jreq.parse(valRequest);
-
- Value result = tableRPC.execute(jreq.strMethod, jreq.params);
-
- // Send reply
- strReply = JSONRPCReply(result, Value::null, jreq.id);
-
- // array of requests
- } else if (valRequest.type() == array_type)
- strReply = JSONRPCExecBatch(valRequest.get_array());
- else
- throw JSONRPCError(RPC_PARSE_ERROR, "Top-level object parse error");
-
- conn->stream() << HTTPReply(HTTP_OK, strReply, fRun) << std::flush;
- }
- catch (Object& objError)
- {
- ErrorReply(conn->stream(), objError, jreq.id);
- break;
- }
- catch (std::exception& e)
- {
- ErrorReply(conn->stream(), JSONRPCError(RPC_PARSE_ERROR, e.what()), jreq.id);
+ if (strURI == "/") {
+ if (!HTTPReq_JSONRPC(conn, strRequest, mapHeaders, fRun))
+ break;
+ } else {
+ conn->stream() << HTTPError(HTTP_NOT_FOUND, false) << std::flush;
break;
}
}
diff --git a/src/rpcserver.h b/src/rpcserver.h
index e8cd2cd0fc..e32eb975a1 100644
--- a/src/rpcserver.h
+++ b/src/rpcserver.h
@@ -21,6 +21,16 @@
class CBlockIndex;
class CNetAddr;
+class AcceptedConnection
+{
+public:
+ virtual ~AcceptedConnection() {}
+
+ virtual std::iostream& stream() = 0;
+ virtual std::string peer_address_to_string() const = 0;
+ virtual void close() = 0;
+};
+
/* Start RPC threads */
void StartRPCThreads();
/* Alternative to StartRPCThreads for the GUI, when no server is
@@ -106,7 +116,6 @@ extern int64_t nWalletUnlockTime;
extern int64_t AmountFromValue(const json_spirit::Value& value);
extern json_spirit::Value ValueFromAmount(int64_t amount);
extern double GetDifficulty(const CBlockIndex* blockindex = NULL);
-extern std::string HexBits(unsigned int nBits);
extern std::string HelpRequiringPassphrase();
extern std::string HelpExampleCli(std::string methodname, std::string args);
extern std::string HelpExampleRpc(std::string methodname, std::string args);
@@ -122,6 +131,7 @@ extern json_spirit::Value getnettotals(const json_spirit::Array& params, bool fH
extern json_spirit::Value dumpprivkey(const json_spirit::Array& params, bool fHelp); // in rpcdump.cpp
extern json_spirit::Value importprivkey(const json_spirit::Array& params, bool fHelp);
+extern json_spirit::Value importaddress(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value dumpwallet(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value importwallet(const json_spirit::Array& params, bool fHelp);
@@ -130,9 +140,11 @@ extern json_spirit::Value setgenerate(const json_spirit::Array& params, bool fHe
extern json_spirit::Value getnetworkhashps(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value gethashespersec(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value getmininginfo(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value getwork(const json_spirit::Array& params, bool fHelp);
+extern json_spirit::Value prioritisetransaction(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value getblocktemplate(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value submitblock(const json_spirit::Array& params, bool fHelp);
+extern json_spirit::Value estimatefee(const json_spirit::Array& params, bool fHelp);
+extern json_spirit::Value estimatepriority(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value getnewaddress(const json_spirit::Array& params, bool fHelp); // in rpcwallet.cpp
extern json_spirit::Value getaccountaddress(const json_spirit::Array& params, bool fHelp);
diff --git a/src/rpcwallet.cpp b/src/rpcwallet.cpp
index a8f267d7fc..1e46129065 100644
--- a/src/rpcwallet.cpp
+++ b/src/rpcwallet.cpp
@@ -8,6 +8,7 @@
#include "init.h"
#include "net.h"
#include "netbase.h"
+#include "timedata.h"
#include "util.h"
#include "wallet.h"
#include "walletdb.h"
@@ -49,7 +50,7 @@ void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
{
entry.push_back(Pair("blockhash", wtx.hashBlock.GetHex()));
entry.push_back(Pair("blockindex", wtx.nIndex));
- entry.push_back(Pair("blocktime", (int64_t)(mapBlockIndex[wtx.hashBlock]->nTime)));
+ entry.push_back(Pair("blocktime", mapBlockIndex[wtx.hashBlock]->GetBlockTime()));
}
uint256 hash = wtx.GetHash();
entry.push_back(Pair("txid", hash.GetHex()));
@@ -57,6 +58,10 @@ void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
BOOST_FOREACH(const uint256& conflict, wtx.GetConflicts())
conflicts.push_back(conflict.GetHex());
entry.push_back(Pair("walletconflicts", conflicts));
+ Array respends;
+ BOOST_FOREACH(const uint256& respend, wtx.GetConflicts(false))
+ respends.push_back(respend.GetHex());
+ entry.push_back(Pair("respendsobserved", respends));
entry.push_back(Pair("time", wtx.GetTxTime()));
entry.push_back(Pair("timereceived", (int64_t)wtx.nTimeReceived));
BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue)
@@ -318,7 +323,7 @@ Value sendtoaddress(const Array& params, bool fHelp)
" to which you're sending the transaction. This is not part of the \n"
" transaction, just kept in your wallet.\n"
"\nResult:\n"
- "\"transactionid\" (string) The transaction id. (view at https://blockchain.info/tx/[transactionid])\n"
+ "\"transactionid\" (string) The transaction id.\n"
"\nExamples:\n"
+ HelpExampleCli("sendtoaddress", "\"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.1")
+ HelpExampleCli("sendtoaddress", "\"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.1 \"donation\" \"seans outpost\"")
@@ -341,7 +346,7 @@ Value sendtoaddress(const Array& params, bool fHelp)
EnsureWalletIsUnlocked();
- string strError = pwalletMain->SendMoneyToDestination(address.Get(), nAmount, wtx);
+ string strError = pwalletMain->SendMoney(address.Get(), nAmount, wtx);
if (strError != "")
throw JSONRPCError(RPC_WALLET_ERROR, strError);
@@ -552,7 +557,7 @@ Value getreceivedbyaccount(const Array& params, bool fHelp)
}
-int64_t GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth)
+int64_t GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth, const isminefilter& filter)
{
int64_t nBalance = 0;
@@ -564,7 +569,7 @@ int64_t GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMi
continue;
int64_t nReceived, nSent, nFee;
- wtx.GetAccountAmounts(strAccount, nReceived, nSent, nFee);
+ wtx.GetAccountAmounts(strAccount, nReceived, nSent, nFee, filter);
if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
nBalance += nReceived;
@@ -577,18 +582,18 @@ int64_t GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMi
return nBalance;
}
-int64_t GetAccountBalance(const string& strAccount, int nMinDepth)
+int64_t GetAccountBalance(const string& strAccount, int nMinDepth, const isminefilter& filter)
{
CWalletDB walletdb(pwalletMain->strWalletFile);
- return GetAccountBalance(walletdb, strAccount, nMinDepth);
+ return GetAccountBalance(walletdb, strAccount, nMinDepth, filter);
}
Value getbalance(const Array& params, bool fHelp)
{
- if (fHelp || params.size() > 2)
+ if (fHelp || params.size() > 3)
throw runtime_error(
- "getbalance ( \"account\" minconf )\n"
+ "getbalance ( \"account\" minconf includeWatchonly )\n"
"\nIf account is not specified, returns the server's total available balance.\n"
"If account is specified, returns the balance in the account.\n"
"Note that the account \"\" is not the same as leaving the parameter out.\n"
@@ -596,6 +601,7 @@ Value getbalance(const Array& params, bool fHelp)
"\nArguments:\n"
"1. \"account\" (string, optional) The selected account, or \"*\" for entire wallet. It may be the default account using \"\".\n"
"2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
+ "3. includeWatchonly (bool, optional, default=false) Also include balance in watchonly addresses (see 'importaddress')\n"
"\nResult:\n"
"amount (numeric) The total amount in btc received for this account.\n"
"\nExamples:\n"
@@ -617,6 +623,10 @@ Value getbalance(const Array& params, bool fHelp)
int nMinDepth = 1;
if (params.size() > 1)
nMinDepth = params[1].get_int();
+ isminefilter filter = ISMINE_SPENDABLE;
+ if(params.size() > 2)
+ if(params[2].get_bool())
+ filter = filter | ISMINE_WATCH_ONLY;
if (params[0].get_str() == "*") {
// Calculate total balance a different way from GetBalance()
@@ -633,7 +643,7 @@ Value getbalance(const Array& params, bool fHelp)
string strSentAccount;
list<pair<CTxDestination, int64_t> > listReceived;
list<pair<CTxDestination, int64_t> > listSent;
- wtx.GetAmounts(listReceived, listSent, allFee, strSentAccount);
+ wtx.GetAmounts(listReceived, listSent, allFee, strSentAccount, filter);
if (wtx.GetDepthInMainChain() >= nMinDepth)
{
BOOST_FOREACH(const PAIRTYPE(CTxDestination,int64_t)& r, listReceived)
@@ -648,7 +658,7 @@ Value getbalance(const Array& params, bool fHelp)
string strAccount = AccountFromValue(params[0]);
- int64_t nBalance = GetAccountBalance(strAccount, nMinDepth);
+ int64_t nBalance = GetAccountBalance(strAccount, nMinDepth, filter);
return ValueFromAmount(nBalance);
}
@@ -747,7 +757,7 @@ Value sendfrom(const Array& params, bool fHelp)
" to which you're sending the transaction. This is not part of the transaction, \n"
" it is just kept in your wallet.\n"
"\nResult:\n"
- "\"transactionid\" (string) The transaction id. (view at https://blockchain.info/tx/[transactionid])\n"
+ "\"transactionid\" (string) The transaction id.\n"
"\nExamples:\n"
"\nSend 0.01 btc from the default account to the address, must have at least 1 confirmation\n"
+ HelpExampleCli("sendfrom", "\"\" \"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.01") +
@@ -776,12 +786,12 @@ Value sendfrom(const Array& params, bool fHelp)
EnsureWalletIsUnlocked();
// Check funds
- int64_t nBalance = GetAccountBalance(strAccount, nMinDepth);
+ int64_t nBalance = GetAccountBalance(strAccount, nMinDepth, ISMINE_SPENDABLE);
if (nAmount > nBalance)
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
// Send
- string strError = pwalletMain->SendMoneyToDestination(address.Get(), nAmount, wtx);
+ string strError = pwalletMain->SendMoney(address.Get(), nAmount, wtx);
if (strError != "")
throw JSONRPCError(RPC_WALLET_ERROR, strError);
@@ -807,7 +817,7 @@ Value sendmany(const Array& params, bool fHelp)
"4. \"comment\" (string, optional) A comment\n"
"\nResult:\n"
"\"transactionid\" (string) The transaction id for the send. Only 1 transaction is created regardless of \n"
- " the number of addresses. See https://blockchain.info/tx/[transactionid]\n"
+ " the number of addresses.\n"
"\nExamples:\n"
"\nSend two amounts to two different addresses:\n"
+ HelpExampleCli("sendmany", "\"tabby\" \"{\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\\\":0.01,\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\"") +
@@ -853,7 +863,7 @@ Value sendmany(const Array& params, bool fHelp)
EnsureWalletIsUnlocked();
// Check funds
- int64_t nBalance = GetAccountBalance(strAccount, nMinDepth);
+ int64_t nBalance = GetAccountBalance(strAccount, nMinDepth, ISMINE_SPENDABLE);
if (totalAmount > nBalance)
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
@@ -922,10 +932,12 @@ struct tallyitem
int64_t nAmount;
int nConf;
vector<uint256> txids;
+ bool fIsWatchonly;
tallyitem()
{
nAmount = 0;
nConf = std::numeric_limits<int>::max();
+ fIsWatchonly = false;
}
};
@@ -941,6 +953,11 @@ Value ListReceived(const Array& params, bool fByAccounts)
if (params.size() > 1)
fIncludeEmpty = params[1].get_bool();
+ isminefilter filter = ISMINE_SPENDABLE;
+ if(params.size() > 2)
+ if(params[2].get_bool())
+ filter = filter | ISMINE_WATCH_ONLY;
+
// Tally
map<CBitcoinAddress, tallyitem> mapTally;
for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
@@ -957,13 +974,19 @@ Value ListReceived(const Array& params, bool fByAccounts)
BOOST_FOREACH(const CTxOut& txout, wtx.vout)
{
CTxDestination address;
- if (!ExtractDestination(txout.scriptPubKey, address) || !IsMine(*pwalletMain, address))
+ if (!ExtractDestination(txout.scriptPubKey, address))
+ continue;
+
+ isminefilter mine = IsMine(*pwalletMain, address);
+ if(!(mine & filter))
continue;
tallyitem& item = mapTally[address];
item.nAmount += txout.nValue;
item.nConf = min(item.nConf, nDepth);
item.txids.push_back(wtx.GetHash());
+ if (mine & ISMINE_WATCH_ONLY)
+ item.fIsWatchonly = true;
}
}
@@ -980,10 +1003,12 @@ Value ListReceived(const Array& params, bool fByAccounts)
int64_t nAmount = 0;
int nConf = std::numeric_limits<int>::max();
+ bool fIsWatchonly = false;
if (it != mapTally.end())
{
nAmount = (*it).second.nAmount;
nConf = (*it).second.nConf;
+ fIsWatchonly = (*it).second.fIsWatchonly;
}
if (fByAccounts)
@@ -991,10 +1016,13 @@ Value ListReceived(const Array& params, bool fByAccounts)
tallyitem& item = mapAccountTally[strAccount];
item.nAmount += nAmount;
item.nConf = min(item.nConf, nConf);
+ item.fIsWatchonly = fIsWatchonly;
}
else
{
Object obj;
+ if(fIsWatchonly)
+ obj.push_back(Pair("involvesWatchonly", true));
obj.push_back(Pair("address", address.ToString()));
obj.push_back(Pair("account", strAccount));
obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
@@ -1019,6 +1047,8 @@ Value ListReceived(const Array& params, bool fByAccounts)
int64_t nAmount = (*it).second.nAmount;
int nConf = (*it).second.nConf;
Object obj;
+ if((*it).second.fIsWatchonly)
+ obj.push_back(Pair("involvesWatchonly", true));
obj.push_back(Pair("account", (*it).first));
obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
@@ -1031,17 +1061,19 @@ Value ListReceived(const Array& params, bool fByAccounts)
Value listreceivedbyaddress(const Array& params, bool fHelp)
{
- if (fHelp || params.size() > 2)
+ if (fHelp || params.size() > 3)
throw runtime_error(
- "listreceivedbyaddress ( minconf includeempty )\n"
+ "listreceivedbyaddress ( minconf includeempty includeWatchonly)\n"
"\nList balances by receiving address.\n"
"\nArguments:\n"
"1. minconf (numeric, optional, default=1) The minimum number of confirmations before payments are included.\n"
"2. includeempty (numeric, optional, dafault=false) Whether to include addresses that haven't received any payments.\n"
+ "3. includeWatchonly (bool, optional, default=false) Whether to include watchonly addresses (see 'importaddress').\n"
"\nResult:\n"
"[\n"
" {\n"
+ " \"involvesWatchonly\" : \"true\", (bool) Only returned if imported addresses were involved in transaction\n"
" \"address\" : \"receivingaddress\", (string) The receiving address\n"
" \"account\" : \"accountname\", (string) The account of the receiving address. The default account is \"\".\n"
" \"amount\" : x.xxx, (numeric) The total amount in btc received by the address\n"
@@ -1053,7 +1085,7 @@ Value listreceivedbyaddress(const Array& params, bool fHelp)
"\nExamples:\n"
+ HelpExampleCli("listreceivedbyaddress", "")
+ HelpExampleCli("listreceivedbyaddress", "6 true")
- + HelpExampleRpc("listreceivedbyaddress", "6, true")
+ + HelpExampleRpc("listreceivedbyaddress", "6, true, true")
);
return ListReceived(params, false);
@@ -1061,17 +1093,19 @@ Value listreceivedbyaddress(const Array& params, bool fHelp)
Value listreceivedbyaccount(const Array& params, bool fHelp)
{
- if (fHelp || params.size() > 2)
+ if (fHelp || params.size() > 3)
throw runtime_error(
- "listreceivedbyaccount ( minconf includeempty )\n"
+ "listreceivedbyaccount ( minconf includeempty includeWatchonly)\n"
"\nList balances by account.\n"
"\nArguments:\n"
"1. minconf (numeric, optional, default=1) The minimum number of confirmations before payments are included.\n"
"2. includeempty (boolean, optional, default=false) Whether to include accounts that haven't received any payments.\n"
+ "3. includeWatchonly (bool, optional, default=false) Whether to include watchonly addresses (see 'importaddress').\n"
"\nResult:\n"
"[\n"
" {\n"
+ " \"involvesWatchonly\" : \"true\", (bool) Only returned if imported addresses were involved in transaction\n"
" \"account\" : \"accountname\", (string) The account name of the receiving account\n"
" \"amount\" : x.xxx, (numeric) The total amount received by addresses with this account\n"
" \"confirmations\" : n (numeric) The number of confirmations of the most recent transaction included\n"
@@ -1082,7 +1116,7 @@ Value listreceivedbyaccount(const Array& params, bool fHelp)
"\nExamples:\n"
+ HelpExampleCli("listreceivedbyaccount", "")
+ HelpExampleCli("listreceivedbyaccount", "6 true")
- + HelpExampleRpc("listreceivedbyaccount", "6, true")
+ + HelpExampleRpc("listreceivedbyaccount", "6, true, true")
);
return ListReceived(params, true);
@@ -1095,16 +1129,17 @@ static void MaybePushAddress(Object & entry, const CTxDestination &dest)
entry.push_back(Pair("address", addr.ToString()));
}
-void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret)
+void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret, const isminefilter& filter)
{
int64_t nFee;
string strSentAccount;
list<pair<CTxDestination, int64_t> > listReceived;
list<pair<CTxDestination, int64_t> > listSent;
- wtx.GetAmounts(listReceived, listSent, nFee, strSentAccount);
+ wtx.GetAmounts(listReceived, listSent, nFee, strSentAccount, filter);
bool fAllAccounts = (strAccount == string("*"));
+ bool involvesWatchonly = wtx.IsFromMe(ISMINE_WATCH_ONLY);
// Sent
if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
@@ -1112,6 +1147,8 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe
BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64_t)& s, listSent)
{
Object entry;
+ if(involvesWatchonly || (::IsMine(*pwalletMain, s.first) & ISMINE_WATCH_ONLY))
+ entry.push_back(Pair("involvesWatchonly", true));
entry.push_back(Pair("account", strSentAccount));
MaybePushAddress(entry, s.first);
entry.push_back(Pair("category", "send"));
@@ -1134,6 +1171,8 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe
if (fAllAccounts || (account == strAccount))
{
Object entry;
+ if(involvesWatchonly || (::IsMine(*pwalletMain, r.first) & ISMINE_WATCH_ONLY))
+ entry.push_back(Pair("involvesWatchonly", true));
entry.push_back(Pair("account", account));
MaybePushAddress(entry, r.first);
if (wtx.IsCoinBase())
@@ -1177,16 +1216,16 @@ void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Ar
Value listtransactions(const Array& params, bool fHelp)
{
- if (fHelp || params.size() > 3)
+ if (fHelp || params.size() > 4)
throw runtime_error(
- "listtransactions ( \"account\" count from )\n"
+ "listtransactions ( \"account\" count from includeWatchonly)\n"
"\nReturns up to 'count' most recent transactions skipping the first 'from' transactions for account 'account'.\n"
"\nArguments:\n"
"1. \"account\" (string, optional) The account name. If not included, it will list all transactions for all accounts.\n"
" If \"\" is set, it will list transactions for the default account.\n"
"2. count (numeric, optional, default=10) The number of transactions to return\n"
"3. from (numeric, optional, default=0) The number of transactions to skip\n"
-
+ "4. includeWatchonly (bool, optional, default=false) Include transactions to watchonly addresses (see 'importaddress')\n"
"\nResult:\n"
"[\n"
" {\n"
@@ -1209,8 +1248,13 @@ Value listtransactions(const Array& params, bool fHelp)
" category of transactions.\n"
" \"blockindex\": n, (numeric) The block index containing the transaction. Available for 'send' and 'receive'\n"
" category of transactions.\n"
- " \"txid\": \"transactionid\", (string) The transaction id (see https://blockchain.info/tx/[transactionid]. Available \n"
- " for 'send' and 'receive' category of transactions.\n"
+ " \"txid\": \"transactionid\", (string) The transaction id. Available for 'send' and 'receive' category of transactions.\n"
+ " \"walletconflicts\" : [\n"
+ " \"conflictid\", (string) Ids of transactions, including equivalent clones, that re-spend a txid input.\n"
+ " ],\n"
+ " \"respendsobserved\" : [\n"
+ " \"respendid\", (string) Ids of transactions, NOT equivalent clones, that re-spend a txid input. \"Double-spends.\"\n"
+ " ],\n"
" \"time\": xxx, (numeric) The transaction time in seconds since epoch (midnight Jan 1 1970 GMT).\n"
" \"timereceived\": xxx, (numeric) The time received in seconds since epoch (midnight Jan 1 1970 GMT). Available \n"
" for 'send' and 'receive' category of transactions.\n"
@@ -1241,6 +1285,10 @@ Value listtransactions(const Array& params, bool fHelp)
int nFrom = 0;
if (params.size() > 2)
nFrom = params[2].get_int();
+ isminefilter filter = ISMINE_SPENDABLE;
+ if(params.size() > 3)
+ if(params[3].get_bool())
+ filter = filter | ISMINE_WATCH_ONLY;
if (nCount < 0)
throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative count");
@@ -1257,7 +1305,7 @@ Value listtransactions(const Array& params, bool fHelp)
{
CWalletTx *const pwtx = (*it).second.first;
if (pwtx != 0)
- ListTransactions(*pwtx, strAccount, 0, true, ret);
+ ListTransactions(*pwtx, strAccount, 0, true, ret, filter);
CAccountingEntry *const pacentry = (*it).second.second;
if (pacentry != 0)
AcentryToJSON(*pacentry, strAccount, ret);
@@ -1285,12 +1333,13 @@ Value listtransactions(const Array& params, bool fHelp)
Value listaccounts(const Array& params, bool fHelp)
{
- if (fHelp || params.size() > 1)
+ if (fHelp || params.size() > 2)
throw runtime_error(
- "listaccounts ( minconf )\n"
+ "listaccounts ( minconf includeWatchonly)\n"
"\nReturns Object that has account names as keys, account balances as values.\n"
"\nArguments:\n"
- "1. minconf (numeric, optional, default=1) Only onclude transactions with at least this many confirmations\n"
+ "1. minconf (numeric, optional, default=1) Only onclude transactions with at least this many confirmations\n"
+ "2. includeWatchonly (bool, optional, default=false) Include balances in watchonly addresses (see 'importaddress')\n"
"\nResult:\n"
"{ (json object where keys are account names, and values are numeric balances\n"
" \"account\": x.xxx, (numeric) The property name is the account name, and the value is the total balance for the account.\n"
@@ -1310,10 +1359,14 @@ Value listaccounts(const Array& params, bool fHelp)
int nMinDepth = 1;
if (params.size() > 0)
nMinDepth = params[0].get_int();
+ isminefilter includeWatchonly = ISMINE_SPENDABLE;
+ if(params.size() > 1)
+ if(params[1].get_bool())
+ includeWatchonly = includeWatchonly | ISMINE_WATCH_ONLY;
map<string, int64_t> mapAccountBalances;
BOOST_FOREACH(const PAIRTYPE(CTxDestination, CAddressBookData)& entry, pwalletMain->mapAddressBook) {
- if (IsMine(*pwalletMain, entry.first)) // This address belongs to me
+ if (IsMine(*pwalletMain, entry.first) & includeWatchonly) // This address belongs to me
mapAccountBalances[entry.second.name] = 0;
}
@@ -1327,7 +1380,7 @@ Value listaccounts(const Array& params, bool fHelp)
int nDepth = wtx.GetDepthInMainChain();
if (wtx.GetBlocksToMaturity() > 0 || nDepth < 0)
continue;
- wtx.GetAmounts(listReceived, listSent, nFee, strSentAccount);
+ wtx.GetAmounts(listReceived, listSent, nFee, strSentAccount, includeWatchonly);
mapAccountBalances[strSentAccount] -= nFee;
BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64_t)& s, listSent)
mapAccountBalances[strSentAccount] -= s.second;
@@ -1357,11 +1410,12 @@ Value listsinceblock(const Array& params, bool fHelp)
{
if (fHelp)
throw runtime_error(
- "listsinceblock ( \"blockhash\" target-confirmations )\n"
+ "listsinceblock ( \"blockhash\" target-confirmations includeWatchonly)\n"
"\nGet all transactions in blocks since block [blockhash], or all transactions if omitted\n"
"\nArguments:\n"
"1. \"blockhash\" (string, optional) The block hash to list transactions since\n"
"2. target-confirmations: (numeric, optional) The confirmations required, must be 1 or more\n"
+ "3. includeWatchonly: (bool, optional, default=false) Include transactions to watchonly addresses (see 'importaddress')"
"\nResult:\n"
"{\n"
" \"transactions\": [\n"
@@ -1375,7 +1429,13 @@ Value listsinceblock(const Array& params, bool fHelp)
" \"blockhash\": \"hashvalue\", (string) The block hash containing the transaction. Available for 'send' and 'receive' category of transactions.\n"
" \"blockindex\": n, (numeric) The block index containing the transaction. Available for 'send' and 'receive' category of transactions.\n"
" \"blocktime\": xxx, (numeric) The block time in seconds since epoch (1 Jan 1970 GMT).\n"
- " \"txid\": \"transactionid\", (string) The transaction id (see https://blockchain.info/tx/[transactionid]. Available for 'send' and 'receive' category of transactions.\n"
+ " \"txid\": \"transactionid\", (string) The transaction id. Available for 'send' and 'receive' category of transactions.\n"
+ " \"walletconflicts\" : [\n"
+ " \"conflictid\", (string) Ids of transactions, including equivalent clones, that re-spend a txid input.\n"
+ " ],\n"
+ " \"respendsobserved\" : [\n"
+ " \"respendid\", (string) Ids of transactions, NOT equivalent clones, that re-spend a txid input. \"Double-spends.\"\n"
+ " ],\n"
" \"time\": xxx, (numeric) The transaction time in seconds since epoch (Jan 1 1970 GMT).\n"
" \"timereceived\": xxx, (numeric) The time received in seconds since epoch (Jan 1 1970 GMT). Available for 'send' and 'receive' category of transactions.\n"
" \"comment\": \"...\", (string) If a comment is associated with the transaction.\n"
@@ -1391,6 +1451,7 @@ Value listsinceblock(const Array& params, bool fHelp)
CBlockIndex *pindex = NULL;
int target_confirms = 1;
+ isminefilter filter = ISMINE_SPENDABLE;
if (params.size() > 0)
{
@@ -1410,6 +1471,10 @@ Value listsinceblock(const Array& params, bool fHelp)
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter");
}
+ if(params.size() > 2)
+ if(params[2].get_bool())
+ filter = filter | ISMINE_WATCH_ONLY;
+
int depth = pindex ? (1 + chainActive.Height() - pindex->nHeight) : -1;
Array transactions;
@@ -1419,7 +1484,7 @@ Value listsinceblock(const Array& params, bool fHelp)
CWalletTx tx = (*it).second;
if (depth == -1 || tx.GetDepthInMainChain() < depth)
- ListTransactions(tx, "*", 0, true, transactions);
+ ListTransactions(tx, "*", 0, true, transactions, filter);
}
CBlockIndex *pblockLast = chainActive[chainActive.Height() + 1 - target_confirms];
@@ -1434,12 +1499,13 @@ Value listsinceblock(const Array& params, bool fHelp)
Value gettransaction(const Array& params, bool fHelp)
{
- if (fHelp || params.size() != 1)
+ if (fHelp || params.size() < 1 || params.size() > 2)
throw runtime_error(
"gettransaction \"txid\"\n"
"\nGet detailed information about in-wallet transaction <txid>\n"
"\nArguments:\n"
"1. \"txid\" (string, required) The transaction id\n"
+ "2. \"includeWatchonly\" (bool, optional, default=false) Whether to include watchonly addresses in balance calculation and details[]\n"
"\nResult:\n"
"{\n"
" \"amount\" : x.xxx, (numeric) The transaction amount in btc\n"
@@ -1447,7 +1513,13 @@ Value gettransaction(const Array& params, bool fHelp)
" \"blockhash\" : \"hash\", (string) The block hash\n"
" \"blockindex\" : xx, (numeric) The block index\n"
" \"blocktime\" : ttt, (numeric) The time in seconds since epoch (1 Jan 1970 GMT)\n"
- " \"txid\" : \"transactionid\", (string) The transaction id, see also https://blockchain.info/tx/[transactionid]\n"
+ " \"txid\" : \"transactionid\", (string) The transaction id.\n"
+ " \"walletconflicts\" : [\n"
+ " \"conflictid\", (string) Ids of transactions, including equivalent clones, that re-spend a txid input.\n"
+ " ],\n"
+ " \"respendsobserved\" : [\n"
+ " \"respendid\", (string) Ids of transactions, NOT equivalent clones, that re-spend a txid input. \"Double-spends.\"\n"
+ " ],\n"
" \"time\" : ttt, (numeric) The transaction time in seconds since epoch (1 Jan 1970 GMT)\n"
" \"timereceived\" : ttt, (numeric) The time received in seconds since epoch (1 Jan 1970 GMT)\n"
" \"details\" : [\n"
@@ -1470,24 +1542,29 @@ Value gettransaction(const Array& params, bool fHelp)
uint256 hash;
hash.SetHex(params[0].get_str());
+ isminefilter filter = ISMINE_SPENDABLE;
+ if(params.size() > 1)
+ if(params[1].get_bool())
+ filter = filter | ISMINE_WATCH_ONLY;
+
Object entry;
if (!pwalletMain->mapWallet.count(hash))
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid or non-wallet transaction id");
const CWalletTx& wtx = pwalletMain->mapWallet[hash];
- int64_t nCredit = wtx.GetCredit();
- int64_t nDebit = wtx.GetDebit();
+ int64_t nCredit = wtx.GetCredit(filter);
+ int64_t nDebit = wtx.GetDebit(filter);
int64_t nNet = nCredit - nDebit;
- int64_t nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0);
+ int64_t nFee = (wtx.IsFromMe(filter) ? wtx.GetValueOut() - nDebit : 0);
entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
- if (wtx.IsFromMe())
+ if (wtx.IsFromMe(filter))
entry.push_back(Pair("fee", ValueFromAmount(nFee)));
WalletTxToJSON(wtx, entry);
Array details;
- ListTransactions(wtx, "*", 0, false, details);
+ ListTransactions(wtx, "*", 0, false, details, filter);
entry.push_back(Pair("details", details));
CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
@@ -1884,7 +1961,7 @@ Value settxfee(const Array& params, bool fHelp)
if (params[0].get_real() != 0.0)
nAmount = AmountFromValue(params[0]); // rejects 0.0 amounts
- nTransactionFee = nAmount;
+ payTxFee = CFeeRate(nAmount, 1000);
return true;
}
diff --git a/src/script.cpp b/src/script.cpp
index ac6d4b316f..238a25e72d 100644
--- a/src/script.cpp
+++ b/src/script.cpp
@@ -9,6 +9,9 @@
#include "hash.h"
#include "key.h"
#include "keystore.h"
+#include "crypto/sha1.h"
+#include "crypto/sha2.h"
+#include "crypto/ripemd160.h"
#include "sync.h"
#include "uint256.h"
#include "util.h"
@@ -208,14 +211,13 @@ const char* GetOpName(opcodetype opcode)
case OP_NOP9 : return "OP_NOP9";
case OP_NOP10 : return "OP_NOP10";
+ case OP_INVALIDOPCODE : return "OP_INVALIDOPCODE";
+ // Note:
+ // The template matching params OP_SMALLDATA/etc are defined in opcodetype enum
+ // as kind of implementation hack, they are *NOT* real opcodes. If found in real
+ // Script, just let the default: case deal with them.
- // template matching params
- case OP_PUBKEYHASH : return "OP_PUBKEYHASH";
- case OP_PUBKEY : return "OP_PUBKEY";
- case OP_SMALLDATA : return "OP_SMALLDATA";
-
- case OP_INVALIDOPCODE : return "OP_INVALIDOPCODE";
default:
return "OP_UNKNOWN";
}
@@ -802,21 +804,15 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co
valtype& vch = stacktop(-1);
valtype vchHash((opcode == OP_RIPEMD160 || opcode == OP_SHA1 || opcode == OP_HASH160) ? 20 : 32);
if (opcode == OP_RIPEMD160)
- RIPEMD160(&vch[0], vch.size(), &vchHash[0]);
+ CRIPEMD160().Write(&vch[0], vch.size()).Finalize(&vchHash[0]);
else if (opcode == OP_SHA1)
- SHA1(&vch[0], vch.size(), &vchHash[0]);
+ CSHA1().Write(&vch[0], vch.size()).Finalize(&vchHash[0]);
else if (opcode == OP_SHA256)
- SHA256(&vch[0], vch.size(), &vchHash[0]);
+ CSHA256().Write(&vch[0], vch.size()).Finalize(&vchHash[0]);
else if (opcode == OP_HASH160)
- {
- uint160 hash160 = Hash160(vch);
- memcpy(&vchHash[0], &hash160, sizeof(hash160));
- }
+ CHash160().Write(&vch[0], vch.size()).Finalize(&vchHash[0]);
else if (opcode == OP_HASH256)
- {
- uint256 hash = Hash(vch.begin(), vch.end());
- memcpy(&vchHash[0], &hash, sizeof(hash));
- }
+ CHash256().Write(&vch[0], vch.size()).Finalize(&vchHash[0]);
popstack(stack);
stack.push_back(vchHash);
}
@@ -839,10 +835,6 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co
valtype& vchSig = stacktop(-2);
valtype& vchPubKey = stacktop(-1);
- ////// debug print
- //PrintHex(vchSig.begin(), vchSig.end(), "sig: %s\n");
- //PrintHex(vchPubKey.begin(), vchPubKey.end(), "pubkey: %s\n");
-
// Subset of script starting at the most recent codeseparator
CScript scriptCode(pbegincodehash, pend);
@@ -982,6 +974,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co
namespace {
+
/** Wrapper that serializes like CTransaction, but with the modifications
* required for the signature hash done in-place
*/
@@ -1074,7 +1067,8 @@ public:
::Serialize(s, txTo.nLockTime, nType, nVersion);
}
};
-}
+
+} // anon namespace
uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType)
{
@@ -1100,7 +1094,6 @@ uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsig
return ss.GetHash();
}
-
// Valid signature cache, to avoid doing expensive ECDSA signature checking
// twice for every transaction (once when accepted into memory pool, and
// again when accepted into the block chain)
@@ -1216,7 +1209,8 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector<vector<unsi
mTemplates.insert(make_pair(TX_MULTISIG, CScript() << OP_SMALLINTEGER << OP_PUBKEYS << OP_SMALLINTEGER << OP_CHECKMULTISIG));
// Empty, provably prunable, data-carrying output
- mTemplates.insert(make_pair(TX_NULL_DATA, CScript() << OP_RETURN << OP_SMALLDATA));
+ if (GetBoolArg("-datacarrier", true))
+ mTemplates.insert(make_pair(TX_NULL_DATA, CScript() << OP_RETURN << OP_SMALLDATA));
mTemplates.insert(make_pair(TX_NULL_DATA, CScript() << OP_RETURN));
}
@@ -1462,36 +1456,49 @@ public:
bool operator()(const CScriptID &scriptID) const { return keystore->HaveCScript(scriptID); }
};
-bool IsMine(const CKeyStore &keystore, const CTxDestination &dest)
+isminetype IsMine(const CKeyStore &keystore, const CTxDestination& dest)
{
- return boost::apply_visitor(CKeyStoreIsMineVisitor(&keystore), dest);
+ CScript script;
+ script.SetDestination(dest);
+ return IsMine(keystore, script);
}
-bool IsMine(const CKeyStore &keystore, const CScript& scriptPubKey)
+isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey)
{
vector<valtype> vSolutions;
txnouttype whichType;
- if (!Solver(scriptPubKey, whichType, vSolutions))
- return false;
+ if (!Solver(scriptPubKey, whichType, vSolutions)) {
+ if (keystore.HaveWatchOnly(scriptPubKey))
+ return ISMINE_WATCH_ONLY;
+ return ISMINE_NO;
+ }
CKeyID keyID;
switch (whichType)
{
case TX_NONSTANDARD:
case TX_NULL_DATA:
- return false;
+ break;
case TX_PUBKEY:
keyID = CPubKey(vSolutions[0]).GetID();
- return keystore.HaveKey(keyID);
+ if (keystore.HaveKey(keyID))
+ return ISMINE_SPENDABLE;
+ break;
case TX_PUBKEYHASH:
keyID = CKeyID(uint160(vSolutions[0]));
- return keystore.HaveKey(keyID);
+ if (keystore.HaveKey(keyID))
+ return ISMINE_SPENDABLE;
+ break;
case TX_SCRIPTHASH:
{
+ CScriptID scriptID = CScriptID(uint160(vSolutions[0]));
CScript subscript;
- if (!keystore.GetCScript(CScriptID(uint160(vSolutions[0])), subscript))
- return false;
- return IsMine(keystore, subscript);
+ if (keystore.GetCScript(scriptID, subscript)) {
+ isminetype ret = IsMine(keystore, subscript);
+ if (ret == ISMINE_SPENDABLE)
+ return ret;
+ }
+ break;
}
case TX_MULTISIG:
{
@@ -1501,10 +1508,15 @@ bool IsMine(const CKeyStore &keystore, const CScript& scriptPubKey)
// them) enable spend-out-from-under-you attacks, especially
// in shared-wallet situations.
vector<valtype> keys(vSolutions.begin()+1, vSolutions.begin()+vSolutions.size()-1);
- return HaveKeys(keys, keystore) == keys.size();
+ if (HaveKeys(keys, keystore) == keys.size())
+ return ISMINE_SPENDABLE;
+ break;
}
}
- return false;
+
+ if (keystore.HaveWatchOnly(scriptPubKey))
+ return ISMINE_WATCH_ONLY;
+ return ISMINE_NO;
}
bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet)
@@ -1644,7 +1656,7 @@ bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const C
}
-bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CTransaction& txTo, unsigned int nIn, int nHashType)
+bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, int nHashType)
{
assert(nIn < txTo.vin.size());
CTxIn& txin = txTo.vin[nIn];
@@ -1679,7 +1691,7 @@ bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CTransa
return VerifyScript(txin.scriptSig, fromPubKey, txTo, nIn, STANDARD_SCRIPT_VERIFY_FLAGS, 0);
}
-bool SignSignature(const CKeyStore &keystore, const CTransaction& txFrom, CTransaction& txTo, unsigned int nIn, int nHashType)
+bool SignSignature(const CKeyStore &keystore, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType)
{
assert(nIn < txTo.vin.size());
CTxIn& txin = txTo.vin[nIn];
@@ -1697,7 +1709,7 @@ static CScript PushAll(const vector<valtype>& values)
return result;
}
-static CScript CombineMultisig(CScript scriptPubKey, const CTransaction& txTo, unsigned int nIn,
+static CScript CombineMultisig(CScript scriptPubKey, const CMutableTransaction& txTo, unsigned int nIn,
const vector<valtype>& vSolutions,
vector<valtype>& sigs1, vector<valtype>& sigs2)
{
diff --git a/src/script.h b/src/script.h
index 0d8a8544bd..e36be2db9e 100644
--- a/src/script.h
+++ b/src/script.h
@@ -20,6 +20,7 @@
class CCoins;
class CKeyStore;
class CTransaction;
+struct CMutableTransaction;
static const unsigned int MAX_SCRIPT_ELEMENT_SIZE = 520; // bytes
static const unsigned int MAX_OP_RETURN_RELAY = 40; // bytes
@@ -193,6 +194,17 @@ enum
SCRIPT_VERIFY_NULLDUMMY = (1U << 4), // verify dummy stack item consumed by CHECKMULTISIG is of zero-length
};
+/** IsMine() return codes */
+enum isminetype
+{
+ ISMINE_NO = 0,
+ ISMINE_WATCH_ONLY = 1,
+ ISMINE_SPENDABLE = 2,
+ ISMINE_ALL = ISMINE_WATCH_ONLY | ISMINE_SPENDABLE
+};
+/** used for bitflags of isminetype */
+typedef uint8_t isminefilter;
+
// Mandatory script verification flags that all new blocks must comply with for
// them to be valid. (but old blocks may not comply with) Currently just P2SH,
// but in the future other flags may be added, such as a soft-fork to enforce
@@ -691,12 +703,6 @@ public:
void SetDestination(const CTxDestination& address);
void SetMultisig(int nRequired, const std::vector<CPubKey>& keys);
-
- void PrintHex() const
- {
- LogPrintf("CScript(%s)\n", HexStr(begin(), end(), true).c_str());
- }
-
std::string ToString() const
{
std::string str;
@@ -720,11 +726,6 @@ public:
return str;
}
- void print() const
- {
- LogPrintf("%s\n", ToString().c_str());
- }
-
CScriptID GetID() const
{
return CScriptID(Hash160(*this));
@@ -780,12 +781,12 @@ public:
void Serialize(Stream &s, int nType, int nVersion) const {
std::vector<unsigned char> compr;
if (Compress(compr)) {
- s << CFlatData(&compr[0], &compr[compr.size()]);
+ s << CFlatData(compr);
return;
}
unsigned int nSize = script.size() + nSpecialScripts;
s << VARINT(nSize);
- s << CFlatData(&script[0], &script[script.size()]);
+ s << CFlatData(script);
}
template<typename Stream>
@@ -794,13 +795,13 @@ public:
s >> VARINT(nSize);
if (nSize < nSpecialScripts) {
std::vector<unsigned char> vch(GetSpecialSize(nSize), 0x00);
- s >> REF(CFlatData(&vch[0], &vch[vch.size()]));
+ s >> REF(CFlatData(vch));
Decompress(nSize, vch);
return;
}
nSize -= nSpecialScripts;
script.resize(nSize);
- s >> REF(CFlatData(&script[0], &script[script.size()]));
+ s >> REF(CFlatData(script));
}
};
@@ -811,13 +812,13 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<std::vector<unsigned char> >& vSolutionsRet);
int ScriptSigArgsExpected(txnouttype t, const std::vector<std::vector<unsigned char> >& vSolutions);
bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType);
-bool IsMine(const CKeyStore& keystore, const CScript& scriptPubKey);
-bool IsMine(const CKeyStore& keystore, const CTxDestination &dest);
+isminetype IsMine(const CKeyStore& keystore, const CScript& scriptPubKey);
+isminetype IsMine(const CKeyStore& keystore, const CTxDestination& dest);
void ExtractAffectedKeys(const CKeyStore &keystore, const CScript& scriptPubKey, std::vector<CKeyID> &vKeys);
bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet);
bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<CTxDestination>& addressRet, int& nRequiredRet);
-bool SignSignature(const CKeyStore& keystore, const CScript& fromPubKey, CTransaction& txTo, unsigned int nIn, int nHashType=SIGHASH_ALL);
-bool SignSignature(const CKeyStore& keystore, const CTransaction& txFrom, CTransaction& txTo, unsigned int nIn, int nHashType=SIGHASH_ALL);
+bool SignSignature(const CKeyStore& keystore, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, int nHashType=SIGHASH_ALL);
+bool SignSignature(const CKeyStore& keystore, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType=SIGHASH_ALL);
bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, unsigned int flags, int nHashType);
// Given two sets of signatures for scriptPubKey, possibly with OP_0 placeholders,
diff --git a/src/secp256k1/.empty b/src/secp256k1/.empty
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/src/secp256k1/.empty
diff --git a/src/serialize.h b/src/serialize.h
index 1341746592..5ac85554c6 100644
--- a/src/serialize.h
+++ b/src/serialize.h
@@ -37,6 +37,34 @@ inline T& REF(const T& val)
return const_cast<T&>(val);
}
+/** Get begin pointer of vector (non-const version).
+ * @note These functions avoid the undefined case of indexing into an empty
+ * vector, as well as that of indexing after the end of the vector.
+ */
+template <class T, class TAl>
+inline T* begin_ptr(std::vector<T,TAl>& v)
+{
+ return v.empty() ? NULL : &v[0];
+}
+/** Get begin pointer of vector (const version) */
+template <class T, class TAl>
+inline const T* begin_ptr(const std::vector<T,TAl>& v)
+{
+ return v.empty() ? NULL : &v[0];
+}
+/** Get end pointer of vector (non-const version) */
+template <class T, class TAl>
+inline T* end_ptr(std::vector<T,TAl>& v)
+{
+ return v.empty() ? NULL : (&v[0] + v.size());
+}
+/** Get end pointer of vector (const version) */
+template <class T, class TAl>
+inline const T* end_ptr(const std::vector<T,TAl>& v)
+{
+ return v.empty() ? NULL : (&v[0] + v.size());
+}
+
/////////////////////////////////////////////////////////////////
//
// Templates for serializing to anything that looks like a stream,
@@ -318,6 +346,12 @@ protected:
char* pend;
public:
CFlatData(void* pbeginIn, void* pendIn) : pbegin((char*)pbeginIn), pend((char*)pendIn) { }
+ template <class T, class TAl>
+ explicit CFlatData(std::vector<T,TAl> &v)
+ {
+ pbegin = (char*)begin_ptr(v);
+ pend = (char*)end_ptr(v);
+ }
char* begin() { return pbegin; }
const char* begin() const { return pbegin; }
char* end() { return pend; }
diff --git a/src/test/DoS_tests.cpp b/src/test/DoS_tests.cpp
index fb06fb3435..5e17555e7a 100644
--- a/src/test/DoS_tests.cpp
+++ b/src/test/DoS_tests.cpp
@@ -11,6 +11,7 @@
#include "keystore.h"
#include "main.h"
#include "net.h"
+#include "pow.h"
#include "script.h"
#include "serialize.h"
@@ -167,7 +168,7 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans)
// 50 orphan transactions:
for (int i = 0; i < 50; i++)
{
- CTransaction tx;
+ CMutableTransaction tx;
tx.vin.resize(1);
tx.vin[0].prevout.n = 0;
tx.vin[0].prevout.hash = GetRandHash();
@@ -184,7 +185,7 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans)
{
CTransaction txPrev = RandomOrphan();
- CTransaction tx;
+ CMutableTransaction tx;
tx.vin.resize(1);
tx.vin[0].prevout.n = 0;
tx.vin[0].prevout.hash = txPrev.GetHash();
@@ -201,7 +202,7 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans)
{
CTransaction txPrev = RandomOrphan();
- CTransaction tx;
+ CMutableTransaction tx;
tx.vout.resize(1);
tx.vout[0].nValue = 1*CENT;
tx.vout[0].scriptPubKey.SetDestination(key.GetPubKey().GetID());
@@ -230,91 +231,4 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans)
BOOST_CHECK(mapOrphanTransactionsByPrev.empty());
}
-BOOST_AUTO_TEST_CASE(DoS_checkSig)
-{
- // Test signature caching code (see key.cpp Verify() methods)
-
- CKey key;
- key.MakeNewKey(true);
- CBasicKeyStore keystore;
- keystore.AddKey(key);
- unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC;
-
- // 100 orphan transactions:
- static const int NPREV=100;
- CTransaction orphans[NPREV];
- for (int i = 0; i < NPREV; i++)
- {
- CTransaction& tx = orphans[i];
- tx.vin.resize(1);
- tx.vin[0].prevout.n = 0;
- tx.vin[0].prevout.hash = GetRandHash();
- tx.vin[0].scriptSig << OP_1;
- tx.vout.resize(1);
- tx.vout[0].nValue = 1*CENT;
- tx.vout[0].scriptPubKey.SetDestination(key.GetPubKey().GetID());
-
- AddOrphanTx(tx);
- }
-
- // Create a transaction that depends on orphans:
- CTransaction tx;
- tx.vout.resize(1);
- tx.vout[0].nValue = 1*CENT;
- tx.vout[0].scriptPubKey.SetDestination(key.GetPubKey().GetID());
- tx.vin.resize(NPREV);
- for (unsigned int j = 0; j < tx.vin.size(); j++)
- {
- tx.vin[j].prevout.n = 0;
- tx.vin[j].prevout.hash = orphans[j].GetHash();
- }
- // Creating signatures primes the cache:
- boost::posix_time::ptime mst1 = boost::posix_time::microsec_clock::local_time();
- for (unsigned int j = 0; j < tx.vin.size(); j++)
- BOOST_CHECK(SignSignature(keystore, orphans[j], tx, j));
- boost::posix_time::ptime mst2 = boost::posix_time::microsec_clock::local_time();
- boost::posix_time::time_duration msdiff = mst2 - mst1;
- long nOneValidate = msdiff.total_milliseconds();
- if (fDebug) printf("DoS_Checksig sign: %ld\n", nOneValidate);
-
- // ... now validating repeatedly should be quick:
- // 2.8GHz machine, -g build: Sign takes ~760ms,
- // uncached Verify takes ~250ms, cached Verify takes ~50ms
- // (for 100 single-signature inputs)
- mst1 = boost::posix_time::microsec_clock::local_time();
- for (unsigned int i = 0; i < 5; i++)
- for (unsigned int j = 0; j < tx.vin.size(); j++)
- BOOST_CHECK(VerifySignature(CCoins(orphans[j], MEMPOOL_HEIGHT), tx, j, flags, SIGHASH_ALL));
- mst2 = boost::posix_time::microsec_clock::local_time();
- msdiff = mst2 - mst1;
- long nManyValidate = msdiff.total_milliseconds();
- if (fDebug) printf("DoS_Checksig five: %ld\n", nManyValidate);
-
- BOOST_CHECK_MESSAGE(nManyValidate < nOneValidate, "Signature cache timing failed");
-
- // Empty a signature, validation should fail:
- CScript save = tx.vin[0].scriptSig;
- tx.vin[0].scriptSig = CScript();
- BOOST_CHECK(!VerifySignature(CCoins(orphans[0], MEMPOOL_HEIGHT), tx, 0, flags, SIGHASH_ALL));
- tx.vin[0].scriptSig = save;
-
- // Swap signatures, validation should fail:
- std::swap(tx.vin[0].scriptSig, tx.vin[1].scriptSig);
- BOOST_CHECK(!VerifySignature(CCoins(orphans[0], MEMPOOL_HEIGHT), tx, 0, flags, SIGHASH_ALL));
- BOOST_CHECK(!VerifySignature(CCoins(orphans[1], MEMPOOL_HEIGHT), tx, 1, flags, SIGHASH_ALL));
- std::swap(tx.vin[0].scriptSig, tx.vin[1].scriptSig);
-
- // Exercise -maxsigcachesize code:
- mapArgs["-maxsigcachesize"] = "10";
- // Generate a new, different signature for vin[0] to trigger cache clear:
- CScript oldSig = tx.vin[0].scriptSig;
- BOOST_CHECK(SignSignature(keystore, orphans[0], tx, 0));
- BOOST_CHECK(tx.vin[0].scriptSig != oldSig);
- for (unsigned int j = 0; j < tx.vin.size(); j++)
- BOOST_CHECK(VerifySignature(CCoins(orphans[j], MEMPOOL_HEIGHT), tx, j, flags, SIGHASH_ALL));
- mapArgs.erase("-maxsigcachesize");
-
- LimitOrphanTxSize(0);
-}
-
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/Makefile b/src/test/Makefile
new file mode 100644
index 0000000000..87bf73fec9
--- /dev/null
+++ b/src/test/Makefile
@@ -0,0 +1,6 @@
+all:
+ $(MAKE) -C .. bitcoin_test
+clean:
+ $(MAKE) -C .. bitcoin_test_clean
+check:
+ $(MAKE) -C .. bitcoin_test_check
diff --git a/src/test/Makefile.am b/src/test/Makefile.am
deleted file mode 100644
index cde3a31e2f..0000000000
--- a/src/test/Makefile.am
+++ /dev/null
@@ -1,77 +0,0 @@
-include $(top_srcdir)/src/Makefile.include
-
-AM_CPPFLAGS += -I$(top_srcdir)/src
-
-bin_PROGRAMS = test_bitcoin
-
-TESTS = test_bitcoin
-
-JSON_TEST_FILES = \
- data/script_valid.json \
- data/base58_keys_valid.json \
- data/sig_canonical.json \
- data/sig_noncanonical.json \
- data/base58_encode_decode.json \
- data/base58_keys_invalid.json \
- data/script_invalid.json \
- data/tx_invalid.json \
- data/tx_valid.json \
- data/sighash.json
-
-RAW_TEST_FILES = data/alertTests.raw
-
-BUILT_SOURCES = $(JSON_TEST_FILES:.json=.json.h) $(RAW_TEST_FILES:.raw=.raw.h)
-
-# test_bitcoin binary #
-test_bitcoin_CPPFLAGS = $(AM_CPPFLAGS) $(TESTDEFS)
-test_bitcoin_LDADD = $(LIBBITCOIN_SERVER) $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBLEVELDB) $(LIBMEMENV) \
- $(BOOST_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIB)
-if ENABLE_WALLET
-test_bitcoin_LDADD += $(LIBBITCOIN_WALLET)
-endif
-test_bitcoin_LDADD += $(BDB_LIBS)
-
-test_bitcoin_SOURCES = \
- bignum.h \
- alert_tests.cpp \
- allocator_tests.cpp \
- base32_tests.cpp \
- base58_tests.cpp \
- base64_tests.cpp \
- bloom_tests.cpp \
- canonical_tests.cpp \
- checkblock_tests.cpp \
- Checkpoints_tests.cpp \
- compress_tests.cpp \
- DoS_tests.cpp \
- getarg_tests.cpp \
- key_tests.cpp \
- main_tests.cpp \
- miner_tests.cpp \
- mruset_tests.cpp \
- multisig_tests.cpp \
- netbase_tests.cpp \
- pmt_tests.cpp \
- rpc_tests.cpp \
- script_P2SH_tests.cpp \
- script_tests.cpp \
- serialize_tests.cpp \
- sigopcount_tests.cpp \
- test_bitcoin.cpp \
- transaction_tests.cpp \
- uint256_tests.cpp \
- util_tests.cpp \
- scriptnum_tests.cpp \
- sighash_tests.cpp \
- $(JSON_TEST_FILES) $(RAW_TEST_FILES)
-
-if ENABLE_WALLET
-test_bitcoin_SOURCES += \
- accounting_tests.cpp \
- wallet_tests.cpp \
- rpc_wallet_tests.cpp
-endif
-
-nodist_test_bitcoin_SOURCES = $(BUILT_SOURCES)
-
-CLEANFILES = *.gcda *.gcno $(BUILT_SOURCES)
diff --git a/src/test/accounting_tests.cpp b/src/test/accounting_tests.cpp
index e2a75da349..4bee0f6b6e 100644
--- a/src/test/accounting_tests.cpp
+++ b/src/test/accounting_tests.cpp
@@ -83,13 +83,21 @@ BOOST_AUTO_TEST_CASE(acc_orderupgrade)
wtx.mapValue["comment"] = "y";
- --wtx.nLockTime; // Just to change the hash :)
+ {
+ CMutableTransaction tx(wtx);
+ --tx.nLockTime; // Just to change the hash :)
+ *static_cast<CTransaction*>(&wtx) = CTransaction(tx);
+ }
pwalletMain->AddToWallet(wtx);
vpwtx.push_back(&pwalletMain->mapWallet[wtx.GetHash()]);
vpwtx[1]->nTimeReceived = (unsigned int)1333333336;
wtx.mapValue["comment"] = "x";
- --wtx.nLockTime; // Just to change the hash :)
+ {
+ CMutableTransaction tx(wtx);
+ --tx.nLockTime; // Just to change the hash :)
+ *static_cast<CTransaction*>(&wtx) = CTransaction(tx);
+ }
pwalletMain->AddToWallet(wtx);
vpwtx.push_back(&pwalletMain->mapWallet[wtx.GetHash()]);
vpwtx[2]->nTimeReceived = (unsigned int)1333333329;
diff --git a/src/test/base58_tests.cpp b/src/test/base58_tests.cpp
index b81a19cfd8..0ac3e9a363 100644
--- a/src/test/base58_tests.cpp
+++ b/src/test/base58_tests.cpp
@@ -142,9 +142,9 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_parse)
bool isPrivkey = find_value(metadata, "isPrivkey").get_bool();
bool isTestnet = find_value(metadata, "isTestnet").get_bool();
if (isTestnet)
- SelectParams(CChainParams::TESTNET);
+ SelectParams(CBaseChainParams::TESTNET);
else
- SelectParams(CChainParams::MAIN);
+ SelectParams(CBaseChainParams::MAIN);
if(isPrivkey)
{
bool isCompressed = find_value(metadata, "isCompressed").get_bool();
@@ -175,7 +175,7 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_parse)
BOOST_CHECK_MESSAGE(!secret.IsValid(), "IsValid pubkey as privkey:" + strTest);
}
}
- SelectParams(CChainParams::MAIN);
+ SelectParams(CBaseChainParams::MAIN);
}
// Goal: check that generated keys match test vectors
@@ -198,9 +198,9 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_gen)
bool isPrivkey = find_value(metadata, "isPrivkey").get_bool();
bool isTestnet = find_value(metadata, "isTestnet").get_bool();
if (isTestnet)
- SelectParams(CChainParams::TESTNET);
+ SelectParams(CBaseChainParams::TESTNET);
else
- SelectParams(CChainParams::MAIN);
+ SelectParams(CBaseChainParams::MAIN);
if(isPrivkey)
{
bool isCompressed = find_value(metadata, "isCompressed").get_bool();
@@ -243,7 +243,7 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_gen)
CTxDestination nodest = CNoDestination();
BOOST_CHECK(!dummyAddr.Set(nodest));
- SelectParams(CChainParams::MAIN);
+ SelectParams(CBaseChainParams::MAIN);
}
// Goal: check that base58 parsing code is robust against a variety of corrupted data
diff --git a/src/test/bloom_tests.cpp b/src/test/bloom_tests.cpp
index abedd3093c..2cdafa4bdd 100644
--- a/src/test/bloom_tests.cpp
+++ b/src/test/bloom_tests.cpp
@@ -45,12 +45,16 @@ BOOST_AUTO_TEST_CASE(bloom_create_insert_serialize)
expected[i] = (char)vch[i];
BOOST_CHECK_EQUAL_COLLECTIONS(stream.begin(), stream.end(), expected.begin(), expected.end());
+
+ BOOST_CHECK_MESSAGE( filter.contains(ParseHex("99108ad8ed9bb6274d3980bab5a85c048f0950c8")), "BloomFilter doesn't contain just-inserted object!");
+ filter.clear();
+ BOOST_CHECK_MESSAGE( !filter.contains(ParseHex("99108ad8ed9bb6274d3980bab5a85c048f0950c8")), "BloomFilter should be empty!");
}
BOOST_AUTO_TEST_CASE(bloom_create_insert_serialize_with_tweak)
{
// Same test as bloom_create_insert_serialize, but we add a nTweak of 100
- CBloomFilter filter(3, 0.01, 2147483649, BLOOM_UPDATE_ALL);
+ CBloomFilter filter(3, 0.01, 2147483649UL, BLOOM_UPDATE_ALL);
filter.insert(ParseHex("99108ad8ed9bb6274d3980bab5a85c048f0950c8"));
BOOST_CHECK_MESSAGE( filter.contains(ParseHex("99108ad8ed9bb6274d3980bab5a85c048f0950c8")), "BloomFilter doesn't contain just-inserted object!");
@@ -118,33 +122,33 @@ BOOST_AUTO_TEST_CASE(bloom_match)
CBloomFilter filter(10, 0.000001, 0, BLOOM_UPDATE_ALL);
filter.insert(uint256("0xb4749f017444b051c44dfd2720e88f314ff94f3dd6d56d40ef65854fcd7fff6b"));
- BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx, tx.GetHash()), "Simple Bloom filter didn't match tx hash");
+ BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx), "Simple Bloom filter didn't match tx hash");
filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL);
// byte-reversed tx hash
filter.insert(ParseHex("6bff7fcd4f8565ef406dd5d63d4ff94f318fe82027fd4dc451b04474019f74b4"));
- BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx, tx.GetHash()), "Simple Bloom filter didn't match manually serialized tx hash");
+ BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx), "Simple Bloom filter didn't match manually serialized tx hash");
filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL);
filter.insert(ParseHex("30450220070aca44506c5cef3a16ed519d7c3c39f8aab192c4e1c90d065f37b8a4af6141022100a8e160b856c2d43d27d8fba71e5aef6405b8643ac4cb7cb3c462aced7f14711a01"));
- BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx, tx.GetHash()), "Simple Bloom filter didn't match input signature");
+ BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx), "Simple Bloom filter didn't match input signature");
filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL);
filter.insert(ParseHex("046d11fee51b0e60666d5049a9101a72741df480b96ee26488a4d3466b95c9a40ac5eeef87e10a5cd336c19a84565f80fa6c547957b7700ff4dfbdefe76036c339"));
- BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx, tx.GetHash()), "Simple Bloom filter didn't match input pub key");
+ BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx), "Simple Bloom filter didn't match input pub key");
filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL);
filter.insert(ParseHex("04943fdd508053c75000106d3bc6e2754dbcff19"));
- BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx, tx.GetHash()), "Simple Bloom filter didn't match output address");
- BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(spendingTx, spendingTx.GetHash()), "Simple Bloom filter didn't add output");
+ BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx), "Simple Bloom filter didn't match output address");
+ BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(spendingTx), "Simple Bloom filter didn't add output");
filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL);
filter.insert(ParseHex("a266436d2965547608b9e15d9032a7b9d64fa431"));
- BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx, tx.GetHash()), "Simple Bloom filter didn't match output address");
+ BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx), "Simple Bloom filter didn't match output address");
filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL);
filter.insert(COutPoint(uint256("0x90c122d70786e899529d71dbeba91ba216982fb6ba58f3bdaab65e73b7e9260b"), 0));
- BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx, tx.GetHash()), "Simple Bloom filter didn't match COutPoint");
+ BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx), "Simple Bloom filter didn't match COutPoint");
filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL);
COutPoint prevOutPoint(uint256("0x90c122d70786e899529d71dbeba91ba216982fb6ba58f3bdaab65e73b7e9260b"), 0);
@@ -154,23 +158,23 @@ BOOST_AUTO_TEST_CASE(bloom_match)
memcpy(&data[32], &prevOutPoint.n, sizeof(unsigned int));
filter.insert(data);
}
- BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx, tx.GetHash()), "Simple Bloom filter didn't match manually serialized COutPoint");
+ BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx), "Simple Bloom filter didn't match manually serialized COutPoint");
filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL);
filter.insert(uint256("00000009e784f32f62ef849763d4f45b98e07ba658647343b915ff832b110436"));
- BOOST_CHECK_MESSAGE(!filter.IsRelevantAndUpdate(tx, tx.GetHash()), "Simple Bloom filter matched random tx hash");
+ BOOST_CHECK_MESSAGE(!filter.IsRelevantAndUpdate(tx), "Simple Bloom filter matched random tx hash");
filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL);
filter.insert(ParseHex("0000006d2965547608b9e15d9032a7b9d64fa431"));
- BOOST_CHECK_MESSAGE(!filter.IsRelevantAndUpdate(tx, tx.GetHash()), "Simple Bloom filter matched random address");
+ BOOST_CHECK_MESSAGE(!filter.IsRelevantAndUpdate(tx), "Simple Bloom filter matched random address");
filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL);
filter.insert(COutPoint(uint256("0x90c122d70786e899529d71dbeba91ba216982fb6ba58f3bdaab65e73b7e9260b"), 1));
- BOOST_CHECK_MESSAGE(!filter.IsRelevantAndUpdate(tx, tx.GetHash()), "Simple Bloom filter matched COutPoint for an output we didn't care about");
+ BOOST_CHECK_MESSAGE(!filter.IsRelevantAndUpdate(tx), "Simple Bloom filter matched COutPoint for an output we didn't care about");
filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL);
filter.insert(COutPoint(uint256("0x000000d70786e899529d71dbeba91ba216982fb6ba58f3bdaab65e73b7e9260b"), 0));
- BOOST_CHECK_MESSAGE(!filter.IsRelevantAndUpdate(tx, tx.GetHash()), "Simple Bloom filter matched COutPoint for an output we didn't care about");
+ BOOST_CHECK_MESSAGE(!filter.IsRelevantAndUpdate(tx), "Simple Bloom filter matched COutPoint for an output we didn't care about");
}
BOOST_AUTO_TEST_CASE(merkle_block_1)
diff --git a/src/test/crypto_tests.cpp b/src/test/crypto_tests.cpp
new file mode 100644
index 0000000000..7bd98fa381
--- /dev/null
+++ b/src/test/crypto_tests.cpp
@@ -0,0 +1,203 @@
+// Copyright (c) 2014 The Bitcoin Core developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include "crypto/ripemd160.h"
+#include "crypto/sha1.h"
+#include "crypto/sha2.h"
+#include "util.h"
+
+#include <vector>
+
+#include <boost/test/unit_test.hpp>
+
+BOOST_AUTO_TEST_SUITE(crypto_tests)
+
+template<typename Hasher, typename In, typename Out>
+void TestVector(const Hasher &h, const In &in, const Out &out) {
+ Out hash;
+ BOOST_CHECK(out.size() == h.OUTPUT_SIZE);
+ hash.resize(out.size());
+ {
+ // Test that writing the whole input string at once works.
+ Hasher(h).Write((unsigned char*)&in[0], in.size()).Finalize(&hash[0]);
+ BOOST_CHECK(hash == out);
+ }
+ for (int i=0; i<32; i++) {
+ // Test that writing the string broken up in random pieces works.
+ Hasher hasher(h);
+ size_t pos = 0;
+ while (pos < in.size()) {
+ size_t len = insecure_rand() % ((in.size() - pos + 1) / 2 + 1);
+ hasher.Write((unsigned char*)&in[pos], len);
+ pos += len;
+ if (pos > 0 && pos + 2 * out.size() > in.size()) {
+ // Test that writing the rest at once to a copy of a hasher works.
+ Hasher(hasher).Write((unsigned char*)&in[pos], in.size() - pos).Finalize(&hash[0]);
+ BOOST_CHECK(hash == out);
+ }
+ }
+ hasher.Finalize(&hash[0]);
+ BOOST_CHECK(hash == out);
+ }
+}
+
+void TestSHA1(const std::string &in, const std::string &hexout) { TestVector(CSHA1(), in, ParseHex(hexout));}
+void TestSHA256(const std::string &in, const std::string &hexout) { TestVector(CSHA256(), in, ParseHex(hexout));}
+void TestSHA512(const std::string &in, const std::string &hexout) { TestVector(CSHA512(), in, ParseHex(hexout));}
+void TestRIPEMD160(const std::string &in, const std::string &hexout) { TestVector(CRIPEMD160(), in, ParseHex(hexout));}
+
+void TestHMACSHA512(const std::string &hexkey, const std::string &hexin, const std::string &hexout) {
+ std::vector<unsigned char> key = ParseHex(hexkey);
+ TestVector(CHMAC_SHA512(&key[0], key.size()), ParseHex(hexin), ParseHex(hexout));
+}
+
+std::string LongTestString(void) {
+ std::string ret;
+ for (int i=0; i<200000; i++) {
+ ret += (unsigned char)(i);
+ ret += (unsigned char)(i >> 4);
+ ret += (unsigned char)(i >> 8);
+ ret += (unsigned char)(i >> 12);
+ ret += (unsigned char)(i >> 16);
+ }
+ return ret;
+}
+
+const std::string test1 = LongTestString();
+
+BOOST_AUTO_TEST_CASE(ripemd160_testvectors) {
+ TestRIPEMD160("", "9c1185a5c5e9fc54612808977ee8f548b2258d31");
+ TestRIPEMD160("abc", "8eb208f7e05d987a9b044a8e98c6b087f15a0bfc");
+ TestRIPEMD160("message digest", "5d0689ef49d2fae572b881b123a85ffa21595f36");
+ TestRIPEMD160("secure hash algorithm", "20397528223b6a5f4cbc2808aba0464e645544f9");
+ TestRIPEMD160("RIPEMD160 is considered to be safe", "a7d78608c7af8a8e728778e81576870734122b66");
+ TestRIPEMD160("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
+ "12a053384a9c0c88e405a06c27dcf49ada62eb2b");
+ TestRIPEMD160("For this sample, this 63-byte string will be used as input data",
+ "de90dbfee14b63fb5abf27c2ad4a82aaa5f27a11");
+ TestRIPEMD160("This is exactly 64 bytes long, not counting the terminating byte",
+ "eda31d51d3a623b81e19eb02e24ff65d27d67b37");
+ TestRIPEMD160(std::string(1000000, 'a'), "52783243c1697bdbe16d37f97f68f08325dc1528");
+ TestRIPEMD160(test1, "464243587bd146ea835cdf57bdae582f25ec45f1");
+}
+
+BOOST_AUTO_TEST_CASE(sha1_testvectors) {
+ TestSHA1("", "da39a3ee5e6b4b0d3255bfef95601890afd80709");
+ TestSHA1("abc", "a9993e364706816aba3e25717850c26c9cd0d89d");
+ TestSHA1("message digest", "c12252ceda8be8994d5fa0290a47231c1d16aae3");
+ TestSHA1("secure hash algorithm", "d4d6d2f0ebe317513bbd8d967d89bac5819c2f60");
+ TestSHA1("SHA1 is considered to be safe", "f2b6650569ad3a8720348dd6ea6c497dee3a842a");
+ TestSHA1("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
+ "84983e441c3bd26ebaae4aa1f95129e5e54670f1");
+ TestSHA1("For this sample, this 63-byte string will be used as input data",
+ "4f0ea5cd0585a23d028abdc1a6684e5a8094dc49");
+ TestSHA1("This is exactly 64 bytes long, not counting the terminating byte",
+ "fb679f23e7d1ce053313e66e127ab1b444397057");
+ TestSHA1(std::string(1000000, 'a'), "34aa973cd4c4daa4f61eeb2bdbad27316534016f");
+ TestSHA1(test1, "b7755760681cbfd971451668f32af5774f4656b5");
+}
+
+BOOST_AUTO_TEST_CASE(sha256_testvectors) {
+ TestSHA256("", "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855");
+ TestSHA256("abc", "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad");
+ TestSHA256("message digest",
+ "f7846f55cf23e14eebeab5b4e1550cad5b509e3348fbc4efa3a1413d393cb650");
+ TestSHA256("secure hash algorithm",
+ "f30ceb2bb2829e79e4ca9753d35a8ecc00262d164cc077080295381cbd643f0d");
+ TestSHA256("SHA256 is considered to be safe",
+ "6819d915c73f4d1e77e4e1b52d1fa0f9cf9beaead3939f15874bd988e2a23630");
+ TestSHA256("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
+ "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1");
+ TestSHA256("For this sample, this 63-byte string will be used as input data",
+ "f08a78cbbaee082b052ae0708f32fa1e50c5c421aa772ba5dbb406a2ea6be342");
+ TestSHA256("This is exactly 64 bytes long, not counting the terminating byte",
+ "ab64eff7e88e2e46165e29f2bce41826bd4c7b3552f6b382a9e7d3af47c245f8");
+ TestSHA256("As Bitcoin relies on 80 byte header hashes, we want to have an example for that.",
+ "7406e8de7d6e4fffc573daef05aefb8806e7790f55eab5576f31349743cca743");
+ TestSHA256(std::string(1000000, 'a'),
+ "cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0");
+ TestSHA256(test1, "a316d55510b49662420f49d145d42fb83f31ef8dc016aa4e32df049991a91e26");
+}
+
+BOOST_AUTO_TEST_CASE(sha512_testvectors) {
+ TestSHA512("",
+ "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce"
+ "47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e");
+ TestSHA512("abc",
+ "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a"
+ "2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f");
+ TestSHA512("message digest",
+ "107dbf389d9e9f71a3a95f6c055b9251bc5268c2be16d6c13492ea45b0199f33"
+ "09e16455ab1e96118e8a905d5597b72038ddb372a89826046de66687bb420e7c");
+ TestSHA512("secure hash algorithm",
+ "7746d91f3de30c68cec0dd693120a7e8b04d8073cb699bdce1a3f64127bca7a3"
+ "d5db502e814bb63c063a7a5043b2df87c61133395f4ad1edca7fcf4b30c3236e");
+ TestSHA512("SHA512 is considered to be safe",
+ "099e6468d889e1c79092a89ae925a9499b5408e01b66cb5b0a3bd0dfa51a9964"
+ "6b4a3901caab1318189f74cd8cf2e941829012f2449df52067d3dd5b978456c2");
+ TestSHA512("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
+ "204a8fc6dda82f0a0ced7beb8e08a41657c16ef468b228a8279be331a703c335"
+ "96fd15c13b1b07f9aa1d3bea57789ca031ad85c7a71dd70354ec631238ca3445");
+ TestSHA512("For this sample, this 63-byte string will be used as input data",
+ "b3de4afbc516d2478fe9b518d063bda6c8dd65fc38402dd81d1eb7364e72fb6e"
+ "6663cf6d2771c8f5a6da09601712fb3d2a36c6ffea3e28b0818b05b0a8660766");
+ TestSHA512("This is exactly 64 bytes long, not counting the terminating byte",
+ "70aefeaa0e7ac4f8fe17532d7185a289bee3b428d950c14fa8b713ca09814a38"
+ "7d245870e007a80ad97c369d193e41701aa07f3221d15f0e65a1ff970cedf030");
+ TestSHA512("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmno"
+ "ijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu",
+ "8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018"
+ "501d289e4900f7e4331b99dec4b5433ac7d329eeb6dd26545e96e55b874be909");
+ TestSHA512(std::string(1000000, 'a'),
+ "e718483d0ce769644e2e42c7bc15b4638e1f98b13b2044285632a803afa973eb"
+ "de0ff244877ea60a4cb0432ce577c31beb009c5c2c49aa2e4eadb217ad8cc09b");
+ TestSHA512(test1,
+ "40cac46c147e6131c5193dd5f34e9d8bb4951395f27b08c558c65ff4ba2de594"
+ "37de8c3ef5459d76a52cedc02dc499a3c9ed9dedbfb3281afd9653b8a112fafc");
+}
+
+BOOST_AUTO_TEST_CASE(hmac_sha512_testvectors) {
+ // test cases 1, 2, 3, 4, 6 and 7 of RFC 4231
+ TestHMACSHA512("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b",
+ "4869205468657265",
+ "87aa7cdea5ef619d4ff0b4241a1d6cb02379f4e2ce4ec2787ad0b30545e17cde"
+ "daa833b7d6b8a702038b274eaea3f4e4be9d914eeb61f1702e696c203a126854");
+ TestHMACSHA512("4a656665",
+ "7768617420646f2079612077616e7420666f72206e6f7468696e673f",
+ "164b7a7bfcf819e2e395fbe73b56e0a387bd64222e831fd610270cd7ea250554"
+ "9758bf75c05a994a6d034f65f8f0e6fdcaeab1a34d4a6b4b636e070a38bce737");
+ TestHMACSHA512("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"
+ "dddddddddddddddddddddddddddddddddddd",
+ "fa73b0089d56a284efb0f0756c890be9b1b5dbdd8ee81a3655f83e33b2279d39"
+ "bf3e848279a722c806b485a47e67c807b946a337bee8942674278859e13292fb");
+ TestHMACSHA512("0102030405060708090a0b0c0d0e0f10111213141516171819",
+ "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"
+ "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd",
+ "b0ba465637458c6990e5a8c5f61d4af7e576d97ff94b872de76f8050361ee3db"
+ "a91ca5c11aa25eb4d679275cc5788063a5f19741120c4f2de2adebeb10a298dd");
+ TestHMACSHA512("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaa",
+ "54657374205573696e67204c6172676572205468616e20426c6f636b2d53697a"
+ "65204b6579202d2048617368204b6579204669727374",
+ "80b24263c7c1a3ebb71493c1dd7be8b49b46d1f41b4aeec1121b013783f8f352"
+ "6b56d037e05f2598bd0fd2215d6a1e5295e64f73f63f0aec8b915a985d786598");
+ TestHMACSHA512("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaa",
+ "5468697320697320612074657374207573696e672061206c6172676572207468"
+ "616e20626c6f636b2d73697a65206b657920616e642061206c61726765722074"
+ "68616e20626c6f636b2d73697a6520646174612e20546865206b6579206e6565"
+ "647320746f20626520686173686564206265666f7265206265696e6720757365"
+ "642062792074686520484d414320616c676f726974686d2e",
+ "e37b6a775dc87dbaa4dfa9f96e5e3ffddebd71f8867289865df5a32d20cdc944"
+ "b6022cac3c4982b10d5eeb55c3e4de15134676fb6de0446065c97440fa8c6a58");
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/data/tx_valid.json b/src/test/data/tx_valid.json
index 1f51d3ce55..aa8e5ca6c3 100644
--- a/src/test/data/tx_valid.json
+++ b/src/test/data/tx_valid.json
@@ -16,7 +16,7 @@
["It is an OP_CHECKMULTISIG with an arbitrary extra byte stuffed into the signature at pos length - 2"],
["The dummy byte is fine however, so the NULLDUMMY flag should be happy"],
[[["60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1", 0, "1 0x41 0x04cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4 0x41 0x0461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af 2 OP_CHECKMULTISIG"]],
-"0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba260000000004A0048304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2bab01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000", "P2SH,NULLDUMMY"],
+"0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba260000000004a0048304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2bab01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000", "P2SH,NULLDUMMY"],
["The following is a tweaked form of 23b397edccd3740a74adb603c9756370fafcde9bcc4483eb271ecad09a94dd63"],
["It is an OP_CHECKMULTISIG with the dummy value set to something other than an empty string"],
@@ -132,5 +132,51 @@
[[["ba4cd7ae2ad4d4d13ebfc8ab1d93a63e4a6563f25089a18bf0fc68f282aa88c1", 0, "2 0x21 0x037c615d761e71d38903609bf4f46847266edc2fb37532047d747ba47eaae5ffe1 0x21 0x02edc823cd634f2c4033d94f5755207cb6b60c4b1f1f056ad7471c47de5f2e4d50 2 CHECKMULTISIG NOT"]],
"0100000001c188aa82f268fcf08ba18950f263654a3ea6931dabc8bf3ed1d4d42aaed74cba000000004b0000483045022100940378576e069aca261a6b26fb38344e4497ca6751bb10905c76bb689f4222b002204833806b014c26fd801727b792b1260003c55710f87c5adbd7a9cb57446dbc9801ffffffff0101000000000000002321037c615d761e71d38903609bf4f46847266edc2fb37532047d747ba47eaae5ffe1ac00000000", "P2SH"],
+
+["OP_CODESEPARATOR tests"],
+
+["Test that SignatureHash() removes OP_CODESEPARATOR with FindAndDelete()"],
+[[["bc7fd132fcf817918334822ee6d9bd95c889099c96e07ca2c1eb2cc70db63224", 0, "CODESEPARATOR 0x21 0x038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041 CHECKSIG"]],
+"01000000012432b60dc72cebc1a27ce0969c0989c895bdd9e62e8234839117f8fc32d17fbc000000004a493046022100a576b52051962c25e642c0fd3d77ee6c92487048e5d90818bcf5b51abaccd7900221008204f8fb121be4ec3b24483b1f92d89b1b0548513a134e345c5442e86e8617a501ffffffff010000000000000000016a00000000", "P2SH"],
+[[["83e194f90b6ef21fa2e3a365b63794fb5daa844bdc9b25de30899fcfe7b01047", 0, "CODESEPARATOR CODESEPARATOR 0x21 0x038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041 CHECKSIG"]],
+"01000000014710b0e7cf9f8930de259bdc4b84aa5dfb9437b665a3e3a21ff26e0bf994e183000000004a493046022100a166121a61b4eeb19d8f922b978ff6ab58ead8a5a5552bf9be73dc9c156873ea02210092ad9bc43ee647da4f6652c320800debcf08ec20a094a0aaf085f63ecb37a17201ffffffff010000000000000000016a00000000", "P2SH"],
+
+["Hashed data starts at the CODESEPARATOR"],
+[[["326882a7f22b5191f1a0cc9962ca4b878cd969cf3b3a70887aece4d801a0ba5e", 0, "0x21 0x038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041 CODESEPARATOR CHECKSIG"]],
+"01000000015ebaa001d8e4ec7a88703a3bcf69d98c874bca6299cca0f191512bf2a7826832000000004948304502203bf754d1c6732fbf87c5dcd81258aefd30f2060d7bd8ac4a5696f7927091dad1022100f5bcb726c4cf5ed0ed34cc13dadeedf628ae1045b7cb34421bc60b89f4cecae701ffffffff010000000000000000016a00000000", "P2SH"],
+
+["But only if execution has reached it"],
+[[["a955032f4d6b0c9bfe8cad8f00a8933790b9c1dc28c82e0f48e75b35da0e4944", 0, "0x21 0x038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041 CHECKSIGVERIFY CODESEPARATOR 0x21 0x038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041 CHECKSIGVERIFY CODESEPARATOR 1"]],
+"010000000144490eda355be7480f2ec828dcc1b9903793a8008fad8cfe9b0c6b4d2f0355a900000000924830450221009c0a27f886a1d8cb87f6f595fbc3163d28f7a81ec3c4b252ee7f3ac77fd13ffa02203caa8dfa09713c8c4d7ef575c75ed97812072405d932bd11e6a1593a98b679370148304502201e3861ef39a526406bad1e20ecad06be7375ad40ddb582c9be42d26c3a0d7b240221009d0a3985e96522e59635d19cc4448547477396ce0ef17a58e7d74c3ef464292301ffffffff010000000000000000016a00000000", "P2SH"],
+
+["CHECKSIG is legal in scriptSigs"],
+[[["ccf7f4053a02e653c36ac75c891b7496d0dc5ce5214f6c913d9cf8f1329ebee0", 0, "DUP HASH160 0x14 0xee5a6aa40facefb2655ac23c0c28c57c65c41f9b EQUALVERIFY CHECKSIG"]],
+"0100000001e0be9e32f1f89c3d916c4f21e55cdcd096741b895cc76ac353e6023a05f4f7cc00000000d86149304602210086e5f736a2c3622ebb62bd9d93d8e5d76508b98be922b97160edc3dcca6d8c47022100b23c312ac232a4473f19d2aeb95ab7bdf2b65518911a0d72d50e38b5dd31dc820121038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ac4730440220508fa761865c8abd81244a168392876ee1d94e8ed83897066b5e2df2400dad24022043f5ee7538e87e9c6aef7ef55133d3e51da7cc522830a9c4d736977a76ef755c0121038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ffffffff010000000000000000016a00000000", "P2SH"],
+
+["Same semantics for OP_CODESEPARATOR"],
+[[["10c9f0effe83e97f80f067de2b11c6a00c3088a4bce42c5ae761519af9306f3c", 1, "DUP HASH160 0x14 0xee5a6aa40facefb2655ac23c0c28c57c65c41f9b EQUALVERIFY CHECKSIG"]],
+"01000000013c6f30f99a5161e75a2ce4bca488300ca0c6112bde67f0807fe983feeff0c91001000000e608646561646265656675ab61493046022100ce18d384221a731c993939015e3d1bcebafb16e8c0b5b5d14097ec8177ae6f28022100bcab227af90bab33c3fe0a9abfee03ba976ee25dc6ce542526e9b2e56e14b7f10121038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ac493046022100c3b93edcc0fd6250eb32f2dd8a0bba1754b0f6c3be8ed4100ed582f3db73eba2022100bf75b5bd2eff4d6bf2bda2e34a40fcc07d4aa3cf862ceaa77b47b81eff829f9a01ab21038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ffffffff010000000000000000016a00000000", "P2SH"],
+
+["Signatures are removed from the script they are in by FindAndDelete() in the CHECKSIG code; even multiple instances of one signature can be removed."],
+[[["6056ebd549003b10cbbd915cea0d82209fe40b8617104be917a26fa92cbe3d6f", 0, "DUP HASH160 0x14 0xee5a6aa40facefb2655ac23c0c28c57c65c41f9b EQUALVERIFY CHECKSIG"]],
+"01000000016f3dbe2ca96fa217e94b1017860be49f20820dea5c91bdcb103b0049d5eb566000000000fd1d0147304402203989ac8f9ad36b5d0919d97fa0a7f70c5272abee3b14477dc646288a8b976df5022027d19da84a066af9053ad3d1d7459d171b7e3a80bc6c4ef7a330677a6be548140147304402203989ac8f9ad36b5d0919d97fa0a7f70c5272abee3b14477dc646288a8b976df5022027d19da84a066af9053ad3d1d7459d171b7e3a80bc6c4ef7a330677a6be548140121038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ac47304402203757e937ba807e4a5da8534c17f9d121176056406a6465054bdd260457515c1a02200f02eccf1bec0f3a0d65df37889143c2e88ab7acec61a7b6f5aa264139141a2b0121038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ffffffff010000000000000000016a00000000", "P2SH"],
+
+["That also includes ahead of the opcode being executed."],
+[[["5a6b0021a6042a686b6b94abc36b387bef9109847774e8b1e51eb8cc55c53921", 1, "DUP HASH160 0x14 0xee5a6aa40facefb2655ac23c0c28c57c65c41f9b EQUALVERIFY CHECKSIG"]],
+"01000000012139c555ccb81ee5b1e87477840991ef7b386bc3ab946b6b682a04a621006b5a01000000fdb40148304502201723e692e5f409a7151db386291b63524c5eb2030df652b1f53022fd8207349f022100b90d9bbf2f3366ce176e5e780a00433da67d9e5c79312c6388312a296a5800390148304502201723e692e5f409a7151db386291b63524c5eb2030df652b1f53022fd8207349f022100b90d9bbf2f3366ce176e5e780a00433da67d9e5c79312c6388312a296a5800390121038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f2204148304502201723e692e5f409a7151db386291b63524c5eb2030df652b1f53022fd8207349f022100b90d9bbf2f3366ce176e5e780a00433da67d9e5c79312c6388312a296a5800390175ac4830450220646b72c35beeec51f4d5bc1cbae01863825750d7f490864af354e6ea4f625e9c022100f04b98432df3a9641719dbced53393022e7249fb59db993af1118539830aab870148304502201723e692e5f409a7151db386291b63524c5eb2030df652b1f53022fd8207349f022100b90d9bbf2f3366ce176e5e780a00433da67d9e5c79312c6388312a296a580039017521038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ffffffff010000000000000000016a00000000", "P2SH"],
+
+["Finally CHECKMULTISIG removes all signatures prior to hashing the script containing those signatures. In conjunction with the SIGHASH_SINGLE bug this lets us test whether or not FindAndDelete() is actually present in scriptPubKey/redeemScript evaluation by including a signature of the digest 0x01 We can compute in advance for our pubkey, embed it it in the scriptPubKey, and then also using a normal SIGHASH_ALL signature. If FindAndDelete() wasn't run, the 'bugged' signature would still be in the hashed script, and the normal signature would fail."],
+
+["Here's an example on mainnet within a P2SH redeemScript. Remarkably it's a standard transaction in <0.9"],
+[[["b5b598de91787439afd5938116654e0b16b7a0d0f82742ba37564219c5afcbf9", 0, "DUP HASH160 0x14 0xf6f365c40f0739b61de827a44751e5e99032ed8f EQUALVERIFY CHECKSIG"],
+ ["ab9805c6d57d7070d9a42c5176e47bb705023e6b67249fb6760880548298e742", 0, "HASH160 0x14 0xd8dacdadb7462ae15cd906f1878706d0da8660e6 EQUAL"]],
+"0100000002f9cbafc519425637ba4227f8d0a0b7160b4e65168193d5af39747891de98b5b5000000006b4830450221008dd619c563e527c47d9bd53534a770b102e40faa87f61433580e04e271ef2f960220029886434e18122b53d5decd25f1f4acb2480659fea20aabd856987ba3c3907e0121022b78b756e2258af13779c1a1f37ea6800259716ca4b7f0b87610e0bf3ab52a01ffffffff42e7988254800876b69f24676b3e0205b77be476512ca4d970707dd5c60598ab00000000fd260100483045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a53034930460221008431bdfa72bc67f9d41fe72e94c88fb8f359ffa30b33c72c121c5a877d922e1002210089ef5fc22dd8bfc6bf9ffdb01a9862d27687d424d1fefbab9e9c7176844a187a014c9052483045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a5303210378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71210378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c7153aeffffffff01a08601000000000017a914d8dacdadb7462ae15cd906f1878706d0da8660e68700000000", "P2SH"],
+
+["Same idea, but with bare CHECKMULTISIG"],
+[[["ceafe58e0f6e7d67c0409fbbf673c84c166e3c5d3c24af58f7175b18df3bb3db", 0, "DUP HASH160 0x14 0xf6f365c40f0739b61de827a44751e5e99032ed8f EQUALVERIFY CHECKSIG"],
+ ["ceafe58e0f6e7d67c0409fbbf673c84c166e3c5d3c24af58f7175b18df3bb3db", 1, "2 0x48 0x3045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a5303 0x21 0x0378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71 0x21 0x0378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71 3 CHECKMULTISIG"]],
+"0100000002dbb33bdf185b17f758af243c5d3c6e164cc873f6bb9f40c0677d6e0f8ee5afce000000006b4830450221009627444320dc5ef8d7f68f35010b4c050a6ed0d96b67a84db99fda9c9de58b1e02203e4b4aaa019e012e65d69b487fdf8719df72f488fa91506a80c49a33929f1fd50121022b78b756e2258af13779c1a1f37ea6800259716ca4b7f0b87610e0bf3ab52a01ffffffffdbb33bdf185b17f758af243c5d3c6e164cc873f6bb9f40c0677d6e0f8ee5afce010000009300483045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a5303483045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a5303ffffffff01a0860100000000001976a9149bc0bbdd3024da4d0c38ed1aecf5c68dd1d3fa1288ac00000000", "P2SH"],
+
+
["Make diffs cleaner by leaving a comment here without comma at the end"]
]
diff --git a/src/test/hmac_tests.cpp b/src/test/hmac_tests.cpp
deleted file mode 100644
index 780ce480ce..0000000000
--- a/src/test/hmac_tests.cpp
+++ /dev/null
@@ -1,129 +0,0 @@
-// Copyright (c) 2013 The Bitcoin Core developers
-// Distributed under the MIT/X11 software license, see the accompanying
-// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-#include "hash.h"
-#include "util.h"
-
-#include <boost/test/unit_test.hpp>
-
-using namespace std;
-
-BOOST_AUTO_TEST_SUITE(hmac_tests)
-
-typedef struct {
- const char *pszKey;
- const char *pszData;
- const char *pszMAC;
-} testvec_t;
-
-// test cases 1, 2, 3, 4, 6 and 7 of RFC 4231
-static const testvec_t vtest[] = {
- {
- "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"
- "0b0b0b0b",
- "4869205468657265",
- "87aa7cdea5ef619d4ff0b4241a1d6cb0"
- "2379f4e2ce4ec2787ad0b30545e17cde"
- "daa833b7d6b8a702038b274eaea3f4e4"
- "be9d914eeb61f1702e696c203a126854"
- },
- {
- "4a656665",
- "7768617420646f2079612077616e7420"
- "666f72206e6f7468696e673f",
- "164b7a7bfcf819e2e395fbe73b56e0a3"
- "87bd64222e831fd610270cd7ea250554"
- "9758bf75c05a994a6d034f65f8f0e6fd"
- "caeab1a34d4a6b4b636e070a38bce737"
- },
- {
- "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
- "aaaaaaaa",
- "dddddddddddddddddddddddddddddddd"
- "dddddddddddddddddddddddddddddddd"
- "dddddddddddddddddddddddddddddddd"
- "dddd",
- "fa73b0089d56a284efb0f0756c890be9"
- "b1b5dbdd8ee81a3655f83e33b2279d39"
- "bf3e848279a722c806b485a47e67c807"
- "b946a337bee8942674278859e13292fb"
- },
- {
- "0102030405060708090a0b0c0d0e0f10"
- "111213141516171819",
- "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"
- "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"
- "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"
- "cdcd",
- "b0ba465637458c6990e5a8c5f61d4af7"
- "e576d97ff94b872de76f8050361ee3db"
- "a91ca5c11aa25eb4d679275cc5788063"
- "a5f19741120c4f2de2adebeb10a298dd"
- },
- {
- "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
- "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
- "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
- "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
- "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
- "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
- "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
- "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
- "aaaaaa",
- "54657374205573696e67204c61726765"
- "72205468616e20426c6f636b2d53697a"
- "65204b6579202d2048617368204b6579"
- "204669727374",
- "80b24263c7c1a3ebb71493c1dd7be8b4"
- "9b46d1f41b4aeec1121b013783f8f352"
- "6b56d037e05f2598bd0fd2215d6a1e52"
- "95e64f73f63f0aec8b915a985d786598"
- },
- {
- "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
- "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
- "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
- "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
- "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
- "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
- "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
- "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
- "aaaaaa",
- "54686973206973206120746573742075"
- "73696e672061206c6172676572207468"
- "616e20626c6f636b2d73697a65206b65"
- "7920616e642061206c61726765722074"
- "68616e20626c6f636b2d73697a652064"
- "6174612e20546865206b6579206e6565"
- "647320746f2062652068617368656420"
- "6265666f7265206265696e6720757365"
- "642062792074686520484d414320616c"
- "676f726974686d2e",
- "e37b6a775dc87dbaa4dfa9f96e5e3ffd"
- "debd71f8867289865df5a32d20cdc944"
- "b6022cac3c4982b10d5eeb55c3e4de15"
- "134676fb6de0446065c97440fa8c6a58"
- }
-};
-
-BOOST_AUTO_TEST_CASE(hmacsha512_testvectors)
-{
- for (unsigned int n=0; n<sizeof(vtest)/sizeof(vtest[0]); n++)
- {
- vector<unsigned char> vchKey = ParseHex(vtest[n].pszKey);
- vector<unsigned char> vchData = ParseHex(vtest[n].pszData);
- vector<unsigned char> vchMAC = ParseHex(vtest[n].pszMAC);
- unsigned char vchTemp[64];
-
- HMAC_SHA512_CTX ctx;
- HMAC_SHA512_Init(&ctx, &vchKey[0], vchKey.size());
- HMAC_SHA512_Update(&ctx, &vchData[0], vchData.size());
- HMAC_SHA512_Final(&vchTemp[0], &ctx);
-
- BOOST_CHECK(memcmp(&vchTemp[0], &vchMAC[0], 64) == 0);
-
- }
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp
index b72ba0293f..47977cf295 100644
--- a/src/test/miner_tests.cpp
+++ b/src/test/miner_tests.cpp
@@ -9,8 +9,6 @@
#include <boost/test/unit_test.hpp>
-extern void SHA256Transform(void* pstate, void* pinput, const void* pinit);
-
BOOST_AUTO_TEST_SUITE(miner_tests)
static
@@ -53,7 +51,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
{
CScript scriptPubKey = CScript() << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f") << OP_CHECKSIG;
CBlockTemplate *pblocktemplate;
- CTransaction tx,tx2;
+ CMutableTransaction tx,tx2;
CScript script;
uint256 hash;
@@ -70,10 +68,12 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
CBlock *pblock = &pblocktemplate->block; // pointer for convenience
pblock->nVersion = 1;
pblock->nTime = chainActive.Tip()->GetMedianTimePast()+1;
- pblock->vtx[0].vin[0].scriptSig = CScript();
- pblock->vtx[0].vin[0].scriptSig.push_back(blockinfo[i].extranonce);
- pblock->vtx[0].vin[0].scriptSig.push_back(chainActive.Height());
- pblock->vtx[0].vout[0].scriptPubKey = CScript();
+ CMutableTransaction txCoinbase(pblock->vtx[0]);
+ txCoinbase.vin[0].scriptSig = CScript();
+ txCoinbase.vin[0].scriptSig.push_back(blockinfo[i].extranonce);
+ txCoinbase.vin[0].scriptSig.push_back(chainActive.Height());
+ txCoinbase.vout[0].scriptPubKey = CScript();
+ pblock->vtx[0] = CTransaction(txCoinbase);
if (txFirst.size() < 2)
txFirst.push_back(new CTransaction(pblock->vtx[0]));
pblock->hashMerkleRoot = pblock->BuildMerkleTree();
@@ -259,30 +259,4 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
}
-BOOST_AUTO_TEST_CASE(sha256transform_equality)
-{
- unsigned int pSHA256InitState[8] = {0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19};
-
-
- // unsigned char pstate[32];
- unsigned char pinput[64];
-
- int i;
-
- for (i = 0; i < 32; i++) {
- pinput[i] = i;
- pinput[i+32] = 0;
- }
-
- uint256 hash;
-
- SHA256Transform(&hash, pinput, pSHA256InitState);
-
- BOOST_TEST_MESSAGE(hash.GetHex());
-
- uint256 hash_reference("0x2df5e1c65ef9f8cde240d23cae2ec036d31a15ec64bc68f64be242b1da6631f3");
-
- BOOST_CHECK(hash == hash_reference);
-}
-
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/multisig_tests.cpp b/src/test/multisig_tests.cpp
index 3775abd633..452cf084a7 100644
--- a/src/test/multisig_tests.cpp
+++ b/src/test/multisig_tests.cpp
@@ -55,13 +55,13 @@ BOOST_AUTO_TEST_CASE(multisig_verify)
CScript escrow;
escrow << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << key[2].GetPubKey() << OP_3 << OP_CHECKMULTISIG;
- CTransaction txFrom; // Funding transaction
+ CMutableTransaction txFrom; // Funding transaction
txFrom.vout.resize(3);
txFrom.vout[0].scriptPubKey = a_and_b;
txFrom.vout[1].scriptPubKey = a_or_b;
txFrom.vout[2].scriptPubKey = escrow;
- CTransaction txTo[3]; // Spending transaction
+ CMutableTransaction txTo[3]; // Spending transaction
for (int i = 0; i < 3; i++)
{
txTo[i].vin.resize(1);
@@ -270,13 +270,13 @@ BOOST_AUTO_TEST_CASE(multisig_Sign)
CScript escrow;
escrow << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << key[2].GetPubKey() << OP_3 << OP_CHECKMULTISIG;
- CTransaction txFrom; // Funding transaction
+ CMutableTransaction txFrom; // Funding transaction
txFrom.vout.resize(3);
txFrom.vout[0].scriptPubKey = a_and_b;
txFrom.vout[1].scriptPubKey = a_or_b;
txFrom.vout[2].scriptPubKey = escrow;
- CTransaction txTo[3]; // Spending transaction
+ CMutableTransaction txTo[3]; // Spending transaction
for (int i = 0; i < 3; i++)
{
txTo[i].vin.resize(1);
diff --git a/src/test/pmt_tests.cpp b/src/test/pmt_tests.cpp
index 7d7e6681df..9dce4daac6 100644
--- a/src/test/pmt_tests.cpp
+++ b/src/test/pmt_tests.cpp
@@ -36,9 +36,9 @@ BOOST_AUTO_TEST_CASE(pmt_test1)
// build a block with some dummy transactions
CBlock block;
for (unsigned int j=0; j<nTx; j++) {
- CTransaction tx;
+ CMutableTransaction tx;
tx.nLockTime = rand(); // actual transaction data doesn't matter; just make the nLockTime's unique
- block.vtx.push_back(tx);
+ block.vtx.push_back(CTransaction(tx));
}
// calculate actual merkle root and height
diff --git a/src/test/rpc_wallet_tests.cpp b/src/test/rpc_wallet_tests.cpp
index eea249b114..1dc2a3d82f 100644
--- a/src/test/rpc_wallet_tests.cpp
+++ b/src/test/rpc_wallet_tests.cpp
@@ -67,6 +67,31 @@ BOOST_AUTO_TEST_CASE(rpc_wallet)
LOCK2(cs_main, pwalletMain->cs_wallet);
+ CPubKey demoPubkey = pwalletMain->GenerateNewKey();
+ CBitcoinAddress demoAddress = CBitcoinAddress(CTxDestination(demoPubkey.GetID()));
+ Value retValue;
+ string strAccount = "walletDemoAccount";
+ string strPurpose = "receive";
+ BOOST_CHECK_NO_THROW({ /*Initialize Wallet with an account */
+ CWalletDB walletdb(pwalletMain->strWalletFile);
+ CAccount account;
+ account.vchPubKey = demoPubkey;
+ pwalletMain->SetAddressBook(account.vchPubKey.GetID(), strAccount, strPurpose);
+ walletdb.WriteAccount(strAccount, account);
+ });
+
+
+ /*********************************
+ * setaccount
+ *********************************/
+ BOOST_CHECK_NO_THROW(CallRPC("setaccount 1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ nullaccount"));
+ BOOST_CHECK_THROW(CallRPC("setaccount"), runtime_error);
+ /* 1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4X (33 chars) is an illegal address (should be 34 chars) */
+ BOOST_CHECK_THROW(CallRPC("setaccount 1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4X nullaccount"), runtime_error);
+
+ /*********************************
+ * listunspent
+ *********************************/
BOOST_CHECK_NO_THROW(CallRPC("listunspent"));
BOOST_CHECK_THROW(CallRPC("listunspent string"), runtime_error);
BOOST_CHECK_THROW(CallRPC("listunspent 0 string"), runtime_error);
@@ -75,6 +100,9 @@ BOOST_AUTO_TEST_CASE(rpc_wallet)
BOOST_CHECK_NO_THROW(r=CallRPC("listunspent 0 1 []"));
BOOST_CHECK(r.get_array().empty());
+ /*********************************
+ * listreceivedbyaddress
+ *********************************/
BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaddress"));
BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaddress 0"));
BOOST_CHECK_THROW(CallRPC("listreceivedbyaddress not_int"), runtime_error);
@@ -82,12 +110,71 @@ BOOST_AUTO_TEST_CASE(rpc_wallet)
BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaddress 0 true"));
BOOST_CHECK_THROW(CallRPC("listreceivedbyaddress 0 true extra"), runtime_error);
+ /*********************************
+ * listreceivedbyaccount
+ *********************************/
BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaccount"));
BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaccount 0"));
BOOST_CHECK_THROW(CallRPC("listreceivedbyaccount not_int"), runtime_error);
BOOST_CHECK_THROW(CallRPC("listreceivedbyaccount 0 not_bool"), runtime_error);
BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaccount 0 true"));
BOOST_CHECK_THROW(CallRPC("listreceivedbyaccount 0 true extra"), runtime_error);
+
+ /*********************************
+ * getrawchangeaddress
+ *********************************/
+ BOOST_CHECK_NO_THROW(CallRPC("getrawchangeaddress"));
+
+ /*********************************
+ * getnewaddress
+ *********************************/
+ BOOST_CHECK_NO_THROW(CallRPC("getnewaddress"));
+ BOOST_CHECK_NO_THROW(CallRPC("getnewaddress getnewaddress_demoaccount"));
+
+ /*********************************
+ * getaccountaddress
+ *********************************/
+ BOOST_CHECK_NO_THROW(CallRPC("getaccountaddress \"\""));
+ BOOST_CHECK_NO_THROW(CallRPC("getaccountaddress accountThatDoesntExists")); // Should generate a new account
+ BOOST_CHECK_NO_THROW(retValue = CallRPC("getaccountaddress " + strAccount));
+ BOOST_CHECK(CBitcoinAddress(retValue.get_str()).Get() == demoAddress.Get());
+
+ /*********************************
+ * getaccount
+ *********************************/
+ BOOST_CHECK_THROW(CallRPC("getaccount"), runtime_error);
+ BOOST_CHECK_NO_THROW(CallRPC("getaccount " + demoAddress.ToString()));
+
+ /*********************************
+ * signmessage + verifymessage
+ *********************************/
+ BOOST_CHECK_NO_THROW(retValue = CallRPC("signmessage " + demoAddress.ToString() + " mymessage"));
+ BOOST_CHECK_THROW(CallRPC("signmessage"), runtime_error);
+ /* Should throw error because this address is not loaded in the wallet */
+ BOOST_CHECK_THROW(CallRPC("signmessage 1QFqqMUD55ZV3PJEJZtaKCsQmjLT6JkjvJ mymessage"), runtime_error);
+
+ /* missing arguments */
+ BOOST_CHECK_THROW(CallRPC("verifymessage "+ demoAddress.ToString()), runtime_error);
+ BOOST_CHECK_THROW(CallRPC("verifymessage "+ demoAddress.ToString() + " " + retValue.get_str()), runtime_error);
+ /* Illegal address */
+ BOOST_CHECK_THROW(CallRPC("verifymessage 1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4X " + retValue.get_str() + " mymessage"), runtime_error);
+ /* wrong address */
+ BOOST_CHECK(CallRPC("verifymessage 1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ " + retValue.get_str() + " mymessage").get_bool() == false);
+ /* Correct address and signature but wrong message */
+ BOOST_CHECK(CallRPC("verifymessage "+ demoAddress.ToString() + " " + retValue.get_str() + " wrongmessage").get_bool() == false);
+ /* Correct address, message and signature*/
+ BOOST_CHECK(CallRPC("verifymessage "+ demoAddress.ToString() + " " + retValue.get_str() + " mymessage").get_bool() == true);
+
+ /*********************************
+ * getaddressesbyaccount
+ *********************************/
+ BOOST_CHECK_THROW(CallRPC("getaddressesbyaccount"), runtime_error);
+ BOOST_CHECK_NO_THROW(retValue = CallRPC("getaddressesbyaccount " + strAccount));
+ Array arr = retValue.get_array();
+ BOOST_CHECK(arr.size() > 0);
+ BOOST_CHECK(CBitcoinAddress(arr[0].get_str()).Get() == demoAddress.Get());
+
}
+
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/script_P2SH_tests.cpp b/src/test/script_P2SH_tests.cpp
index 9b1290e0ea..a1dc17ba36 100644
--- a/src/test/script_P2SH_tests.cpp
+++ b/src/test/script_P2SH_tests.cpp
@@ -30,11 +30,11 @@ static bool
Verify(const CScript& scriptSig, const CScript& scriptPubKey, bool fStrict)
{
// Create dummy to/from transactions:
- CTransaction txFrom;
+ CMutableTransaction txFrom;
txFrom.vout.resize(1);
txFrom.vout[0].scriptPubKey = scriptPubKey;
- CTransaction txTo;
+ CMutableTransaction txTo;
txTo.vin.resize(1);
txTo.vout.resize(1);
txTo.vin[0].prevout.n = 0;
@@ -78,7 +78,7 @@ BOOST_AUTO_TEST_CASE(sign)
evalScripts[i].SetDestination(standardScripts[i].GetID());
}
- CTransaction txFrom; // Funding transaction:
+ CMutableTransaction txFrom; // Funding transaction:
string reason;
txFrom.vout.resize(8);
for (int i = 0; i < 4; i++)
@@ -90,7 +90,7 @@ BOOST_AUTO_TEST_CASE(sign)
}
BOOST_CHECK(IsStandardTx(txFrom, reason));
- CTransaction txTo[8]; // Spending transactions
+ CMutableTransaction txTo[8]; // Spending transactions
for (int i = 0; i < 8; i++)
{
txTo[i].vin.resize(1);
@@ -173,7 +173,7 @@ BOOST_AUTO_TEST_CASE(set)
keystore.AddCScript(inner[i]);
}
- CTransaction txFrom; // Funding transaction:
+ CMutableTransaction txFrom; // Funding transaction:
string reason;
txFrom.vout.resize(4);
for (int i = 0; i < 4; i++)
@@ -183,7 +183,7 @@ BOOST_AUTO_TEST_CASE(set)
}
BOOST_CHECK(IsStandardTx(txFrom, reason));
- CTransaction txTo[4]; // Spending transactions
+ CMutableTransaction txTo[4]; // Spending transactions
for (int i = 0; i < 4; i++)
{
txTo[i].vin.resize(1);
@@ -256,66 +256,86 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard)
CCoinsView coinsDummy;
CCoinsViewCache coins(coinsDummy);
CBasicKeyStore keystore;
- CKey key[3];
+ CKey key[6];
vector<CPubKey> keys;
- for (int i = 0; i < 3; i++)
+ for (int i = 0; i < 6; i++)
{
key[i].MakeNewKey(true);
keystore.AddKey(key[i]);
- keys.push_back(key[i].GetPubKey());
}
+ for (int i = 0; i < 3; i++)
+ keys.push_back(key[i].GetPubKey());
- CTransaction txFrom;
- txFrom.vout.resize(6);
+ CMutableTransaction txFrom;
+ txFrom.vout.resize(7);
// First three are standard:
CScript pay1; pay1.SetDestination(key[0].GetPubKey().GetID());
keystore.AddCScript(pay1);
- CScript payScriptHash1; payScriptHash1.SetDestination(pay1.GetID());
CScript pay1of3; pay1of3.SetMultisig(1, keys);
- txFrom.vout[0].scriptPubKey = payScriptHash1;
+ txFrom.vout[0].scriptPubKey.SetDestination(pay1.GetID()); // P2SH (OP_CHECKSIG)
txFrom.vout[0].nValue = 1000;
- txFrom.vout[1].scriptPubKey = pay1;
+ txFrom.vout[1].scriptPubKey = pay1; // ordinary OP_CHECKSIG
txFrom.vout[1].nValue = 2000;
- txFrom.vout[2].scriptPubKey = pay1of3;
+ txFrom.vout[2].scriptPubKey = pay1of3; // ordinary OP_CHECKMULTISIG
txFrom.vout[2].nValue = 3000;
- // Last three non-standard:
- CScript empty;
- keystore.AddCScript(empty);
- txFrom.vout[3].scriptPubKey = empty;
+ // vout[3] is complicated 1-of-3 AND 2-of-3
+ // ... that is OK if wrapped in P2SH:
+ CScript oneAndTwo;
+ oneAndTwo << OP_1 << key[0].GetPubKey() << key[1].GetPubKey() << key[2].GetPubKey();
+ oneAndTwo << OP_3 << OP_CHECKMULTISIGVERIFY;
+ oneAndTwo << OP_2 << key[3].GetPubKey() << key[4].GetPubKey() << key[5].GetPubKey();
+ oneAndTwo << OP_3 << OP_CHECKMULTISIG;
+ keystore.AddCScript(oneAndTwo);
+ txFrom.vout[3].scriptPubKey.SetDestination(oneAndTwo.GetID());
txFrom.vout[3].nValue = 4000;
- // Can't use SetPayToScriptHash, it checks for the empty Script. So:
- txFrom.vout[4].scriptPubKey << OP_HASH160 << Hash160(empty) << OP_EQUAL;
+
+ // vout[4] is max sigops:
+ CScript fifteenSigops; fifteenSigops << OP_1;
+ for (unsigned i = 0; i < MAX_P2SH_SIGOPS; i++)
+ fifteenSigops << key[i%3].GetPubKey();
+ fifteenSigops << OP_15 << OP_CHECKMULTISIG;
+ keystore.AddCScript(fifteenSigops);
+ txFrom.vout[4].scriptPubKey.SetDestination(fifteenSigops.GetID());
txFrom.vout[4].nValue = 5000;
- CScript oneOfEleven;
- oneOfEleven << OP_1;
- for (int i = 0; i < 11; i++)
- oneOfEleven << key[0].GetPubKey();
- oneOfEleven << OP_11 << OP_CHECKMULTISIG;
- txFrom.vout[5].scriptPubKey.SetDestination(oneOfEleven.GetID());
- txFrom.vout[5].nValue = 6000;
+
+ // vout[5/6] are non-standard because they exceed MAX_P2SH_SIGOPS
+ CScript sixteenSigops; sixteenSigops << OP_16 << OP_CHECKMULTISIG;
+ keystore.AddCScript(sixteenSigops);
+ txFrom.vout[5].scriptPubKey.SetDestination(fifteenSigops.GetID());
+ txFrom.vout[5].nValue = 5000;
+ CScript twentySigops; twentySigops << OP_CHECKMULTISIG;
+ keystore.AddCScript(twentySigops);
+ txFrom.vout[6].scriptPubKey.SetDestination(twentySigops.GetID());
+ txFrom.vout[6].nValue = 6000;
+
coins.SetCoins(txFrom.GetHash(), CCoins(txFrom, 0));
- CTransaction txTo;
+ CMutableTransaction txTo;
txTo.vout.resize(1);
txTo.vout[0].scriptPubKey.SetDestination(key[1].GetPubKey().GetID());
- txTo.vin.resize(3);
- txTo.vin[0].prevout.n = 0;
- txTo.vin[0].prevout.hash = txFrom.GetHash();
+ txTo.vin.resize(5);
+ for (int i = 0; i < 5; i++)
+ {
+ txTo.vin[i].prevout.n = i;
+ txTo.vin[i].prevout.hash = txFrom.GetHash();
+ }
BOOST_CHECK(SignSignature(keystore, txFrom, txTo, 0));
- txTo.vin[1].prevout.n = 1;
- txTo.vin[1].prevout.hash = txFrom.GetHash();
BOOST_CHECK(SignSignature(keystore, txFrom, txTo, 1));
- txTo.vin[2].prevout.n = 2;
- txTo.vin[2].prevout.hash = txFrom.GetHash();
BOOST_CHECK(SignSignature(keystore, txFrom, txTo, 2));
+ // SignSignature doesn't know how to sign these. We're
+ // not testing validating signatures, so just create
+ // dummy signatures that DO include the correct P2SH scripts:
+ txTo.vin[3].scriptSig << OP_11 << OP_11 << static_cast<vector<unsigned char> >(oneAndTwo);
+ txTo.vin[4].scriptSig << static_cast<vector<unsigned char> >(fifteenSigops);
BOOST_CHECK(::AreInputsStandard(txTo, coins));
- BOOST_CHECK_EQUAL(GetP2SHSigOpCount(txTo, coins), 1U);
+ // 22 P2SH sigops for all inputs (1 for vin[0], 6 for vin[3], 15 for vin[4]
+ BOOST_CHECK_EQUAL(GetP2SHSigOpCount(txTo, coins), 22U);
// Make sure adding crap to the scriptSigs makes them non-standard:
for (int i = 0; i < 3; i++)
@@ -326,23 +346,29 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard)
txTo.vin[i].scriptSig = t;
}
- CTransaction txToNonStd;
- txToNonStd.vout.resize(1);
- txToNonStd.vout[0].scriptPubKey.SetDestination(key[1].GetPubKey().GetID());
- txToNonStd.vout[0].nValue = 1000;
- txToNonStd.vin.resize(2);
- txToNonStd.vin[0].prevout.n = 4;
- txToNonStd.vin[0].prevout.hash = txFrom.GetHash();
- txToNonStd.vin[0].scriptSig << Serialize(empty);
- txToNonStd.vin[1].prevout.n = 5;
- txToNonStd.vin[1].prevout.hash = txFrom.GetHash();
- txToNonStd.vin[1].scriptSig << OP_0 << Serialize(oneOfEleven);
-
- BOOST_CHECK(!::AreInputsStandard(txToNonStd, coins));
- BOOST_CHECK_EQUAL(GetP2SHSigOpCount(txToNonStd, coins), 11U);
-
- txToNonStd.vin[0].scriptSig.clear();
- BOOST_CHECK(!::AreInputsStandard(txToNonStd, coins));
+ CMutableTransaction txToNonStd1;
+ txToNonStd1.vout.resize(1);
+ txToNonStd1.vout[0].scriptPubKey.SetDestination(key[1].GetPubKey().GetID());
+ txToNonStd1.vout[0].nValue = 1000;
+ txToNonStd1.vin.resize(1);
+ txToNonStd1.vin[0].prevout.n = 5;
+ txToNonStd1.vin[0].prevout.hash = txFrom.GetHash();
+ txToNonStd1.vin[0].scriptSig << static_cast<vector<unsigned char> >(sixteenSigops);
+
+ BOOST_CHECK(!::AreInputsStandard(txToNonStd1, coins));
+ BOOST_CHECK_EQUAL(GetP2SHSigOpCount(txToNonStd1, coins), 16U);
+
+ CMutableTransaction txToNonStd2;
+ txToNonStd2.vout.resize(1);
+ txToNonStd2.vout[0].scriptPubKey.SetDestination(key[1].GetPubKey().GetID());
+ txToNonStd2.vout[0].nValue = 1000;
+ txToNonStd2.vin.resize(1);
+ txToNonStd2.vin[0].prevout.n = 6;
+ txToNonStd2.vin[0].prevout.hash = txFrom.GetHash();
+ txToNonStd2.vin[0].scriptSig << static_cast<vector<unsigned char> >(twentySigops);
+
+ BOOST_CHECK(!::AreInputsStandard(txToNonStd2, coins));
+ BOOST_CHECK_EQUAL(GetP2SHSigOpCount(txToNonStd2, coins), 20U);
}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp
index 29d518d707..cba582e941 100644
--- a/src/test/script_tests.cpp
+++ b/src/test/script_tests.cpp
@@ -240,11 +240,11 @@ BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG12)
CScript scriptPubKey12;
scriptPubKey12 << OP_1 << key1.GetPubKey() << key2.GetPubKey() << OP_2 << OP_CHECKMULTISIG;
- CTransaction txFrom12;
+ CMutableTransaction txFrom12;
txFrom12.vout.resize(1);
txFrom12.vout[0].scriptPubKey = scriptPubKey12;
- CTransaction txTo12;
+ CMutableTransaction txTo12;
txTo12.vin.resize(1);
txTo12.vout.resize(1);
txTo12.vin[0].prevout.n = 0;
@@ -274,11 +274,11 @@ BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG23)
CScript scriptPubKey23;
scriptPubKey23 << OP_2 << key1.GetPubKey() << key2.GetPubKey() << key3.GetPubKey() << OP_3 << OP_CHECKMULTISIG;
- CTransaction txFrom23;
+ CMutableTransaction txFrom23;
txFrom23.vout.resize(1);
txFrom23.vout[0].scriptPubKey = scriptPubKey23;
- CTransaction txTo23;
+ CMutableTransaction txTo23;
txTo23.vin.resize(1);
txTo23.vout.resize(1);
txTo23.vin[0].prevout.n = 0;
@@ -345,11 +345,11 @@ BOOST_AUTO_TEST_CASE(script_combineSigs)
keystore.AddKey(key);
}
- CTransaction txFrom;
+ CMutableTransaction txFrom;
txFrom.vout.resize(1);
txFrom.vout[0].scriptPubKey.SetDestination(keys[0].GetPubKey().GetID());
CScript& scriptPubKey = txFrom.vout[0].scriptPubKey;
- CTransaction txTo;
+ CMutableTransaction txTo;
txTo.vin.resize(1);
txTo.vout.resize(1);
txTo.vin[0].prevout.n = 0;
diff --git a/src/test/sighash_tests.cpp b/src/test/sighash_tests.cpp
index 353fd60f7b..423ae4a789 100644
--- a/src/test/sighash_tests.cpp
+++ b/src/test/sighash_tests.cpp
@@ -28,7 +28,7 @@ uint256 static SignatureHashOld(CScript scriptCode, const CTransaction& txTo, un
printf("ERROR: SignatureHash() : nIn=%d out of range\n", nIn);
return 1;
}
- CTransaction txTmp(txTo);
+ CMutableTransaction txTmp(txTo);
// In case concatenating two scripts ends up with two codeseparators,
// or an extra one at the end, this prevents all those possible incompatibilities.
@@ -90,7 +90,7 @@ void static RandomScript(CScript &script) {
script << oplist[insecure_rand() % (sizeof(oplist)/sizeof(oplist[0]))];
}
-void static RandomTransaction(CTransaction &tx, bool fSingle) {
+void static RandomTransaction(CMutableTransaction &tx, bool fSingle) {
tx.nVersion = insecure_rand();
tx.vin.clear();
tx.vout.clear();
@@ -130,7 +130,7 @@ BOOST_AUTO_TEST_CASE(sighash_test)
#endif
for (int i=0; i<nRandomTests; i++) {
int nHashType = insecure_rand();
- CTransaction txTo;
+ CMutableTransaction txTo;
RandomTransaction(txTo, (nHashType & 0x1f) == SIGHASH_SINGLE);
CScript scriptCode;
RandomScript(scriptCode);
diff --git a/src/test/skiplist_tests.cpp b/src/test/skiplist_tests.cpp
new file mode 100644
index 0000000000..11762c6ea0
--- /dev/null
+++ b/src/test/skiplist_tests.cpp
@@ -0,0 +1,101 @@
+// Copyright (c) 2014 The Bitcoin Core developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <boost/test/unit_test.hpp>
+#include <vector>
+#include "main.h"
+#include "util.h"
+
+
+#define SKIPLIST_LENGTH 300000
+
+BOOST_AUTO_TEST_SUITE(skiplist_tests)
+
+BOOST_AUTO_TEST_CASE(skiplist_test)
+{
+ std::vector<CBlockIndex> vIndex(SKIPLIST_LENGTH);
+
+ for (int i=0; i<SKIPLIST_LENGTH; i++) {
+ vIndex[i].nHeight = i;
+ vIndex[i].pprev = (i == 0) ? NULL : &vIndex[i - 1];
+ vIndex[i].BuildSkip();
+ }
+
+ for (int i=0; i<SKIPLIST_LENGTH; i++) {
+ if (i > 0) {
+ BOOST_CHECK(vIndex[i].pskip == &vIndex[vIndex[i].pskip->nHeight]);
+ BOOST_CHECK(vIndex[i].pskip->nHeight < i);
+ } else {
+ BOOST_CHECK(vIndex[i].pskip == NULL);
+ }
+ }
+
+ for (int i=0; i < 1000; i++) {
+ int from = insecure_rand() % (SKIPLIST_LENGTH - 1);
+ int to = insecure_rand() % (from + 1);
+
+ BOOST_CHECK(vIndex[SKIPLIST_LENGTH - 1].GetAncestor(from) == &vIndex[from]);
+ BOOST_CHECK(vIndex[from].GetAncestor(to) == &vIndex[to]);
+ BOOST_CHECK(vIndex[from].GetAncestor(0) == &vIndex[0]);
+ }
+}
+
+BOOST_AUTO_TEST_CASE(getlocator_test)
+{
+ // Build a main chain 100000 blocks long.
+ std::vector<uint256> vHashMain(100000);
+ std::vector<CBlockIndex> vBlocksMain(100000);
+ for (unsigned int i=0; i<vBlocksMain.size(); i++) {
+ vHashMain[i] = i; // Set the hash equal to the height, so we can quickly check the distances.
+ vBlocksMain[i].nHeight = i;
+ vBlocksMain[i].pprev = i ? &vBlocksMain[i - 1] : NULL;
+ vBlocksMain[i].phashBlock = &vHashMain[i];
+ vBlocksMain[i].BuildSkip();
+ BOOST_CHECK_EQUAL((int)vBlocksMain[i].GetBlockHash().GetLow64(), vBlocksMain[i].nHeight);
+ BOOST_CHECK(vBlocksMain[i].pprev == NULL || vBlocksMain[i].nHeight == vBlocksMain[i].pprev->nHeight + 1);
+ }
+
+ // Build a branch that splits off at block 49999, 50000 blocks long.
+ std::vector<uint256> vHashSide(50000);
+ std::vector<CBlockIndex> vBlocksSide(50000);
+ for (unsigned int i=0; i<vBlocksSide.size(); i++) {
+ vHashSide[i] = i + 50000 + (uint256(1) << 128); // Add 1<<128 to the hashes, so GetLow64() still returns the height.
+ vBlocksSide[i].nHeight = i + 50000;
+ vBlocksSide[i].pprev = i ? &vBlocksSide[i - 1] : &vBlocksMain[49999];
+ vBlocksSide[i].phashBlock = &vHashSide[i];
+ vBlocksSide[i].BuildSkip();
+ BOOST_CHECK_EQUAL((int)vBlocksSide[i].GetBlockHash().GetLow64(), vBlocksSide[i].nHeight);
+ BOOST_CHECK(vBlocksSide[i].pprev == NULL || vBlocksSide[i].nHeight == vBlocksSide[i].pprev->nHeight + 1);
+ }
+
+ // Build a CChain for the main branch.
+ CChain chain;
+ chain.SetTip(&vBlocksMain.back());
+
+ // Test 100 random starting points for locators.
+ for (int n=0; n<100; n++) {
+ int r = insecure_rand() % 150000;
+ CBlockIndex* tip = (r < 100000) ? &vBlocksMain[r] : &vBlocksSide[r - 100000];
+ CBlockLocator locator = chain.GetLocator(tip);
+
+ // The first result must be the block itself, the last one must be genesis.
+ BOOST_CHECK(locator.vHave.front() == tip->GetBlockHash());
+ BOOST_CHECK(locator.vHave.back() == vBlocksMain[0].GetBlockHash());
+
+ // Entries 1 through 11 (inclusive) go back one step each.
+ for (unsigned int i = 1; i < 12 && i < locator.vHave.size() - 1; i++) {
+ BOOST_CHECK_EQUAL(locator.vHave[i].GetLow64(), tip->nHeight - i);
+ }
+
+ // The further ones (excluding the last one) go back with exponential steps.
+ unsigned int dist = 2;
+ for (unsigned int i = 12; i < locator.vHave.size() - 1; i++) {
+ BOOST_CHECK_EQUAL(locator.vHave[i - 1].GetLow64() - locator.vHave[i].GetLow64(), dist);
+ dist *= 2;
+ }
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp
index 2d993e24db..bcd2f75f55 100644
--- a/src/test/test_bitcoin.cpp
+++ b/src/test/test_bitcoin.cpp
@@ -18,7 +18,7 @@
#include <boost/filesystem.hpp>
#include <boost/test/unit_test.hpp>
-
+CClientUIInterface uiInterface;
CWallet* pwalletMain;
extern bool fPrintToConsole;
@@ -31,6 +31,7 @@ struct TestingSetup {
TestingSetup() {
fPrintToDebugLog = false; // don't want to write to debug.log file
+ SelectParams(CBaseChainParams::MAIN);
noui_connect();
#ifdef ENABLE_WALLET
bitdb.MakeMock();
diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp
index feba5ee80e..238033f407 100644
--- a/src/test/transaction_tests.cpp
+++ b/src/test/transaction_tests.cpp
@@ -208,7 +208,7 @@ BOOST_AUTO_TEST_CASE(basic_transaction_tests)
unsigned char ch[] = {0x01, 0x00, 0x00, 0x00, 0x01, 0x6b, 0xff, 0x7f, 0xcd, 0x4f, 0x85, 0x65, 0xef, 0x40, 0x6d, 0xd5, 0xd6, 0x3d, 0x4f, 0xf9, 0x4f, 0x31, 0x8f, 0xe8, 0x20, 0x27, 0xfd, 0x4d, 0xc4, 0x51, 0xb0, 0x44, 0x74, 0x01, 0x9f, 0x74, 0xb4, 0x00, 0x00, 0x00, 0x00, 0x8c, 0x49, 0x30, 0x46, 0x02, 0x21, 0x00, 0xda, 0x0d, 0xc6, 0xae, 0xce, 0xfe, 0x1e, 0x06, 0xef, 0xdf, 0x05, 0x77, 0x37, 0x57, 0xde, 0xb1, 0x68, 0x82, 0x09, 0x30, 0xe3, 0xb0, 0xd0, 0x3f, 0x46, 0xf5, 0xfc, 0xf1, 0x50, 0xbf, 0x99, 0x0c, 0x02, 0x21, 0x00, 0xd2, 0x5b, 0x5c, 0x87, 0x04, 0x00, 0x76, 0xe4, 0xf2, 0x53, 0xf8, 0x26, 0x2e, 0x76, 0x3e, 0x2d, 0xd5, 0x1e, 0x7f, 0xf0, 0xbe, 0x15, 0x77, 0x27, 0xc4, 0xbc, 0x42, 0x80, 0x7f, 0x17, 0xbd, 0x39, 0x01, 0x41, 0x04, 0xe6, 0xc2, 0x6e, 0xf6, 0x7d, 0xc6, 0x10, 0xd2, 0xcd, 0x19, 0x24, 0x84, 0x78, 0x9a, 0x6c, 0xf9, 0xae, 0xa9, 0x93, 0x0b, 0x94, 0x4b, 0x7e, 0x2d, 0xb5, 0x34, 0x2b, 0x9d, 0x9e, 0x5b, 0x9f, 0xf7, 0x9a, 0xff, 0x9a, 0x2e, 0xe1, 0x97, 0x8d, 0xd7, 0xfd, 0x01, 0xdf, 0xc5, 0x22, 0xee, 0x02, 0x28, 0x3d, 0x3b, 0x06, 0xa9, 0xd0, 0x3a, 0xcf, 0x80, 0x96, 0x96, 0x8d, 0x7d, 0xbb, 0x0f, 0x91, 0x78, 0xff, 0xff, 0xff, 0xff, 0x02, 0x8b, 0xa7, 0x94, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x19, 0x76, 0xa9, 0x14, 0xba, 0xde, 0xec, 0xfd, 0xef, 0x05, 0x07, 0x24, 0x7f, 0xc8, 0xf7, 0x42, 0x41, 0xd7, 0x3b, 0xc0, 0x39, 0x97, 0x2d, 0x7b, 0x88, 0xac, 0x40, 0x94, 0xa8, 0x02, 0x00, 0x00, 0x00, 0x00, 0x19, 0x76, 0xa9, 0x14, 0xc1, 0x09, 0x32, 0x48, 0x3f, 0xec, 0x93, 0xed, 0x51, 0xf5, 0xfe, 0x95, 0xe7, 0x25, 0x59, 0xf2, 0xcc, 0x70, 0x43, 0xf9, 0x88, 0xac, 0x00, 0x00, 0x00, 0x00, 0x00};
vector<unsigned char> vch(ch, ch + sizeof(ch) -1);
CDataStream stream(vch, SER_DISK, CLIENT_VERSION);
- CTransaction tx;
+ CMutableTransaction tx;
stream >> tx;
CValidationState state;
BOOST_CHECK_MESSAGE(CheckTransaction(tx, state) && state.IsValid(), "Simple deserialized transaction should be valid.");
@@ -224,10 +224,10 @@ BOOST_AUTO_TEST_CASE(basic_transaction_tests)
// paid to a TX_PUBKEY, the second 21 and 22 CENT outputs
// paid to a TX_PUBKEYHASH.
//
-static std::vector<CTransaction>
+static std::vector<CMutableTransaction>
SetupDummyInputs(CBasicKeyStore& keystoreRet, CCoinsView & coinsRet)
{
- std::vector<CTransaction> dummyTransactions;
+ std::vector<CMutableTransaction> dummyTransactions;
dummyTransactions.resize(2);
// Add some keys to the keystore:
@@ -261,9 +261,9 @@ BOOST_AUTO_TEST_CASE(test_Get)
CBasicKeyStore keystore;
CCoinsView coinsDummy;
CCoinsViewCache coins(coinsDummy);
- std::vector<CTransaction> dummyTransactions = SetupDummyInputs(keystore, coins);
+ std::vector<CMutableTransaction> dummyTransactions = SetupDummyInputs(keystore, coins);
- CTransaction t1;
+ CMutableTransaction t1;
t1.vin.resize(3);
t1.vin[0].prevout.hash = dummyTransactions[0].GetHash();
t1.vin[0].prevout.n = 1;
@@ -296,9 +296,9 @@ BOOST_AUTO_TEST_CASE(test_IsStandard)
CBasicKeyStore keystore;
CCoinsView coinsDummy;
CCoinsViewCache coins(coinsDummy);
- std::vector<CTransaction> dummyTransactions = SetupDummyInputs(keystore, coins);
+ std::vector<CMutableTransaction> dummyTransactions = SetupDummyInputs(keystore, coins);
- CTransaction t;
+ CMutableTransaction t;
t.vin.resize(1);
t.vin[0].prevout.hash = dummyTransactions[0].GetHash();
t.vin[0].prevout.n = 1;
diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp
index 3811569c0a..0b071361d8 100644
--- a/src/test/util_tests.cpp
+++ b/src/test/util_tests.cpp
@@ -108,13 +108,11 @@ BOOST_AUTO_TEST_CASE(util_HexStr)
BOOST_AUTO_TEST_CASE(util_DateTimeStrFormat)
{
-/*These are platform-dependant and thus removed to avoid useless test failures
BOOST_CHECK_EQUAL(DateTimeStrFormat("%Y-%m-%d %H:%M:%S", 0), "1970-01-01 00:00:00");
BOOST_CHECK_EQUAL(DateTimeStrFormat("%Y-%m-%d %H:%M:%S", 0x7FFFFFFF), "2038-01-19 03:14:07");
- // Formats used within Bitcoin
BOOST_CHECK_EQUAL(DateTimeStrFormat("%Y-%m-%d %H:%M:%S", 1317425777), "2011-09-30 23:36:17");
BOOST_CHECK_EQUAL(DateTimeStrFormat("%Y-%m-%d %H:%M", 1317425777), "2011-09-30 23:36");
-*/
+ BOOST_CHECK_EQUAL(DateTimeStrFormat("%a, %d %b %Y %H:%M:%S +0000", 1317425777), "Fri, 30 Sep 2011 23:36:17 +0000");
}
BOOST_AUTO_TEST_CASE(util_ParseParameters)
@@ -353,4 +351,15 @@ BOOST_AUTO_TEST_CASE(test_ParseInt32)
BOOST_CHECK(!ParseInt32("32482348723847471234", NULL));
}
+BOOST_AUTO_TEST_CASE(test_FormatParagraph)
+{
+ BOOST_CHECK_EQUAL(FormatParagraph("", 79, 0), "");
+ BOOST_CHECK_EQUAL(FormatParagraph("test", 79, 0), "test");
+ BOOST_CHECK_EQUAL(FormatParagraph(" test", 79, 0), "test");
+ BOOST_CHECK_EQUAL(FormatParagraph("test test", 79, 0), "test test");
+ BOOST_CHECK_EQUAL(FormatParagraph("test test", 4, 0), "test\ntest");
+ BOOST_CHECK_EQUAL(FormatParagraph("testerde test ", 4, 0), "testerde\ntest");
+ BOOST_CHECK_EQUAL(FormatParagraph("test test", 4, 4), "test\n test");
+}
+
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/wallet_tests.cpp b/src/test/wallet_tests.cpp
index 1993358826..3887efbd0d 100644
--- a/src/test/wallet_tests.cpp
+++ b/src/test/wallet_tests.cpp
@@ -31,20 +31,22 @@ static vector<COutput> vCoins;
static void add_coin(int64_t nValue, int nAge = 6*24, bool fIsFromMe = false, int nInput=0)
{
static int nextLockTime = 0;
- CTransaction tx;
+ CMutableTransaction tx;
tx.nLockTime = nextLockTime++; // so all transactions get different hashes
tx.vout.resize(nInput+1);
tx.vout[nInput].nValue = nValue;
+ if (fIsFromMe) {
+ // IsFromMe() returns (GetDebit() > 0), and GetDebit() is 0 if vin.empty(),
+ // so stop vin being empty, and cache a non-zero Debit to fake out IsFromMe()
+ tx.vin.resize(1);
+ }
CWalletTx* wtx = new CWalletTx(&wallet, tx);
if (fIsFromMe)
{
- // IsFromMe() returns (GetDebit() > 0), and GetDebit() is 0 if vin.empty(),
- // so stop vin being empty, and cache a non-zero Debit to fake out IsFromMe()
- wtx->vin.resize(1);
wtx->fDebitCached = true;
wtx->nDebitCached = 1;
}
- COutput output(wtx, nInput, nAge);
+ COutput output(wtx, nInput, nAge, true);
vCoins.push_back(output);
}
diff --git a/src/timedata.cpp b/src/timedata.cpp
new file mode 100644
index 0000000000..8a095d26dc
--- /dev/null
+++ b/src/timedata.cpp
@@ -0,0 +1,91 @@
+// Copyright (c) 2014 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 "timedata.h"
+
+#include "netbase.h"
+#include "sync.h"
+#include "ui_interface.h"
+#include "util.h"
+
+#include <boost/foreach.hpp>
+
+using namespace std;
+
+static CCriticalSection cs_nTimeOffset;
+static int64_t nTimeOffset = 0;
+
+//
+// "Never go to sea with two chronometers; take one or three."
+// Our three time sources are:
+// - System clock
+// - Median of other nodes clocks
+// - The user (asking the user to fix the system clock if the first two disagree)
+//
+//
+int64_t GetTimeOffset()
+{
+ LOCK(cs_nTimeOffset);
+ return nTimeOffset;
+}
+
+int64_t GetAdjustedTime()
+{
+ return GetTime() + GetTimeOffset();
+}
+
+void AddTimeData(const CNetAddr& ip, int64_t nTime)
+{
+ int64_t nOffsetSample = nTime - GetTime();
+
+ LOCK(cs_nTimeOffset);
+ // Ignore duplicates
+ static set<CNetAddr> setKnown;
+ if (!setKnown.insert(ip).second)
+ return;
+
+ // Add data
+ static CMedianFilter<int64_t> vTimeOffsets(200,0);
+ vTimeOffsets.input(nOffsetSample);
+ LogPrintf("Added time data, samples %d, offset %+d (%+d minutes)\n", vTimeOffsets.size(), nOffsetSample, nOffsetSample/60);
+ if (vTimeOffsets.size() >= 5 && vTimeOffsets.size() % 2 == 1)
+ {
+ int64_t nMedian = vTimeOffsets.median();
+ std::vector<int64_t> vSorted = vTimeOffsets.sorted();
+ // Only let other nodes change our time by so much
+ if (abs64(nMedian) < 70 * 60)
+ {
+ nTimeOffset = nMedian;
+ }
+ else
+ {
+ nTimeOffset = 0;
+
+ static bool fDone;
+ if (!fDone)
+ {
+ // If nobody has a time different than ours but within 5 minutes of ours, give a warning
+ bool fMatch = false;
+ BOOST_FOREACH(int64_t nOffset, vSorted)
+ if (nOffset != 0 && abs64(nOffset) < 5 * 60)
+ fMatch = true;
+
+ if (!fMatch)
+ {
+ fDone = true;
+ string strMessage = _("Warning: Please check that your computer's date and time are correct! If your clock is wrong Bitcoin will not work properly.");
+ strMiscWarning = strMessage;
+ LogPrintf("*** %s\n", strMessage);
+ uiInterface.ThreadSafeMessageBox(strMessage, "", CClientUIInterface::MSG_WARNING);
+ }
+ }
+ }
+ if (fDebug) {
+ BOOST_FOREACH(int64_t n, vSorted)
+ LogPrintf("%+d ", n);
+ LogPrintf("| ");
+ }
+ LogPrintf("nTimeOffset = %+d (%+d minutes)\n", nTimeOffset, nTimeOffset/60);
+ }
+}
diff --git a/src/timedata.h b/src/timedata.h
new file mode 100644
index 0000000000..0e7bdc2c1f
--- /dev/null
+++ b/src/timedata.h
@@ -0,0 +1,17 @@
+// Copyright (c) 2014 The Bitcoin developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_TIMEDATA_H
+#define BITCOIN_TIMEDATA_H
+
+#include <stdint.h>
+
+class CNetAddr;
+
+/* Functions to keep track of adjusted P2P time */
+int64_t GetTimeOffset();
+int64_t GetAdjustedTime();
+void AddTimeData(const CNetAddr& ip, int64_t nTime);
+
+#endif
diff --git a/src/txdb.cpp b/src/txdb.cpp
index 4eab8525a5..52cd96283e 100644
--- a/src/txdb.cpp
+++ b/src/txdb.cpp
@@ -6,6 +6,7 @@
#include "txdb.h"
#include "core.h"
+#include "pow.h"
#include "uint256.h"
#include <stdint.h>
@@ -53,11 +54,11 @@ bool CCoinsViewDB::SetBestBlock(const uint256 &hashBlock) {
return db.WriteBatch(batch);
}
-bool CCoinsViewDB::BatchWrite(const std::map<uint256, CCoins> &mapCoins, const uint256 &hashBlock) {
+bool CCoinsViewDB::BatchWrite(const CCoinsMap &mapCoins, const uint256 &hashBlock) {
LogPrint("coindb", "Committing %u changed transactions to coin database...\n", (unsigned int)mapCoins.size());
CLevelDBBatch batch;
- for (std::map<uint256, CCoins>::const_iterator it = mapCoins.begin(); it != mapCoins.end(); it++)
+ for (CCoinsMap::const_iterator it = mapCoins.begin(); it != mapCoins.end(); it++)
BatchWriteCoins(batch, it->first, it->second);
if (hashBlock != uint256(0))
BatchWriteHashBestChain(batch, hashBlock);
@@ -212,8 +213,8 @@ bool CBlockTreeDB::LoadBlockIndexGuts()
pindexNew->nStatus = diskindex.nStatus;
pindexNew->nTx = diskindex.nTx;
- if (!pindexNew->CheckIndex())
- return error("LoadBlockIndex() : CheckIndex failed: %s", pindexNew->ToString());
+ if (!CheckProofOfWork(pindexNew->GetBlockHash(), pindexNew->nBits))
+ return error("LoadBlockIndex() : CheckProofOfWork failed: %s", pindexNew->ToString());
pcursor->Next();
} else {
diff --git a/src/txdb.h b/src/txdb.h
index 7257b0dd21..7d670c2542 100644
--- a/src/txdb.h
+++ b/src/txdb.h
@@ -37,7 +37,7 @@ public:
bool HaveCoins(const uint256 &txid);
uint256 GetBestBlock();
bool SetBestBlock(const uint256 &hashBlock);
- bool BatchWrite(const std::map<uint256, CCoins> &mapCoins, const uint256 &hashBlock);
+ bool BatchWrite(const CCoinsMap &mapCoins, const uint256 &hashBlock);
bool GetStats(CCoinsStats &stats);
};
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
index 64c9eac73d..a852de5da8 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -6,6 +6,8 @@
#include "core.h"
#include "txmempool.h"
+#include <boost/circular_buffer.hpp>
+
using namespace std;
CTxMemPoolEntry::CTxMemPoolEntry()
@@ -35,12 +37,316 @@ CTxMemPoolEntry::GetPriority(unsigned int currentHeight) const
return dResult;
}
-CTxMemPool::CTxMemPool()
+//
+// Keep track of fee/priority for transactions confirmed within N blocks
+//
+class CBlockAverage
+{
+private:
+ boost::circular_buffer<CFeeRate> feeSamples;
+ boost::circular_buffer<double> prioritySamples;
+
+ template<typename T> std::vector<T> buf2vec(boost::circular_buffer<T> buf) const
+ {
+ std::vector<T> vec(buf.begin(), buf.end());
+ return vec;
+ }
+
+public:
+ CBlockAverage() : feeSamples(100), prioritySamples(100) { }
+
+ void RecordFee(const CFeeRate& feeRate) {
+ feeSamples.push_back(feeRate);
+ }
+
+ void RecordPriority(double priority) {
+ prioritySamples.push_back(priority);
+ }
+
+ size_t FeeSamples() const { return feeSamples.size(); }
+ size_t GetFeeSamples(std::vector<CFeeRate>& insertInto) const
+ {
+ BOOST_FOREACH(const CFeeRate& f, feeSamples)
+ insertInto.push_back(f);
+ return feeSamples.size();
+ }
+ size_t PrioritySamples() const { return prioritySamples.size(); }
+ size_t GetPrioritySamples(std::vector<double>& insertInto) const
+ {
+ BOOST_FOREACH(double d, prioritySamples)
+ insertInto.push_back(d);
+ return prioritySamples.size();
+ }
+
+ // Used as belt-and-suspenders check when reading to detect
+ // file corruption
+ bool AreSane(const std::vector<CFeeRate>& vecFee, const CFeeRate& minRelayFee)
+ {
+ BOOST_FOREACH(CFeeRate fee, vecFee)
+ {
+ if (fee < CFeeRate(0))
+ return false;
+ if (fee.GetFeePerK() > minRelayFee.GetFeePerK() * 10000)
+ return false;
+ }
+ return true;
+ }
+ bool AreSane(const std::vector<double> vecPriority)
+ {
+ BOOST_FOREACH(double priority, vecPriority)
+ {
+ if (priority < 0)
+ return false;
+ }
+ return true;
+ }
+
+ void Write(CAutoFile& fileout) const
+ {
+ std::vector<CFeeRate> vecFee = buf2vec(feeSamples);
+ fileout << vecFee;
+ std::vector<double> vecPriority = buf2vec(prioritySamples);
+ fileout << vecPriority;
+ }
+
+ void Read(CAutoFile& filein, const CFeeRate& minRelayFee) {
+ std::vector<CFeeRate> vecFee;
+ filein >> vecFee;
+ if (AreSane(vecFee, minRelayFee))
+ feeSamples.insert(feeSamples.end(), vecFee.begin(), vecFee.end());
+ else
+ throw runtime_error("Corrupt fee value in estimates file.");
+ std::vector<double> vecPriority;
+ filein >> vecPriority;
+ if (AreSane(vecPriority))
+ prioritySamples.insert(prioritySamples.end(), vecPriority.begin(), vecPriority.end());
+ else
+ throw runtime_error("Corrupt priority value in estimates file.");
+ if (feeSamples.size() + prioritySamples.size() > 0)
+ LogPrint("estimatefee", "Read %d fee samples and %d priority samples\n",
+ feeSamples.size(), prioritySamples.size());
+ }
+};
+
+class CMinerPolicyEstimator
+{
+private:
+ // Records observed averages transactions that confirmed within one block, two blocks,
+ // three blocks etc.
+ std::vector<CBlockAverage> history;
+ std::vector<CFeeRate> sortedFeeSamples;
+ std::vector<double> sortedPrioritySamples;
+
+ int nBestSeenHeight;
+
+ // nBlocksAgo is 0 based, i.e. transactions that confirmed in the highest seen block are
+ // nBlocksAgo == 0, transactions in the block before that are nBlocksAgo == 1 etc.
+ void seenTxConfirm(const CFeeRate& feeRate, const CFeeRate& minRelayFee, double dPriority, int nBlocksAgo)
+ {
+ // Last entry records "everything else".
+ int nBlocksTruncated = min(nBlocksAgo, (int) history.size() - 1);
+ assert(nBlocksTruncated >= 0);
+
+ // We need to guess why the transaction was included in a block-- either
+ // because it is high-priority or because it has sufficient fees.
+ bool sufficientFee = (feeRate > minRelayFee);
+ bool sufficientPriority = AllowFree(dPriority);
+ const char* assignedTo = "unassigned";
+ if (sufficientFee && !sufficientPriority)
+ {
+ history[nBlocksTruncated].RecordFee(feeRate);
+ assignedTo = "fee";
+ }
+ else if (sufficientPriority && !sufficientFee)
+ {
+ history[nBlocksTruncated].RecordPriority(dPriority);
+ assignedTo = "priority";
+ }
+ else
+ {
+ // Neither or both fee and priority sufficient to get confirmed:
+ // don't know why they got confirmed.
+ }
+ LogPrint("estimatefee", "Seen TX confirm: %s : %s fee/%g priority, took %d blocks\n",
+ assignedTo, feeRate.ToString(), dPriority, nBlocksAgo);
+ }
+
+public:
+ CMinerPolicyEstimator(int nEntries) : nBestSeenHeight(0)
+ {
+ history.resize(nEntries);
+ }
+
+ void seenBlock(const std::vector<CTxMemPoolEntry>& entries, int nBlockHeight, const CFeeRate minRelayFee)
+ {
+ if (nBlockHeight <= nBestSeenHeight)
+ {
+ // Ignore side chains and re-orgs; assuming they are random
+ // they don't affect the estimate.
+ // And if an attacker can re-org the chain at will, then
+ // you've got much bigger problems than "attacker can influence
+ // transaction fees."
+ return;
+ }
+ nBestSeenHeight = nBlockHeight;
+
+ // Fill up the history buckets based on how long transactions took
+ // to confirm.
+ std::vector<std::vector<const CTxMemPoolEntry*> > entriesByConfirmations;
+ entriesByConfirmations.resize(history.size());
+ BOOST_FOREACH(const CTxMemPoolEntry& entry, entries)
+ {
+ // How many blocks did it take for miners to include this transaction?
+ int delta = nBlockHeight - entry.GetHeight();
+ if (delta <= 0)
+ {
+ // Re-org made us lose height, this should only happen if we happen
+ // to re-org on a difficulty transition point: very rare!
+ continue;
+ }
+ if ((delta-1) >= (int)history.size())
+ delta = history.size(); // Last bucket is catch-all
+ entriesByConfirmations[delta-1].push_back(&entry);
+ }
+ for (size_t i = 0; i < entriesByConfirmations.size(); i++)
+ {
+ std::vector<const CTxMemPoolEntry*> &e = entriesByConfirmations.at(i);
+ // Insert at most 10 random entries per bucket, otherwise a single block
+ // can dominate an estimate:
+ if (e.size() > 10) {
+ std::random_shuffle(e.begin(), e.end());
+ e.resize(10);
+ }
+ BOOST_FOREACH(const CTxMemPoolEntry* entry, e)
+ {
+ // Fees are stored and reported as BTC-per-kb:
+ CFeeRate feeRate(entry->GetFee(), entry->GetTxSize());
+ double dPriority = entry->GetPriority(entry->GetHeight()); // Want priority when it went IN
+ seenTxConfirm(feeRate, minRelayFee, dPriority, i);
+ }
+ }
+ for (size_t i = 0; i < history.size(); i++) {
+ if (history[i].FeeSamples() + history[i].PrioritySamples() > 0)
+ LogPrint("estimatefee", "estimates: for confirming within %d blocks based on %d/%d samples, fee=%s, prio=%g\n",
+ i,
+ history[i].FeeSamples(), history[i].PrioritySamples(),
+ estimateFee(i+1).ToString(), estimatePriority(i+1));
+ }
+ sortedFeeSamples.clear();
+ sortedPrioritySamples.clear();
+ }
+
+ // Can return CFeeRate(0) if we don't have any data for that many blocks back. nBlocksToConfirm is 1 based.
+ CFeeRate estimateFee(int nBlocksToConfirm)
+ {
+ nBlocksToConfirm--;
+
+ if (nBlocksToConfirm < 0 || nBlocksToConfirm >= (int)history.size())
+ return CFeeRate(0);
+
+ if (sortedFeeSamples.size() == 0)
+ {
+ for (size_t i = 0; i < history.size(); i++)
+ history.at(i).GetFeeSamples(sortedFeeSamples);
+ std::sort(sortedFeeSamples.begin(), sortedFeeSamples.end(),
+ std::greater<CFeeRate>());
+ }
+ if (sortedFeeSamples.size() < 11)
+ {
+ // Eleven is Gavin's Favorite Number
+ // ... but we also take a maximum of 10 samples per block so eleven means
+ // we're getting samples from at least two different blocks
+ return CFeeRate(0);
+ }
+
+ int nBucketSize = history.at(nBlocksToConfirm).FeeSamples();
+
+ // Estimates should not increase as number of confirmations goes up,
+ // but the estimates are noisy because confirmations happen discretely
+ // in blocks. To smooth out the estimates, use all samples in the history
+ // and use the nth highest where n is (number of samples in previous bucket +
+ // half the samples in nBlocksToConfirm bucket):
+ size_t nPrevSize = 0;
+ for (int i = 0; i < nBlocksToConfirm; i++)
+ nPrevSize += history.at(i).FeeSamples();
+ size_t index = min(nPrevSize + nBucketSize/2, sortedFeeSamples.size()-1);
+ return sortedFeeSamples[index];
+ }
+ double estimatePriority(int nBlocksToConfirm)
+ {
+ nBlocksToConfirm--;
+
+ if (nBlocksToConfirm < 0 || nBlocksToConfirm >= (int)history.size())
+ return -1;
+
+ if (sortedPrioritySamples.size() == 0)
+ {
+ for (size_t i = 0; i < history.size(); i++)
+ history.at(i).GetPrioritySamples(sortedPrioritySamples);
+ std::sort(sortedPrioritySamples.begin(), sortedPrioritySamples.end(),
+ std::greater<double>());
+ }
+ if (sortedPrioritySamples.size() < 11)
+ return -1.0;
+
+ int nBucketSize = history.at(nBlocksToConfirm).PrioritySamples();
+
+ // Estimates should not increase as number of confirmations needed goes up,
+ // but the estimates are noisy because confirmations happen discretely
+ // in blocks. To smooth out the estimates, use all samples in the history
+ // and use the nth highest where n is (number of samples in previous buckets +
+ // half the samples in nBlocksToConfirm bucket).
+ size_t nPrevSize = 0;
+ for (int i = 0; i < nBlocksToConfirm; i++)
+ nPrevSize += history.at(i).PrioritySamples();
+ size_t index = min(nPrevSize + nBucketSize/2, sortedFeeSamples.size()-1);
+ return sortedPrioritySamples[index];
+ }
+
+ void Write(CAutoFile& fileout) const
+ {
+ fileout << nBestSeenHeight;
+ fileout << history.size();
+ BOOST_FOREACH(const CBlockAverage& entry, history)
+ {
+ entry.Write(fileout);
+ }
+ }
+
+ void Read(CAutoFile& filein, const CFeeRate& minRelayFee)
+ {
+ filein >> nBestSeenHeight;
+ size_t numEntries;
+ filein >> numEntries;
+ history.clear();
+ for (size_t i = 0; i < numEntries; i++)
+ {
+ CBlockAverage entry;
+ entry.Read(filein, minRelayFee);
+ history.push_back(entry);
+ }
+ }
+};
+
+
+CTxMemPool::CTxMemPool(const CFeeRate& _minRelayFee) : minRelayFee(_minRelayFee)
{
// Sanity checks off by default for performance, because otherwise
// accepting transactions becomes O(N^2) where N is the number
// of transactions in the pool
fSanityCheck = false;
+
+ // 25 blocks is a compromise between using a lot of disk/memory and
+ // trying to give accurate estimates to people who might be willing
+ // to wait a day or two to save a fraction of a penny in fees.
+ // Confirmation times for very-low-fee transactions that take more
+ // than an hour or three to confirm are highly variable.
+ minerPolicyEstimator = new CMinerPolicyEstimator(25);
+}
+
+CTxMemPool::~CTxMemPool()
+{
+ delete minerPolicyEstimator;
}
void CTxMemPool::pruneSpent(const uint256 &hashTx, CCoins &coins)
@@ -114,7 +420,6 @@ void CTxMemPool::remove(const CTransaction &tx, std::list<CTransaction>& removed
void CTxMemPool::removeConflicts(const CTransaction &tx, std::list<CTransaction>& removed)
{
// Remove transactions which depend on inputs of tx, recursively
- list<CTransaction> result;
LOCK(cs);
BOOST_FOREACH(const CTxIn &txin, tx.vin) {
std::map<COutPoint, CInPoint>::iterator it = mapNextTx.find(txin.prevout);
@@ -128,6 +433,29 @@ void CTxMemPool::removeConflicts(const CTransaction &tx, std::list<CTransaction>
}
}
+// Called when a block is connected. Removes from mempool and updates the miner fee estimator.
+void CTxMemPool::removeForBlock(const std::vector<CTransaction>& vtx, unsigned int nBlockHeight,
+ std::list<CTransaction>& conflicts)
+{
+ LOCK(cs);
+ std::vector<CTxMemPoolEntry> entries;
+ BOOST_FOREACH(const CTransaction& tx, vtx)
+ {
+ uint256 hash = tx.GetHash();
+ if (mapTx.count(hash))
+ entries.push_back(mapTx[hash]);
+ }
+ minerPolicyEstimator->seenBlock(entries, nBlockHeight, minRelayFee);
+ BOOST_FOREACH(const CTransaction& tx, vtx)
+ {
+ std::list<CTransaction> dummy;
+ remove(tx, dummy, false);
+ removeConflicts(tx, conflicts);
+ ClearPrioritisation(tx.GetHash());
+ }
+}
+
+
void CTxMemPool::clear()
{
LOCK(cs);
@@ -195,6 +523,81 @@ bool CTxMemPool::lookup(uint256 hash, CTransaction& result) const
return true;
}
+CFeeRate CTxMemPool::estimateFee(int nBlocks) const
+{
+ LOCK(cs);
+ return minerPolicyEstimator->estimateFee(nBlocks);
+}
+double CTxMemPool::estimatePriority(int nBlocks) const
+{
+ LOCK(cs);
+ return minerPolicyEstimator->estimatePriority(nBlocks);
+}
+
+bool
+CTxMemPool::WriteFeeEstimates(CAutoFile& fileout) const
+{
+ try {
+ LOCK(cs);
+ fileout << 99900; // version required to read: 0.9.99 or later
+ fileout << CLIENT_VERSION; // version that wrote the file
+ minerPolicyEstimator->Write(fileout);
+ }
+ catch (std::exception &e) {
+ LogPrintf("CTxMemPool::WriteFeeEstimates() : unable to write policy estimator data (non-fatal)");
+ return false;
+ }
+ return true;
+}
+
+bool
+CTxMemPool::ReadFeeEstimates(CAutoFile& filein)
+{
+ try {
+ int nVersionRequired, nVersionThatWrote;
+ filein >> nVersionRequired >> nVersionThatWrote;
+ if (nVersionRequired > CLIENT_VERSION)
+ return error("CTxMemPool::ReadFeeEstimates() : up-version (%d) fee estimate file", nVersionRequired);
+
+ LOCK(cs);
+ minerPolicyEstimator->Read(filein, minRelayFee);
+ }
+ catch (std::exception &e) {
+ LogPrintf("CTxMemPool::ReadFeeEstimates() : unable to read policy estimator data (non-fatal)");
+ return false;
+ }
+ return true;
+}
+
+void CTxMemPool::PrioritiseTransaction(const uint256 hash, const string strHash, double dPriorityDelta, int64_t nFeeDelta)
+{
+ {
+ LOCK(cs);
+ std::pair<double, int64_t> &deltas = mapDeltas[hash];
+ deltas.first += dPriorityDelta;
+ deltas.second += nFeeDelta;
+ }
+ LogPrintf("PrioritiseTransaction: %s priority += %f, fee += %d\n", strHash.c_str(), dPriorityDelta, nFeeDelta);
+}
+
+void CTxMemPool::ApplyDeltas(const uint256 hash, double &dPriorityDelta, int64_t &nFeeDelta)
+{
+ LOCK(cs);
+ std::map<uint256, std::pair<double, int64_t> >::iterator pos = mapDeltas.find(hash);
+ if (pos == mapDeltas.end())
+ return;
+ const std::pair<double, int64_t> &deltas = pos->second;
+ dPriorityDelta += deltas.first;
+ nFeeDelta += deltas.second;
+}
+
+void CTxMemPool::ClearPrioritisation(const uint256 hash)
+{
+ LOCK(cs);
+ mapDeltas.erase(hash);
+}
+
+
CCoinsViewMemPool::CCoinsViewMemPool(CCoinsView &baseIn, CTxMemPool &mempoolIn) : CCoinsViewBacked(baseIn), mempool(mempoolIn) { }
bool CCoinsViewMemPool::GetCoins(const uint256 &txid, CCoins &coins) {
diff --git a/src/txmempool.h b/src/txmempool.h
index 4509e95778..41b2c52f39 100644
--- a/src/txmempool.h
+++ b/src/txmempool.h
@@ -11,6 +11,13 @@
#include "core.h"
#include "sync.h"
+inline bool AllowFree(double dPriority)
+{
+ // Large (in bytes) low-priority (new, small-coin) transactions
+ // need a fee.
+ return dPriority > COIN * 144 / 250;
+}
+
/** Fake height value used in CCoins to signify they are only in the memory pool (since 0.8) */
static const unsigned int MEMPOOL_HEIGHT = 0x7FFFFFFF;
@@ -41,6 +48,8 @@ public:
unsigned int GetHeight() const { return nHeight; }
};
+class CMinerPolicyEstimator;
+
/*
* CTxMemPool stores valid-according-to-the-current-best-chain
* transactions that may be included in the next block.
@@ -56,13 +65,18 @@ class CTxMemPool
private:
bool fSanityCheck; // Normally false, true if -checkmempool or -regtest
unsigned int nTransactionsUpdated;
+ CMinerPolicyEstimator* minerPolicyEstimator;
+
+ CFeeRate minRelayFee; // Passed to constructor to avoid dependency on main
public:
mutable CCriticalSection cs;
std::map<uint256, CTxMemPoolEntry> mapTx;
std::map<COutPoint, CInPoint> mapNextTx;
+ std::map<uint256, std::pair<double, int64_t> > mapDeltas;
- CTxMemPool();
+ CTxMemPool(const CFeeRate& _minRelayFee);
+ ~CTxMemPool();
/*
* If sanity-checking is turned on, check makes sure the pool is
@@ -76,12 +90,19 @@ public:
bool addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry);
void remove(const CTransaction &tx, std::list<CTransaction>& removed, bool fRecursive = false);
void removeConflicts(const CTransaction &tx, std::list<CTransaction>& removed);
+ void removeForBlock(const std::vector<CTransaction>& vtx, unsigned int nBlockHeight,
+ std::list<CTransaction>& conflicts);
void clear();
void queryHashes(std::vector<uint256>& vtxid);
void pruneSpent(const uint256& hash, CCoins &coins);
unsigned int GetTransactionsUpdated() const;
void AddTransactionsUpdated(unsigned int n);
+ /** Affect CreateNewBlock prioritisation of transactions */
+ void PrioritiseTransaction(const uint256 hash, const std::string strHash, double dPriorityDelta, int64_t nFeeDelta);
+ void ApplyDeltas(const uint256 hash, double &dPriorityDelta, int64_t &nFeeDelta);
+ void ClearPrioritisation(const uint256 hash);
+
unsigned long size()
{
LOCK(cs);
@@ -95,6 +116,16 @@ public:
}
bool lookup(uint256 hash, CTransaction& result) const;
+
+ // Estimate fee rate needed to get into the next
+ // nBlocks
+ CFeeRate estimateFee(int nBlocks) const;
+ // Estimate priority needed to get into the next
+ // nBlocks
+ double estimatePriority(int nBlocks) const;
+ // Write/Read estimates to disk
+ bool WriteFeeEstimates(CAutoFile& fileout) const;
+ bool ReadFeeEstimates(CAutoFile& filein);
};
/** CCoinsView that brings transactions from a memorypool into view.
diff --git a/src/ui_interface.h b/src/ui_interface.h
index 7b655ac951..e9fcd91d41 100644
--- a/src/ui_interface.h
+++ b/src/ui_interface.h
@@ -21,7 +21,8 @@ enum ChangeType
{
CT_NEW,
CT_UPDATED,
- CT_DELETED
+ CT_DELETED,
+ CT_GOT_CONFLICT
};
/** Signals for UI communication. */
@@ -94,6 +95,9 @@ public:
/** A wallet has been loaded. */
boost::signals2::signal<void (CWallet* wallet)> LoadWallet;
+
+ /** Show progress e.g. for verifychain */
+ boost::signals2::signal<void (const std::string &title, int nProgress)> ShowProgress;
};
extern CClientUIInterface uiInterface;
diff --git a/src/uint256.cpp b/src/uint256.cpp
new file mode 100644
index 0000000000..3392f1e9bc
--- /dev/null
+++ b/src/uint256.cpp
@@ -0,0 +1,292 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2014 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 "uint256.h"
+#include "util.h"
+
+#include <stdio.h>
+#include <string.h>
+
+template<unsigned int BITS>
+base_uint<BITS>::base_uint(const std::string& str)
+{
+ SetHex(str);
+}
+
+template<unsigned int BITS>
+base_uint<BITS>::base_uint(const std::vector<unsigned char>& vch)
+{
+ if (vch.size() != sizeof(pn))
+ throw uint_error("Converting vector of wrong size to base_uint");
+ memcpy(pn, &vch[0], sizeof(pn));
+}
+
+template<unsigned int BITS>
+base_uint<BITS>& base_uint<BITS>::operator<<=(unsigned int shift)
+{
+ base_uint<BITS> a(*this);
+ for (int i = 0; i < WIDTH; i++)
+ pn[i] = 0;
+ int k = shift / 32;
+ shift = shift % 32;
+ for (int i = 0; i < WIDTH; i++) {
+ if (i+k+1 < WIDTH && shift != 0)
+ pn[i+k+1] |= (a.pn[i] >> (32-shift));
+ if (i+k < WIDTH)
+ pn[i+k] |= (a.pn[i] << shift);
+ }
+ return *this;
+}
+
+template<unsigned int BITS>
+base_uint<BITS>& base_uint<BITS>::operator>>=(unsigned int shift)
+{
+ base_uint<BITS> a(*this);
+ for (int i = 0; i < WIDTH; i++)
+ pn[i] = 0;
+ int k = shift / 32;
+ shift = shift % 32;
+ for (int i = 0; i < WIDTH; i++) {
+ if (i-k-1 >= 0 && shift != 0)
+ pn[i-k-1] |= (a.pn[i] << (32-shift));
+ if (i-k >= 0)
+ pn[i-k] |= (a.pn[i] >> shift);
+ }
+ return *this;
+}
+
+template<unsigned int BITS>
+base_uint<BITS>& base_uint<BITS>::operator*=(uint32_t b32)
+{
+ uint64_t carry = 0;
+ for (int i = 0; i < WIDTH; i++) {
+ uint64_t n = carry + (uint64_t)b32 * pn[i];
+ pn[i] = n & 0xffffffff;
+ carry = n >> 32;
+ }
+ return *this;
+}
+
+template<unsigned int BITS>
+base_uint<BITS>& base_uint<BITS>::operator*=(const base_uint& b)
+{
+ base_uint<BITS> a = *this;
+ *this = 0;
+ for (int j = 0; j < WIDTH; j++) {
+ uint64_t carry = 0;
+ for (int i = 0; i + j < WIDTH; i++) {
+ uint64_t n = carry + pn[i + j] + (uint64_t)a.pn[j] * b.pn[i];
+ pn[i + j] = n & 0xffffffff;
+ carry = n >> 32;
+ }
+ }
+ return *this;
+}
+
+template<unsigned int BITS>
+base_uint<BITS>& base_uint<BITS>::operator/=(const base_uint& b)
+{
+ base_uint<BITS> div = b; // make a copy, so we can shift.
+ base_uint<BITS> num = *this; // make a copy, so we can subtract.
+ *this = 0; // the quotient.
+ int num_bits = num.bits();
+ int div_bits = div.bits();
+ if (div_bits == 0)
+ throw uint_error("Division by zero");
+ if (div_bits > num_bits) // the result is certainly 0.
+ return *this;
+ int shift = num_bits - div_bits;
+ div <<= shift; // shift so that div and nun align.
+ while (shift >= 0) {
+ if (num >= div) {
+ num -= div;
+ pn[shift / 32] |= (1 << (shift & 31)); // set a bit of the result.
+ }
+ div >>= 1; // shift back.
+ shift--;
+ }
+ // num now contains the remainder of the division.
+ return *this;
+}
+
+template<unsigned int BITS>
+int base_uint<BITS>::CompareTo(const base_uint<BITS>& b) const {
+ for (int i = WIDTH-1; i >= 0; i--) {
+ if (pn[i] < b.pn[i])
+ return -1;
+ if (pn[i] > b.pn[i])
+ return 1;
+ }
+ return 0;
+}
+
+template<unsigned int BITS>
+bool base_uint<BITS>::EqualTo(uint64_t b) const {
+ for (int i = WIDTH-1; i >= 2; i--) {
+ if (pn[i])
+ return false;
+ }
+ if (pn[1] != (b >> 32))
+ return false;
+ if (pn[0] != (b & 0xfffffffful))
+ return false;
+ return true;
+}
+
+template<unsigned int BITS>
+double base_uint<BITS>::getdouble() const
+{
+ double ret = 0.0;
+ double fact = 1.0;
+ for (int i = 0; i < WIDTH; i++) {
+ ret += fact * pn[i];
+ fact *= 4294967296.0;
+ }
+ return ret;
+}
+
+template<unsigned int BITS>
+std::string base_uint<BITS>::GetHex() const
+{
+ char psz[sizeof(pn)*2 + 1];
+ for (unsigned int i = 0; i < sizeof(pn); i++)
+ sprintf(psz + i*2, "%02x", ((unsigned char*)pn)[sizeof(pn) - i - 1]);
+ return std::string(psz, psz + sizeof(pn)*2);
+}
+
+template<unsigned int BITS>
+void base_uint<BITS>::SetHex(const char* psz)
+{
+ memset(pn,0,sizeof(pn));
+
+ // skip leading spaces
+ while (isspace(*psz))
+ psz++;
+
+ // skip 0x
+ if (psz[0] == '0' && tolower(psz[1]) == 'x')
+ psz += 2;
+
+ // hex string to uint
+ const char* pbegin = psz;
+ while (::HexDigit(*psz) != -1)
+ psz++;
+ psz--;
+ unsigned char* p1 = (unsigned char*)pn;
+ unsigned char* pend = p1 + WIDTH * 4;
+ while (psz >= pbegin && p1 < pend) {
+ *p1 = ::HexDigit(*psz--);
+ if (psz >= pbegin) {
+ *p1 |= ((unsigned char)::HexDigit(*psz--) << 4);
+ p1++;
+ }
+ }
+}
+
+template<unsigned int BITS>
+void base_uint<BITS>::SetHex(const std::string& str)
+{
+ SetHex(str.c_str());
+}
+
+template<unsigned int BITS>
+std::string base_uint<BITS>::ToString() const
+{
+ return (GetHex());
+}
+
+template<unsigned int BITS>
+unsigned int base_uint<BITS>::bits() const
+{
+ for (int pos = WIDTH-1; pos >= 0; pos--) {
+ if (pn[pos]) {
+ for (int bits = 31; bits > 0; bits--) {
+ if (pn[pos] & 1<<bits)
+ return 32*pos + bits + 1;
+ }
+ return 32*pos + 1;
+ }
+ }
+ return 0;
+}
+
+// Explicit instantiations for base_uint<160>
+template base_uint<160>::base_uint(const std::string&);
+template base_uint<160>::base_uint(const std::vector<unsigned char>&);
+template base_uint<160>& base_uint<160>::operator<<=(unsigned int);
+template base_uint<160>& base_uint<160>::operator>>=(unsigned int);
+template base_uint<160>& base_uint<160>::operator*=(uint32_t b32);
+template base_uint<160>& base_uint<160>::operator*=(const base_uint<160>& b);
+template base_uint<160>& base_uint<160>::operator/=(const base_uint<160>& b);
+template int base_uint<160>::CompareTo(const base_uint<160>&) const;
+template bool base_uint<160>::EqualTo(uint64_t) const;
+template double base_uint<160>::getdouble() const;
+template std::string base_uint<160>::GetHex() const;
+template std::string base_uint<160>::ToString() const;
+template void base_uint<160>::SetHex(const char*);
+template void base_uint<160>::SetHex(const std::string&);
+template unsigned int base_uint<160>::bits() const;
+
+// Explicit instantiations for base_uint<256>
+template base_uint<256>::base_uint(const std::string&);
+template base_uint<256>::base_uint(const std::vector<unsigned char>&);
+template base_uint<256>& base_uint<256>::operator<<=(unsigned int);
+template base_uint<256>& base_uint<256>::operator>>=(unsigned int);
+template base_uint<256>& base_uint<256>::operator*=(uint32_t b32);
+template base_uint<256>& base_uint<256>::operator*=(const base_uint<256>& b);
+template base_uint<256>& base_uint<256>::operator/=(const base_uint<256>& b);
+template int base_uint<256>::CompareTo(const base_uint<256>&) const;
+template bool base_uint<256>::EqualTo(uint64_t) const;
+template double base_uint<256>::getdouble() const;
+template std::string base_uint<256>::GetHex() const;
+template std::string base_uint<256>::ToString() const;
+template void base_uint<256>::SetHex(const char*);
+template void base_uint<256>::SetHex(const std::string&);
+template unsigned int base_uint<256>::bits() const;
+
+// This implementation directly uses shifts instead of going
+// through an intermediate MPI representation.
+uint256& uint256::SetCompact(uint32_t nCompact, bool *pfNegative, bool *pfOverflow)
+{
+ int nSize = nCompact >> 24;
+ uint32_t nWord = nCompact & 0x007fffff;
+ if (nSize <= 3) {
+ nWord >>= 8*(3-nSize);
+ *this = nWord;
+ } else {
+ *this = nWord;
+ *this <<= 8*(nSize-3);
+ }
+ if (pfNegative)
+ *pfNegative = nWord != 0 && (nCompact & 0x00800000) != 0;
+ if (pfOverflow)
+ *pfOverflow = nWord != 0 && ((nSize > 34) ||
+ (nWord > 0xff && nSize > 33) ||
+ (nWord > 0xffff && nSize > 32));
+ return *this;
+}
+
+uint32_t uint256::GetCompact(bool fNegative) const
+{
+ int nSize = (bits() + 7) / 8;
+ uint32_t nCompact = 0;
+ if (nSize <= 3) {
+ nCompact = GetLow64() << 8*(3-nSize);
+ } else {
+ uint256 bn = *this >> 8*(nSize-3);
+ nCompact = bn.GetLow64();
+ }
+ // The 0x00800000 bit denotes the sign.
+ // Thus, if it is already set, divide the mantissa by 256 and increase the exponent.
+ if (nCompact & 0x00800000) {
+ nCompact >>= 8;
+ nSize++;
+ }
+ assert((nCompact & ~0x007fffff) == 0);
+ assert(nSize < 256);
+ nCompact |= nSize << 24;
+ nCompact |= (fNegative && (nCompact & 0x007fffff) ? 0x00800000 : 0);
+ return nCompact;
+}
diff --git a/src/uint256.h b/src/uint256.h
index 1acedd14bf..82db7758c9 100644
--- a/src/uint256.h
+++ b/src/uint256.h
@@ -9,18 +9,9 @@
#include <assert.h>
#include <stdexcept>
#include <stdint.h>
-#include <stdio.h>
#include <string>
-#include <string.h>
#include <vector>
-extern const signed char p_util_hexdigit[256]; // defined in util.cpp
-
-inline signed char HexDigit(char c)
-{
- return p_util_hexdigit[(unsigned char)c];
-}
-
class uint_error : public std::runtime_error {
public:
explicit uint_error(const std::string& str) : std::runtime_error(str) {}
@@ -62,17 +53,8 @@ public:
pn[i] = 0;
}
- explicit base_uint(const std::string& str)
- {
- SetHex(str);
- }
-
- explicit base_uint(const std::vector<unsigned char>& vch)
- {
- if (vch.size() != sizeof(pn))
- throw uint_error("Converting vector of wrong size to base_uint");
- memcpy(pn, &vch[0], sizeof(pn));
- }
+ explicit base_uint(const std::string& str);
+ explicit base_uint(const std::vector<unsigned char>& vch);
bool operator!() const
{
@@ -99,16 +81,7 @@ public:
return ret;
}
- double getdouble() const
- {
- double ret = 0.0;
- double fact = 1.0;
- for (int i = 0; i < WIDTH; i++) {
- ret += fact * pn[i];
- fact *= 4294967296.0;
- }
- return ret;
- }
+ double getdouble() const;
base_uint& operator=(uint64_t b)
{
@@ -154,39 +127,8 @@ public:
return *this;
}
- base_uint& operator<<=(unsigned int shift)
- {
- base_uint a(*this);
- for (int i = 0; i < WIDTH; i++)
- pn[i] = 0;
- int k = shift / 32;
- shift = shift % 32;
- for (int i = 0; i < WIDTH; i++)
- {
- if (i+k+1 < WIDTH && shift != 0)
- pn[i+k+1] |= (a.pn[i] >> (32-shift));
- if (i+k < WIDTH)
- pn[i+k] |= (a.pn[i] << shift);
- }
- return *this;
- }
-
- base_uint& operator>>=(unsigned int shift)
- {
- base_uint a(*this);
- for (int i = 0; i < WIDTH; i++)
- pn[i] = 0;
- int k = shift / 32;
- shift = shift % 32;
- for (int i = 0; i < WIDTH; i++)
- {
- if (i-k-1 >= 0 && shift != 0)
- pn[i-k-1] |= (a.pn[i] << (32-shift));
- if (i-k >= 0)
- pn[i-k] |= (a.pn[i] >> shift);
- }
- return *this;
- }
+ base_uint& operator<<=(unsigned int shift);
+ base_uint& operator>>=(unsigned int shift);
base_uint& operator+=(const base_uint& b)
{
@@ -222,57 +164,9 @@ public:
return *this;
}
- base_uint& operator*=(uint32_t b32)
- {
- uint64_t carry = 0;
- for (int i = 0; i < WIDTH; i++)
- {
- uint64_t n = carry + (uint64_t)b32 * pn[i];
- pn[i] = n & 0xffffffff;
- carry = n >> 32;
- }
- return *this;
- }
-
- base_uint& operator*=(const base_uint& b)
- {
- base_uint a = *this;
- *this = 0;
- for (int j = 0; j < WIDTH; j++) {
- uint64_t carry = 0;
- for (int i = 0; i + j < WIDTH; i++) {
- uint64_t n = carry + pn[i + j] + (uint64_t)a.pn[j] * b.pn[i];
- pn[i + j] = n & 0xffffffff;
- carry = n >> 32;
- }
- }
- return *this;
- }
-
- base_uint& operator/=(const base_uint& b)
- {
- base_uint div = b; // make a copy, so we can shift.
- base_uint num = *this; // make a copy, so we can subtract.
- *this = 0; // the quotient.
- int num_bits = num.bits();
- int div_bits = div.bits();
- if (div_bits == 0)
- throw uint_error("Division by zero");
- if (div_bits > num_bits) // the result is certainly 0.
- return *this;
- int shift = num_bits - div_bits;
- div <<= shift; // shift so that div and nun align.
- while (shift >= 0) {
- if (num >= div) {
- num -= div;
- pn[shift / 32] |= (1 << (shift & 31)); // set a bit of the result.
- }
- div >>= 1; // shift back.
- shift--;
- }
- // num now contains the remainder of the division.
- return *this;
- }
+ base_uint& operator*=(uint32_t b32);
+ base_uint& operator*=(const base_uint& b);
+ base_uint& operator/=(const base_uint& b);
base_uint& operator++()
{
@@ -308,27 +202,8 @@ public:
return ret;
}
- int CompareTo(const base_uint& b) const {
- for (int i = base_uint::WIDTH-1; i >= 0; i--) {
- if (pn[i] < b.pn[i])
- return -1;
- if (pn[i] > b.pn[i])
- return 1;
- }
- return 0;
- }
-
- bool EqualTo(uint64_t b) const {
- for (int i = base_uint::WIDTH-1; i >= 2; i--) {
- if (pn[i])
- return false;
- }
- if (pn[1] != (b >> 32))
- return false;
- if (pn[0] != (b & 0xfffffffful))
- return false;
- return true;
- }
+ int CompareTo(const base_uint& b) const;
+ bool EqualTo(uint64_t b) const;
friend inline const base_uint operator+(const base_uint& a, const base_uint& b) { return base_uint(a) += b; }
friend inline const base_uint operator-(const base_uint& a, const base_uint& b) { return base_uint(a) -= b; }
@@ -349,53 +224,10 @@ public:
friend inline bool operator==(const base_uint& a, uint64_t b) { return a.EqualTo(b); }
friend inline bool operator!=(const base_uint& a, uint64_t b) { return !a.EqualTo(b); }
- std::string GetHex() const
- {
- char psz[sizeof(pn)*2 + 1];
- for (unsigned int i = 0; i < sizeof(pn); i++)
- sprintf(psz + i*2, "%02x", ((unsigned char*)pn)[sizeof(pn) - i - 1]);
- return std::string(psz, psz + sizeof(pn)*2);
- }
-
- void SetHex(const char* psz)
- {
- memset(pn,0,sizeof(pn));
-
- // skip leading spaces
- while (isspace(*psz))
- psz++;
-
- // skip 0x
- if (psz[0] == '0' && tolower(psz[1]) == 'x')
- psz += 2;
-
- // hex string to uint
- const char* pbegin = psz;
- while (::HexDigit(*psz) != -1)
- psz++;
- psz--;
- unsigned char* p1 = (unsigned char*)pn;
- unsigned char* pend = p1 + WIDTH * 4;
- while (psz >= pbegin && p1 < pend)
- {
- *p1 = ::HexDigit(*psz--);
- if (psz >= pbegin)
- {
- *p1 |= ((unsigned char)::HexDigit(*psz--) << 4);
- p1++;
- }
- }
- }
-
- void SetHex(const std::string& str)
- {
- SetHex(str.c_str());
- }
-
- std::string ToString() const
- {
- return (GetHex());
- }
+ std::string GetHex() const;
+ void SetHex(const char* psz);
+ void SetHex(const std::string& str);
+ std::string ToString() const;
unsigned char* begin()
{
@@ -424,19 +256,7 @@ public:
// Returns the position of the highest bit set plus one, or zero if the
// value is zero.
- unsigned int bits() const
- {
- for (int pos = WIDTH-1; pos >= 0; pos--) {
- if (pn[pos]) {
- for (int bits = 31; bits > 0; bits--) {
- if (pn[pos] & 1<<bits)
- return 32*pos + bits + 1;
- }
- return 32*pos + 1;
- }
- }
- return 0;
- }
+ unsigned int bits() const;
uint64_t GetLow64() const
{
@@ -500,56 +320,8 @@ public:
// targets, which are unsigned 256bit quantities. Thus, all the
// complexities of the sign bit and using base 256 are probably an
// implementation accident.
- //
- // This implementation directly uses shifts instead of going
- // through an intermediate MPI representation.
- uint256& SetCompact(uint32_t nCompact, bool *pfNegative = NULL, bool *pfOverflow = NULL)
- {
- int nSize = nCompact >> 24;
- uint32_t nWord = nCompact & 0x007fffff;
- if (nSize <= 3)
- {
- nWord >>= 8*(3-nSize);
- *this = nWord;
- }
- else
- {
- *this = nWord;
- *this <<= 8*(nSize-3);
- }
- if (pfNegative)
- *pfNegative = nWord != 0 && (nCompact & 0x00800000) != 0;
- if (pfOverflow)
- *pfOverflow = nWord != 0 && ((nSize > 34) ||
- (nWord > 0xff && nSize > 33) ||
- (nWord > 0xffff && nSize > 32));
- return *this;
- }
-
- uint32_t GetCompact(bool fNegative = false) const
- {
- int nSize = (bits() + 7) / 8;
- uint32_t nCompact = 0;
- if (nSize <= 3)
- nCompact = GetLow64() << 8*(3-nSize);
- else
- {
- uint256 bn = *this >> 8*(nSize-3);
- nCompact = bn.GetLow64();
- }
- // The 0x00800000 bit denotes the sign.
- // Thus, if it is already set, divide the mantissa by 256 and increase the exponent.
- if (nCompact & 0x00800000)
- {
- nCompact >>= 8;
- nSize++;
- }
- assert((nCompact & ~0x007fffff) == 0);
- assert(nSize < 256);
- nCompact |= nSize << 24;
- nCompact |= (fNegative && (nCompact & 0x007fffff) ? 0x00800000 : 0);
- return nCompact;
- }
+ uint256& SetCompact(uint32_t nCompact, bool *pfNegative = NULL, bool *pfOverflow = NULL);
+ uint32_t GetCompact(bool fNegative = false) const;
};
#endif
diff --git a/src/util.cpp b/src/util.cpp
index aa3adf89ec..91ac8833d5 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -5,15 +5,15 @@
#include "util.h"
-#include "chainparams.h"
-#include "netbase.h"
+#include "chainparamsbase.h"
#include "sync.h"
-#include "ui_interface.h"
#include "uint256.h"
#include "version.h"
#include <stdarg.h>
+#include <boost/date_time/posix_time/posix_time.hpp>
+
#ifndef WIN32
// for posix_fallocate
#ifdef __linux_
@@ -76,11 +76,12 @@
// See also: http://stackoverflow.com/questions/10020179/compilation-fail-in-boost-librairies-program-options
// http://clang.debian.net/status.php?version=3.0&key=CANNOT_FIND_FUNCTION
namespace boost {
+
namespace program_options {
std::string to_internal(const std::string&);
}
-}
+} // namespace boost
using namespace std;
@@ -92,10 +93,9 @@ bool fPrintToDebugLog = true;
bool fDaemon = false;
bool fServer = false;
string strMiscWarning;
-bool fNoListen = false;
bool fLogTimestamps = false;
+bool fLogIPs = false;
volatile bool fReopenDebugLog = false;
-CClientUIInterface uiInterface;
// Init OpenSSL library multithreading support
static CCriticalSection** ppmutexOpenSSL;
@@ -121,15 +121,17 @@ public:
CRYPTO_set_locking_callback(locking_callback);
#ifdef WIN32
- // Seed random number generator with screen scrape and other hardware sources
+ // Seed OpenSSL PRNG with current contents of the screen
RAND_screen();
#endif
- // Seed random number generator with performance counter
+ // Seed OpenSSL PRNG with performance counter
RandAddSeed();
}
~CInit()
{
+ // Securely erase the memory used by the PRNG
+ RAND_cleanup();
// Shutdown OpenSSL library multithreading support
CRYPTO_set_locking_callback(NULL);
for (int i = 0; i < CRYPTO_num_locks(); i++)
@@ -167,16 +169,31 @@ void RandAddSeedPerfmon()
#ifdef WIN32
// Don't need this on Linux, OpenSSL automatically uses /dev/urandom
// Seed with the entire set of perfmon data
- unsigned char pdata[250000];
- memset(pdata, 0, sizeof(pdata));
- unsigned long nSize = sizeof(pdata);
- long ret = RegQueryValueExA(HKEY_PERFORMANCE_DATA, "Global", NULL, NULL, pdata, &nSize);
+ std::vector <unsigned char> vData(250000,0);
+ long ret = 0;
+ unsigned long nSize = 0;
+ const size_t nMaxSize = 10000000; // Bail out at more than 10MB of performance data
+ while (true)
+ {
+ nSize = vData.size();
+ ret = RegQueryValueExA(HKEY_PERFORMANCE_DATA, "Global", NULL, NULL, begin_ptr(vData), &nSize);
+ if (ret != ERROR_MORE_DATA || vData.size() >= nMaxSize)
+ break;
+ vData.resize(std::max((vData.size()*3)/2, nMaxSize)); // Grow size of buffer exponentially
+ }
RegCloseKey(HKEY_PERFORMANCE_DATA);
if (ret == ERROR_SUCCESS)
{
- RAND_add(pdata, nSize, nSize/100.0);
- OPENSSL_cleanse(pdata, nSize);
- LogPrint("rand", "RandAddSeed() %lu bytes\n", nSize);
+ RAND_add(begin_ptr(vData), nSize, nSize/100.0);
+ OPENSSL_cleanse(begin_ptr(vData), nSize);
+ LogPrint("rand", "%s: %lu bytes\n", __func__, nSize);
+ } else {
+ static bool warned = false; // Warn only once
+ if (!warned)
+ {
+ LogPrintf("%s: Warning: RegQueryValueExA(HKEY_PERFORMANCE_DATA) failed with code %i\n", __func__, ret);
+ warned = true;
+ }
}
#endif
}
@@ -404,6 +421,11 @@ const signed char p_util_hexdigit[256] =
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, };
+signed char HexDigit(char c)
+{
+ return p_util_hexdigit[(unsigned char)c];
+}
+
bool IsHex(const string& str)
{
BOOST_FOREACH(char c, str)
@@ -459,6 +481,7 @@ void ParseParameters(int argc, const char* const argv[])
{
mapArgs.clear();
mapMultiArgs.clear();
+
for (int i = 1; i < argc; i++)
{
std::string str(argv[i]);
@@ -474,9 +497,15 @@ void ParseParameters(int argc, const char* const argv[])
if (boost::algorithm::starts_with(str, "/"))
str = "-" + str.substr(1);
#endif
+
if (str[0] != '-')
break;
+ // Interpret --foo as -foo.
+ // If both --foo and -foo are set, the last takes effect.
+ if (str.length() > 1 && str[1] == '-')
+ str = str.substr(1);
+
mapArgs[str] = strValue;
mapMultiArgs[str].push_back(strValue);
}
@@ -484,19 +513,8 @@ void ParseParameters(int argc, const char* const argv[])
// New 0.6 features:
BOOST_FOREACH(const PAIRTYPE(string,string)& entry, mapArgs)
{
- string name = entry.first;
-
- // interpret --foo as -foo (as long as both are not set)
- if (name.find("--") == 0)
- {
- std::string singleDash(name.begin()+1, name.end());
- if (mapArgs.count(singleDash) == 0)
- mapArgs[singleDash] = entry.second;
- name = singleDash;
- }
-
// interpret -nofoo as -foo=0 (and -nofoo=0 as -foo=1) as long as -foo not set
- InterpretNegativeSetting(name, mapArgs);
+ InterpretNegativeSetting(entry.first, mapArgs);
}
}
@@ -885,12 +903,6 @@ static std::string FormatException(std::exception* pex, const char* pszThread)
"UNKNOWN EXCEPTION \n%s in %s \n", pszModule, pszThread);
}
-void LogException(std::exception* pex, const char* pszThread)
-{
- std::string message = FormatException(pex, pszThread);
- LogPrintf("\n%s", message);
-}
-
void PrintExceptionContinue(std::exception* pex, const char* pszThread)
{
std::string message = FormatException(pex, pszThread);
@@ -928,7 +940,7 @@ boost::filesystem::path GetDefaultDataDir()
#endif
}
-static boost::filesystem::path pathCached[CChainParams::MAX_NETWORK_TYPES+1];
+static boost::filesystem::path pathCached[CBaseChainParams::MAX_NETWORK_TYPES+1];
static CCriticalSection csPathCached;
const boost::filesystem::path &GetDataDir(bool fNetSpecific)
@@ -937,8 +949,8 @@ const boost::filesystem::path &GetDataDir(bool fNetSpecific)
LOCK(csPathCached);
- int nNet = CChainParams::MAX_NETWORK_TYPES;
- if (fNetSpecific) nNet = Params().NetworkID();
+ int nNet = CBaseChainParams::MAX_NETWORK_TYPES;
+ if (fNetSpecific) nNet = BaseParams().NetworkID();
fs::path &path = pathCached[nNet];
@@ -957,7 +969,7 @@ const boost::filesystem::path &GetDataDir(bool fNetSpecific)
path = GetDefaultDataDir();
}
if (fNetSpecific)
- path /= Params().DataDir();
+ path /= BaseParams().DataDir();
fs::create_directories(path);
@@ -966,14 +978,16 @@ const boost::filesystem::path &GetDataDir(bool fNetSpecific)
void ClearDatadirCache()
{
- std::fill(&pathCached[0], &pathCached[CChainParams::MAX_NETWORK_TYPES+1],
- boost::filesystem::path());
+ std::fill(&pathCached[0], &pathCached[CBaseChainParams::MAX_NETWORK_TYPES+1],
+ boost::filesystem::path());
}
boost::filesystem::path GetConfigFile()
{
boost::filesystem::path pathConfigFile(GetArg("-conf", "bitcoin.conf"));
- if (!pathConfigFile.is_complete()) pathConfigFile = GetDataDir(false) / pathConfigFile;
+ if (!pathConfigFile.is_complete())
+ pathConfigFile = GetDataDir(false) / pathConfigFile;
+
return pathConfigFile;
}
@@ -1033,9 +1047,9 @@ bool RenameOver(boost::filesystem::path src, boost::filesystem::path dest)
#endif /* WIN32 */
}
-
-// Ignores exceptions thrown by boost's create_directory if the requested directory exists.
-// Specifically handles case where path p exists, but it wasn't possible for the user to write to the parent directory.
+// Ignores exceptions thrown by Boost's create_directory if the requested directory exists.
+// Specifically handles case where path p exists, but it wasn't possible for the user to
+// write to the parent directory.
bool TryCreateDirectory(const boost::filesystem::path& p)
{
try
@@ -1148,15 +1162,15 @@ void ShrinkDebugFile()
if (file && boost::filesystem::file_size(pathLog) > 10 * 1000000)
{
// Restart the file with some of the end
- char pch[200000];
- fseek(file, -sizeof(pch), SEEK_END);
- int nBytes = fread(pch, 1, sizeof(pch), file);
+ std::vector <char> vch(200000,0);
+ fseek(file, -vch.size(), SEEK_END);
+ int nBytes = fread(begin_ptr(vch), 1, vch.size(), file);
fclose(file);
file = fopen(pathLog.string().c_str(), "w");
if (file)
{
- fwrite(pch, 1, nBytes, file);
+ fwrite(begin_ptr(vch), 1, nBytes, file);
fclose(file);
}
}
@@ -1164,13 +1178,6 @@ void ShrinkDebugFile()
fclose(file);
}
-//
-// "Never go to sea with two chronometers; take one or three."
-// Our three time sources are:
-// - System clock
-// - Median of other nodes clocks
-// - The user (asking the user to fix the system clock if the first two disagree)
-//
static int64_t nMockTime = 0; // For unit testing
int64_t GetTime()
@@ -1185,75 +1192,6 @@ void SetMockTime(int64_t nMockTimeIn)
nMockTime = nMockTimeIn;
}
-static CCriticalSection cs_nTimeOffset;
-static int64_t nTimeOffset = 0;
-
-int64_t GetTimeOffset()
-{
- LOCK(cs_nTimeOffset);
- return nTimeOffset;
-}
-
-int64_t GetAdjustedTime()
-{
- return GetTime() + GetTimeOffset();
-}
-
-void AddTimeData(const CNetAddr& ip, int64_t nTime)
-{
- int64_t nOffsetSample = nTime - GetTime();
-
- LOCK(cs_nTimeOffset);
- // Ignore duplicates
- static set<CNetAddr> setKnown;
- if (!setKnown.insert(ip).second)
- return;
-
- // Add data
- static CMedianFilter<int64_t> vTimeOffsets(200,0);
- vTimeOffsets.input(nOffsetSample);
- LogPrintf("Added time data, samples %d, offset %+d (%+d minutes)\n", vTimeOffsets.size(), nOffsetSample, nOffsetSample/60);
- if (vTimeOffsets.size() >= 5 && vTimeOffsets.size() % 2 == 1)
- {
- int64_t nMedian = vTimeOffsets.median();
- std::vector<int64_t> vSorted = vTimeOffsets.sorted();
- // Only let other nodes change our time by so much
- if (abs64(nMedian) < 70 * 60)
- {
- nTimeOffset = nMedian;
- }
- else
- {
- nTimeOffset = 0;
-
- static bool fDone;
- if (!fDone)
- {
- // If nobody has a time different than ours but within 5 minutes of ours, give a warning
- bool fMatch = false;
- BOOST_FOREACH(int64_t nOffset, vSorted)
- if (nOffset != 0 && abs64(nOffset) < 5 * 60)
- fMatch = true;
-
- if (!fMatch)
- {
- fDone = true;
- string strMessage = _("Warning: Please check that your computer's date and time are correct! If your clock is wrong Bitcoin will not work properly.");
- strMiscWarning = strMessage;
- LogPrintf("*** %s\n", strMessage);
- uiInterface.ThreadSafeMessageBox(strMessage, "", CClientUIInterface::MSG_WARNING);
- }
- }
- }
- if (fDebug) {
- BOOST_FOREACH(int64_t n, vSorted)
- LogPrintf("%+d ", n);
- LogPrintf("| ");
- }
- LogPrintf("nTimeOffset = %+d (%+d minutes)\n", nTimeOffset, nTimeOffset/60);
- }
-}
-
uint32_t insecure_rand_Rz = 11;
uint32_t insecure_rand_Rw = 11;
void seed_insecure_rand(bool fDeterministic)
@@ -1386,17 +1324,62 @@ bool ParseInt32(const std::string& str, int32_t *out)
void SetupEnvironment()
{
- #ifndef WIN32
+#ifndef WIN32
try
{
- #if BOOST_FILESYSTEM_VERSION == 3
+#if BOOST_FILESYSTEM_VERSION == 3
boost::filesystem::path::codecvt(); // Raises runtime error if current locale is invalid
- #else // boost filesystem v2
+#else // boost filesystem v2
std::locale(); // Raises runtime error if current locale is invalid
- #endif
+#endif
} catch(std::runtime_error &e)
{
setenv("LC_ALL", "C", 1); // Force C locale
}
- #endif
+#endif
+}
+
+std::string DateTimeStrFormat(const char* pszFormat, int64_t nTime)
+{
+ // std::locale takes ownership of the pointer
+ std::locale loc(std::locale::classic(), new boost::posix_time::time_facet(pszFormat));
+ std::stringstream ss;
+ ss.imbue(loc);
+ ss << boost::posix_time::from_time_t(nTime);
+ return ss.str();
+}
+
+std::string FormatParagraph(const std::string in, size_t width, size_t indent)
+{
+ std::stringstream out;
+ size_t col = 0;
+ size_t ptr = 0;
+ while(ptr < in.size())
+ {
+ // Find beginning of next word
+ ptr = in.find_first_not_of(' ', ptr);
+ if (ptr == std::string::npos)
+ break;
+ // Find end of next word
+ size_t endword = in.find_first_of(' ', ptr);
+ if (endword == std::string::npos)
+ endword = in.size();
+ // Add newline and indentation if this wraps over the allowed width
+ if (col > 0)
+ {
+ if ((col + endword - ptr) > width)
+ {
+ out << '\n';
+ for(size_t i=0; i<indent; ++i)
+ out << ' ';
+ col = 0;
+ } else
+ out << ' ';
+ }
+ // Append word
+ out << in.substr(ptr, endword - ptr);
+ col += endword - ptr;
+ ptr = endword;
+ }
+ return out.str();
}
diff --git a/src/util.h b/src/util.h
index 97185073e0..60db71bfd0 100644
--- a/src/util.h
+++ b/src/util.h
@@ -7,7 +7,7 @@
#define BITCOIN_UTIL_H
#if defined(HAVE_CONFIG_H)
-#include "bitcoin-config.h"
+#include "config/bitcoin-config.h"
#endif
#include "compat.h"
@@ -32,7 +32,6 @@
#include <boost/filesystem/path.hpp>
#include <boost/thread.hpp>
-class CNetAddr;
class uint256;
static const int64_t COIN = 100000000;
@@ -100,8 +99,8 @@ extern bool fPrintToConsole;
extern bool fPrintToDebugLog;
extern bool fServer;
extern std::string strMiscWarning;
-extern bool fNoListen;
extern bool fLogTimestamps;
+extern bool fLogIPs;
extern volatile bool fReopenDebugLog;
void RandAddSeed();
@@ -151,8 +150,6 @@ static inline bool error(const char* format)
return false;
}
-
-void LogException(std::exception* pex, const char* pszThread);
void PrintExceptionContinue(std::exception* pex, const char* pszThread);
std::string FormatMoney(int64_t n, bool fPlus=false);
bool ParseMoney(const std::string& str, int64_t& nRet);
@@ -160,6 +157,7 @@ bool ParseMoney(const char* pszIn, int64_t& nRet);
std::string SanitizeString(const std::string& str);
std::vector<unsigned char> ParseHex(const char* psz);
std::vector<unsigned char> ParseHex(const std::string& str);
+signed char HexDigit(char c);
bool IsHex(const std::string& str);
std::vector<unsigned char> DecodeBase64(const char* p, bool* pfInvalid = NULL);
std::string DecodeBase64(const std::string& str);
@@ -194,11 +192,8 @@ uint64_t GetRand(uint64_t nMax);
uint256 GetRandHash();
int64_t GetTime();
void SetMockTime(int64_t nMockTimeIn);
-int64_t GetAdjustedTime();
-int64_t GetTimeOffset();
std::string FormatFullVersion();
std::string FormatSubVersion(const std::string& name, int nClientVersion, const std::vector<std::string>& comments);
-void AddTimeData(const CNetAddr& ip, int64_t nTime);
void runCommand(std::string strCommand);
@@ -289,16 +284,10 @@ inline std::string HexStr(const T& vch, bool fSpaces=false)
return HexStr(vch.begin(), vch.end(), fSpaces);
}
-template<typename T>
-void PrintHex(const T pbegin, const T pend, const char* pszFormat="%s", bool fSpaces=true)
-{
- LogPrintf(pszFormat, HexStr(pbegin, pend, fSpaces).c_str());
-}
-
-inline void PrintHex(const std::vector<unsigned char>& vch, const char* pszFormat="%s", bool fSpaces=true)
-{
- LogPrintf(pszFormat, HexStr(vch, fSpaces).c_str());
-}
+/** Format a paragraph of text to a fixed width, adding spaces for
+ * indentation to any added line.
+ */
+std::string FormatParagraph(const std::string in, size_t width=79, size_t indent=0);
inline int64_t GetPerformanceCounter()
{
@@ -325,14 +314,7 @@ inline int64_t GetTimeMicros()
boost::posix_time::ptime(boost::gregorian::date(1970,1,1))).total_microseconds();
}
-inline std::string DateTimeStrFormat(const char* pszFormat, int64_t nTime)
-{
- time_t n = nTime;
- struct tm* ptmTime = gmtime(&n);
- char pszTime[200];
- strftime(pszTime, sizeof(pszTime), pszFormat, ptmTime);
- return pszTime;
-}
+std::string DateTimeStrFormat(const char* pszFormat, int64_t nTime);
inline bool IsSwitchChar(char c)
{
diff --git a/src/version.cpp b/src/version.cpp
index 51e34aa9c9..d86caa3ac2 100644
--- a/src/version.cpp
+++ b/src/version.cpp
@@ -12,7 +12,7 @@
const std::string CLIENT_NAME("Satoshi");
// Client version number
-#define CLIENT_VERSION_SUFFIX "-beta"
+#define CLIENT_VERSION_SUFFIX ""
// The following part of the code determines the CLIENT_BUILD variable.
diff --git a/src/wallet.cpp b/src/wallet.cpp
index fa7aecddb6..a54494f935 100644
--- a/src/wallet.cpp
+++ b/src/wallet.cpp
@@ -9,6 +9,7 @@
#include "checkpoints.h"
#include "coincontrol.h"
#include "net.h"
+#include "timedata.h"
#include <boost/algorithm/string/replace.hpp>
#include <openssl/rand.h>
@@ -16,9 +17,13 @@
using namespace std;
// Settings
-int64_t nTransactionFee = DEFAULT_TRANSACTION_FEE;
+CFeeRate payTxFee(DEFAULT_TRANSACTION_FEE);
+unsigned int nTxConfirmTarget = 1;
bool bSpendZeroConfChange = true;
+/** Fees smaller than this (in satoshi) are considered zero fee (for transaction creation) */
+CFeeRate CWallet::minTxFee = CFeeRate(10000); // Override with -mintxfee
+
//////////////////////////////////////////////////////////////////////////////
//
// mapWallet
@@ -128,6 +133,37 @@ bool CWallet::AddCScript(const CScript& redeemScript)
return CWalletDB(strWalletFile).WriteCScript(Hash160(redeemScript), redeemScript);
}
+bool CWallet::LoadCScript(const CScript& redeemScript)
+{
+ /* A sanity check was added in pull #3843 to avoid adding redeemScripts
+ * that never can be redeemed. However, old wallets may still contain
+ * these. Do not add them to the wallet and warn. */
+ if (redeemScript.size() > MAX_SCRIPT_ELEMENT_SIZE)
+ {
+ std::string strAddr = CBitcoinAddress(redeemScript.GetID()).ToString();
+ LogPrintf("%s: Warning: This wallet contains a redeemScript of size %i which exceeds maximum size %i thus can never be redeemed. Do not use address %s.\n",
+ __func__, redeemScript.size(), MAX_SCRIPT_ELEMENT_SIZE, strAddr);
+ return true;
+ }
+
+ return CCryptoKeyStore::AddCScript(redeemScript);
+}
+
+bool CWallet::AddWatchOnly(const CScript &dest)
+{
+ if (!CCryptoKeyStore::AddWatchOnly(dest))
+ return false;
+ nTimeFirstKey = 1; // No birthday information for watch-only keys.
+ if (!fFileBacked)
+ return true;
+ return CWalletDB(strWalletFile).WriteWatchOnly(dest);
+}
+
+bool CWallet::LoadWatchOnly(const CScript &dest)
+{
+ return CCryptoKeyStore::AddWatchOnly(dest);
+}
+
bool CWallet::Unlock(const SecureString& strWalletPassphrase)
{
CCrypter crypter;
@@ -239,7 +275,7 @@ bool CWallet::SetMaxVersion(int nVersion)
return true;
}
-set<uint256> CWallet::GetConflicts(const uint256& txid) const
+set<uint256> CWallet::GetConflicts(const uint256& txid, bool includeEquivalent) const
{
set<uint256> result;
AssertLockHeld(cs_wallet);
@@ -257,7 +293,8 @@ set<uint256> CWallet::GetConflicts(const uint256& txid) const
continue; // No conflict if zero or one spends
range = mapTxSpends.equal_range(txin.prevout);
for (TxSpends::const_iterator it = range.first; it != range.second; ++it)
- result.insert(it->second);
+ if (includeEquivalent || !wtx.IsEquivalentTo(mapWallet.at(it->second)))
+ result.insert(it->second);
}
return result;
}
@@ -286,6 +323,7 @@ void CWallet::SyncMetaData(pair<TxSpends::iterator, TxSpends::iterator> range)
const uint256& hash = it->second;
CWalletTx* copyTo = &mapWallet[hash];
if (copyFrom == copyTo) continue;
+ if (!copyFrom->IsEquivalentTo(*copyTo)) continue;
copyTo->mapValue = copyFrom->mapValue;
copyTo->vOrderForm = copyFrom->vOrderForm;
// fTimeReceivedIsTxTime not copied on purpose
@@ -492,8 +530,8 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet)
{
if (mapBlockIndex.count(wtxIn.hashBlock))
{
- unsigned int latestNow = wtx.nTimeReceived;
- unsigned int latestEntry = 0;
+ int64_t latestNow = wtx.nTimeReceived;
+ int64_t latestEntry = 0;
{
// Tolerate times up to the last timestamp in the wallet not more than 5 minutes into the future
int64_t latestTolerated = latestNow + 300;
@@ -524,7 +562,7 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet)
}
}
- unsigned int& blocktime = mapBlockIndex[wtxIn.hashBlock]->nTime;
+ int64_t blocktime = mapBlockIndex[wtxIn.hashBlock]->GetBlockTime();
wtx.nTimeSmart = std::max(latestEntry, std::min(blocktime, latestNow));
}
else
@@ -571,6 +609,28 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet)
// Notify UI of new or updated transaction
NotifyTransactionChanged(this, hash, fInsertedNew ? CT_NEW : CT_UPDATED);
+ // Notifications for existing transactions that now have conflicts with this one
+ if (fInsertedNew)
+ {
+ BOOST_FOREACH(const uint256& conflictHash, wtxIn.GetConflicts(false))
+ {
+ CWalletTx& txConflict = mapWallet[conflictHash];
+ NotifyTransactionChanged(this, conflictHash, CT_UPDATED); //Updates UI table
+ if (IsFromMe(txConflict) || IsMine(txConflict))
+ {
+ NotifyTransactionChanged(this, conflictHash, CT_GOT_CONFLICT); //Throws dialog
+ // external respend notify
+ std::string strCmd = GetArg("-respendnotify", "");
+ if (!strCmd.empty())
+ {
+ boost::replace_all(strCmd, "%s", wtxIn.GetHash().GetHex());
+ boost::replace_all(strCmd, "%t", conflictHash.GetHex());
+ boost::thread t(runCommand, strCmd); // thread runs free
+ }
+ }
+ }
+ }
+
// notify an external script when a wallet transaction comes in or is updated
std::string strCmd = GetArg("-walletnotify", "");
@@ -587,13 +647,18 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet)
// 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 CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate)
{
{
AssertLockHeld(cs_wallet);
- bool fExisted = mapWallet.count(hash);
+ bool fExisted = mapWallet.count(tx.GetHash());
if (fExisted && !fUpdate) return false;
- if (fExisted || IsMine(tx) || IsFromMe(tx))
+
+ bool fIsConflicting = IsConflicting(tx);
+ if (fIsConflicting)
+ nConflictsReceived++;
+
+ if (fExisted || IsMine(tx) || IsFromMe(tx) || fIsConflicting)
{
CWalletTx wtx(this,tx);
// Get merkle branch if transaction was found in a block
@@ -605,10 +670,10 @@ bool CWallet::AddToWalletIfInvolvingMe(const uint256 &hash, const CTransaction&
return false;
}
-void CWallet::SyncTransaction(const uint256 &hash, const CTransaction& tx, const CBlock* pblock)
+void CWallet::SyncTransaction(const CTransaction& tx, const CBlock* pblock)
{
LOCK2(cs_main, cs_wallet);
- if (!AddToWalletIfInvolvingMe(hash, tx, pblock, true))
+ if (!AddToWalletIfInvolvingMe(tx, pblock, true))
return; // Not one of ours
// If a transaction changes 'conflicted' state, that changes the balance
@@ -634,7 +699,7 @@ void CWallet::EraseFromWallet(const uint256 &hash)
}
-bool CWallet::IsMine(const CTxIn &txin) const
+isminetype CWallet::IsMine(const CTxIn &txin) const
{
{
LOCK(cs_wallet);
@@ -643,14 +708,13 @@ bool CWallet::IsMine(const CTxIn &txin) const
{
const CWalletTx& prev = (*mi).second;
if (txin.prevout.n < prev.vout.size())
- if (IsMine(prev.vout[txin.prevout.n]))
- return true;
+ return IsMine(prev.vout[txin.prevout.n]);
}
}
- return false;
+ return ISMINE_NO;
}
-int64_t CWallet::GetDebit(const CTxIn &txin) const
+int64_t CWallet::GetDebit(const CTxIn &txin, const isminefilter& filter) const
{
{
LOCK(cs_wallet);
@@ -659,7 +723,7 @@ int64_t CWallet::GetDebit(const CTxIn &txin) const
{
const CWalletTx& prev = (*mi).second;
if (txin.prevout.n < prev.vout.size())
- if (IsMine(prev.vout[txin.prevout.n]))
+ if (IsMine(prev.vout[txin.prevout.n]) & filter)
return prev.vout[txin.prevout.n].nValue;
}
}
@@ -668,17 +732,19 @@ int64_t CWallet::GetDebit(const CTxIn &txin) const
bool CWallet::IsChange(const CTxOut& txout) const
{
- CTxDestination address;
-
// TODO: fix handling of 'change' outputs. The assumption is that any
- // payment to a TX_PUBKEYHASH that is mine but isn't in the address book
+ // payment to a script that is ours, but is not in the address book
// is change. That assumption is likely to break when we implement multisignature
// wallets that return change back into a multi-signature-protected address;
// a better way of identifying which outputs are 'the send' and which are
// 'the change' will need to be implemented (maybe extend CWalletTx to remember
// which output, if any, was change).
- if (ExtractDestination(txout.scriptPubKey, address) && ::IsMine(*this, address))
+ if (::IsMine(*this, txout.scriptPubKey))
{
+ CTxDestination address;
+ if (!ExtractDestination(txout.scriptPubKey, address))
+ return true;
+
LOCK(cs_wallet);
if (!mapAddressBook.count(address))
return true;
@@ -732,7 +798,7 @@ int CWalletTx::GetRequestCount() const
}
void CWalletTx::GetAmounts(list<pair<CTxDestination, int64_t> >& listReceived,
- list<pair<CTxDestination, int64_t> >& listSent, int64_t& nFee, string& strSentAccount) const
+ list<pair<CTxDestination, int64_t> >& listSent, int64_t& nFee, string& strSentAccount, const isminefilter& filter) const
{
nFee = 0;
listReceived.clear();
@@ -740,7 +806,7 @@ void CWalletTx::GetAmounts(list<pair<CTxDestination, int64_t> >& listReceived,
strSentAccount = strFromAccount;
// Compute fee:
- int64_t nDebit = GetDebit();
+ int64_t nDebit = GetDebit(filter);
if (nDebit > 0) // debit>0 means we signed/sent this transaction
{
int64_t nValueOut = GetValueOut();
@@ -750,7 +816,8 @@ void CWalletTx::GetAmounts(list<pair<CTxDestination, int64_t> >& listReceived,
// Sent/received.
BOOST_FOREACH(const CTxOut& txout, vout)
{
- bool fIsMine;
+ isminetype fIsMine = pwallet->IsMine(txout);
+
// Only need to handle txouts if AT LEAST one of these is true:
// 1) they debit from us (sent)
// 2) the output is to us (received)
@@ -759,9 +826,8 @@ void CWalletTx::GetAmounts(list<pair<CTxDestination, int64_t> >& listReceived,
// Don't report 'change' txouts
if (pwallet->IsChange(txout))
continue;
- fIsMine = pwallet->IsMine(txout);
}
- else if (!(fIsMine = pwallet->IsMine(txout)))
+ else if (!(fIsMine & filter))
continue;
// In either case, we need to get the destination address
@@ -785,7 +851,7 @@ void CWalletTx::GetAmounts(list<pair<CTxDestination, int64_t> >& listReceived,
}
void CWalletTx::GetAccountAmounts(const string& strAccount, int64_t& nReceived,
- int64_t& nSent, int64_t& nFee) const
+ int64_t& nSent, int64_t& nFee, const isminefilter& filter) const
{
nReceived = nSent = nFee = 0;
@@ -793,7 +859,7 @@ void CWalletTx::GetAccountAmounts(const string& strAccount, int64_t& nReceived,
string strSentAccount;
list<pair<CTxDestination, int64_t> > listReceived;
list<pair<CTxDestination, int64_t> > listSent;
- GetAmounts(listReceived, listSent, allFee, strSentAccount);
+ GetAmounts(listReceived, listSent, allFee, strSentAccount, filter);
if (strAccount == strSentAccount)
{
@@ -839,7 +905,7 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate)
// no need to read and scan block, if block was created before
// our wallet birthday (as adjusted for block time variability)
- while (pindex && nTimeFirstKey && (pindex->nTime < (nTimeFirstKey - 7200)))
+ while (pindex && nTimeFirstKey && (pindex->GetBlockTime() < (nTimeFirstKey - 7200)))
pindex = chainActive.Next(pindex);
ShowProgress(_("Rescanning..."), 0); // show rescan progress in GUI as dialog or on splashscreen, if -rescan on startup
@@ -854,7 +920,7 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate)
ReadBlockFromDisk(block, pindex);
BOOST_FOREACH(CTransaction& tx, block.vtx)
{
- if (AddToWalletIfInvolvingMe(tx.GetHash(), tx, &block, fUpdate))
+ if (AddToWalletIfInvolvingMe(tx, &block, fUpdate))
ret++;
}
pindex = chainActive.Next(pindex);
@@ -879,7 +945,7 @@ void CWallet::ReacceptWalletTransactions()
int nDepth = wtx.GetDepthInMainChain();
- if (!wtx.IsCoinBase() && nDepth < 0)
+ if (!wtx.IsCoinBase() && nDepth < 0 && (IsMine(wtx) || IsFromMe(wtx)))
{
// Try to add to memory pool
LOCK(mempool.cs);
@@ -893,20 +959,19 @@ void CWalletTx::RelayWalletTransaction()
if (!IsCoinBase())
{
if (GetDepthInMainChain() == 0) {
- uint256 hash = GetHash();
- LogPrintf("Relaying wtx %s\n", hash.ToString());
- RelayTransaction((CTransaction)*this, hash);
+ LogPrintf("Relaying wtx %s\n", GetHash().ToString());
+ RelayTransaction((CTransaction)*this);
}
}
}
-set<uint256> CWalletTx::GetConflicts() const
+set<uint256> CWalletTx::GetConflicts(bool includeEquivalent) const
{
set<uint256> result;
if (pwallet != NULL)
{
uint256 myHash = GetHash();
- result = pwallet->GetConflicts(myHash);
+ result = pwallet->GetConflicts(myHash, includeEquivalent);
result.erase(myHash);
}
return result;
@@ -1006,13 +1071,58 @@ int64_t CWallet::GetImmatureBalance() const
return nTotal;
}
-// populate vCoins with vector of spendable COutputs
+int64_t CWallet::GetWatchOnlyBalance() const
+{
+ int64_t nTotal = 0;
+ {
+ LOCK(cs_wallet);
+ for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
+ {
+ const CWalletTx* pcoin = &(*it).second;
+ if (pcoin->IsTrusted())
+ nTotal += pcoin->GetAvailableWatchOnlyCredit();
+ }
+ }
+
+ return nTotal;
+}
+
+int64_t CWallet::GetUnconfirmedWatchOnlyBalance() const
+{
+ int64_t nTotal = 0;
+ {
+ LOCK(cs_wallet);
+ for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
+ {
+ const CWalletTx* pcoin = &(*it).second;
+ if (!IsFinalTx(*pcoin) || (!pcoin->IsTrusted() && pcoin->GetDepthInMainChain() == 0))
+ nTotal += pcoin->GetAvailableWatchOnlyCredit();
+ }
+ }
+ return nTotal;
+}
+
+int64_t CWallet::GetImmatureWatchOnlyBalance() const
+{
+ int64_t nTotal = 0;
+ {
+ LOCK(cs_wallet);
+ for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
+ {
+ const CWalletTx* pcoin = &(*it).second;
+ nTotal += pcoin->GetImmatureWatchOnlyCredit();
+ }
+ }
+ return nTotal;
+}
+
+// populate vCoins with vector of available COutputs.
void CWallet::AvailableCoins(vector<COutput>& vCoins, bool fOnlyConfirmed, const CCoinControl *coinControl) const
{
vCoins.clear();
{
- LOCK(cs_wallet);
+ LOCK2(cs_main, cs_wallet);
for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
{
const uint256& wtxid = it->first;
@@ -1032,10 +1142,11 @@ void CWallet::AvailableCoins(vector<COutput>& vCoins, bool fOnlyConfirmed, const
continue;
for (unsigned int i = 0; i < pcoin->vout.size(); i++) {
- if (!(IsSpent(wtxid, i)) && IsMine(pcoin->vout[i]) &&
+ isminetype mine = IsMine(pcoin->vout[i]);
+ if (!(IsSpent(wtxid, i)) && mine != ISMINE_NO &&
!IsLockedCoin((*it).first, i) && pcoin->vout[i].nValue > 0 &&
(!coinControl || !coinControl->HasSelected() || coinControl->IsSelected((*it).first, i)))
- vCoins.push_back(COutput(pcoin, i, nDepth));
+ vCoins.push_back(COutput(pcoin, i, nDepth, mine & ISMINE_SPENDABLE));
}
}
}
@@ -1102,11 +1213,14 @@ bool CWallet::SelectCoinsMinConf(int64_t nTargetValue, int nConfMine, int nConfT
random_shuffle(vCoins.begin(), vCoins.end(), GetRandInt);
- BOOST_FOREACH(COutput output, vCoins)
+ BOOST_FOREACH(const COutput &output, vCoins)
{
+ if (!output.fSpendable)
+ continue;
+
const CWalletTx *pcoin = output.tx;
- if (output.nDepth < (pcoin->IsFromMe() ? nConfMine : nConfTheirs))
+ if (output.nDepth < (pcoin->IsFromMe(ISMINE_ALL) ? nConfMine : nConfTheirs))
continue;
int i = output.i;
@@ -1195,6 +1309,8 @@ bool CWallet::SelectCoins(int64_t nTargetValue, set<pair<const CWalletTx*,unsign
{
BOOST_FOREACH(const COutput& out, vCoins)
{
+ if(!out.fSpendable)
+ continue;
nValueRet += out.tx->vout[out.i].nValue;
setCoinsRet.insert(make_pair(out.tx, out.i));
}
@@ -1228,16 +1344,18 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64_t> >& vecSend,
return false;
}
+ wtxNew.fTimeReceivedIsTxTime = true;
wtxNew.BindWallet(this);
+ CMutableTransaction txNew;
{
LOCK2(cs_main, cs_wallet);
{
- nFeeRet = nTransactionFee;
+ nFeeRet = payTxFee.GetFeePerK();
while (true)
{
- wtxNew.vin.clear();
- wtxNew.vout.clear();
+ txNew.vin.clear();
+ txNew.vout.clear();
wtxNew.fFromMe = true;
int64_t nTotalValue = nValue + nFeeRet;
@@ -1246,12 +1364,12 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64_t> >& vecSend,
BOOST_FOREACH (const PAIRTYPE(CScript, int64_t)& s, vecSend)
{
CTxOut txout(s.second, s.first);
- if (txout.IsDust(CTransaction::nMinRelayTxFee))
+ if (txout.IsDust(::minRelayTxFee))
{
strFailReason = _("Transaction amount too small");
return false;
}
- wtxNew.vout.push_back(txout);
+ txNew.vout.push_back(txout);
}
// Choose coins to use
@@ -1272,16 +1390,6 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64_t> >& vecSend,
}
int64_t nChange = nValueIn - nValue - nFeeRet;
- // The following if statement should be removed once enough miners
- // have upgraded to the 0.9 GetMinFee() rules. Until then, this avoids
- // creating free transactions that have change outputs less than
- // CENT bitcoins.
- if (nFeeRet < CTransaction::nMinTxFee && nChange > 0 && nChange < CENT)
- {
- int64_t nMoveToFee = min(nChange, CTransaction::nMinTxFee - nFeeRet);
- nChange -= nMoveToFee;
- nFeeRet += nMoveToFee;
- }
if (nChange > 0)
{
@@ -1317,7 +1425,7 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64_t> >& vecSend,
// Never create dust outputs; if we would, just
// add the dust to the fee.
- if (newTxOut.IsDust(CTransaction::nMinRelayTxFee))
+ if (newTxOut.IsDust(::minRelayTxFee))
{
nFeeRet += nChange;
reservekey.ReturnKey();
@@ -1325,8 +1433,8 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64_t> >& vecSend,
else
{
// Insert change txn at random position:
- vector<CTxOut>::iterator position = wtxNew.vout.begin()+GetRandInt(wtxNew.vout.size()+1);
- wtxNew.vout.insert(position, newTxOut);
+ vector<CTxOut>::iterator position = txNew.vout.begin()+GetRandInt(txNew.vout.size()+1);
+ txNew.vout.insert(position, newTxOut);
}
}
else
@@ -1334,17 +1442,20 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64_t> >& vecSend,
// Fill vin
BOOST_FOREACH(const PAIRTYPE(const CWalletTx*,unsigned int)& coin, setCoins)
- wtxNew.vin.push_back(CTxIn(coin.first->GetHash(),coin.second));
+ txNew.vin.push_back(CTxIn(coin.first->GetHash(),coin.second));
// Sign
int nIn = 0;
BOOST_FOREACH(const PAIRTYPE(const CWalletTx*,unsigned int)& coin, setCoins)
- if (!SignSignature(*this, *coin.first, wtxNew, nIn++))
+ if (!SignSignature(*this, *coin.first, txNew, nIn++))
{
strFailReason = _("Signing transaction failed");
return false;
}
+ // Embed the constructed transaction data in wtxNew.
+ *static_cast<CTransaction*>(&wtxNew) = CTransaction(txNew);
+
// Limit size
unsigned int nBytes = ::GetSerializeSize(*(CTransaction*)&wtxNew, SER_NETWORK, PROTOCOL_VERSION);
if (nBytes >= MAX_STANDARD_TX_SIZE)
@@ -1354,19 +1465,31 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64_t> >& vecSend,
}
dPriority = wtxNew.ComputePriority(dPriority, nBytes);
- // Check that enough fee is included
- int64_t nPayFee = nTransactionFee * (1 + (int64_t)nBytes / 1000);
- bool fAllowFree = AllowFree(dPriority);
- int64_t nMinFee = GetMinFee(wtxNew, nBytes, fAllowFree, GMF_SEND);
- if (nFeeRet < max(nPayFee, nMinFee))
+ int64_t nFeeNeeded = GetMinimumFee(nBytes, nTxConfirmTarget, mempool);
+
+ if (nFeeRet >= nFeeNeeded)
+ break; // Done, enough fee included.
+
+ // Too big to send for free? Include more fee and try again:
+ if (nBytes > MAX_FREE_TRANSACTION_CREATE_SIZE)
{
- nFeeRet = max(nPayFee, nMinFee);
+ nFeeRet = nFeeNeeded;
continue;
}
- wtxNew.fTimeReceivedIsTxTime = true;
+ // Not enough fee: enough priority?
+ double dPriorityNeeded = mempool.estimatePriority(nTxConfirmTarget);
+ // Not enough mempool history to estimate: use hard-coded AllowFree.
+ if (dPriorityNeeded <= 0 && AllowFree(dPriority))
+ break;
+
+ // Small enough, and priority high enough, to send for free
+ if (dPriorityNeeded > 0 && dPriority >= dPriorityNeeded)
+ break;
- break;
+ // Include more fee and try again.
+ nFeeRet = nFeeNeeded;
+ continue;
}
}
}
@@ -1431,18 +1554,29 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey)
-string CWallet::SendMoney(CScript scriptPubKey, int64_t nValue, CWalletTx& wtxNew)
+string CWallet::SendMoney(const CTxDestination &address, int64_t nValue, CWalletTx& wtxNew)
{
- CReserveKey reservekey(this);
- int64_t nFeeRequired;
+ // Check amount
+ if (nValue <= 0)
+ return _("Invalid amount");
+ if (nValue > GetBalance())
+ return _("Insufficient funds");
+ string strError;
if (IsLocked())
{
- string strError = _("Error: Wallet locked, unable to create transaction!");
+ strError = _("Error: Wallet locked, unable to create transaction!");
LogPrintf("SendMoney() : %s", strError);
return strError;
}
- string strError;
+
+ // Parse Bitcoin address
+ CScript scriptPubKey;
+ scriptPubKey.SetDestination(address);
+
+ // Create and send the transaction
+ CReserveKey reservekey(this);
+ int64_t nFeeRequired;
if (!CreateTransaction(scriptPubKey, nValue, wtxNew, reservekey, nFeeRequired, strError))
{
if (nValue + nFeeRequired > GetBalance())
@@ -1450,7 +1584,6 @@ string CWallet::SendMoney(CScript scriptPubKey, int64_t nValue, CWalletTx& wtxNe
LogPrintf("SendMoney() : %s\n", strError);
return strError;
}
-
if (!CommitTransaction(wtxNew, reservekey))
return _("Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here.");
@@ -1459,19 +1592,18 @@ string CWallet::SendMoney(CScript scriptPubKey, int64_t nValue, CWalletTx& wtxNe
-string CWallet::SendMoneyToDestination(const CTxDestination& address, int64_t nValue, CWalletTx& wtxNew)
+int64_t CWallet::GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarget, const CTxMemPool& pool)
{
- // Check amount
- if (nValue <= 0)
- return _("Invalid amount");
- if (nValue + nTransactionFee > GetBalance())
- return _("Insufficient funds");
-
- // Parse Bitcoin address
- CScript scriptPubKey;
- scriptPubKey.SetDestination(address);
-
- return SendMoney(scriptPubKey, nValue, wtxNew);
+ // payTxFee is user-set "I want to pay this much"
+ int64_t nFeeNeeded = payTxFee.GetFee(nTxBytes);
+ // User didn't set: use -txconfirmtarget to estimate...
+ if (nFeeNeeded == 0)
+ nFeeNeeded = pool.estimateFee(nConfirmTarget).GetFee(nTxBytes);
+ // ... unless we don't have enough mempool data, in which case fall
+ // back to a hard-coded fee
+ if (nFeeNeeded == 0)
+ nFeeNeeded = minTxFee.GetFee(nTxBytes);
+ return nFeeNeeded;
}
@@ -1505,11 +1637,11 @@ DBErrors CWallet::LoadWallet(bool& fFirstRunRet)
}
-DBErrors CWallet::ZapWalletTx()
+DBErrors CWallet::ZapWalletTx(std::vector<CWalletTx>& vWtx)
{
if (!fFileBacked)
return DB_LOAD_OK;
- DBErrors nZapWalletTxRet = CWalletDB(strWalletFile,"cr+").ZapWalletTx(this);
+ DBErrors nZapWalletTxRet = CWalletDB(strWalletFile,"cr+").ZapWalletTx(this, vWtx);
if (nZapWalletTxRet == DB_NEED_REWRITE)
{
if (CDB::Rewrite(strWalletFile, "\x04pool"))
@@ -1671,21 +1803,6 @@ void CWallet::ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool)
}
}
-int64_t CWallet::AddReserveKey(const CKeyPool& keypool)
-{
- {
- LOCK2(cs_main, cs_wallet);
- CWalletDB walletdb(strWalletFile);
-
- int64_t nIndex = 1 + *(--setKeyPool.end());
- if (!walletdb.WritePool(nIndex, keypool))
- throw runtime_error("AddReserveKey() : writing added key failed");
- setKeyPool.insert(nIndex);
- return nIndex;
- }
- return -1;
-}
-
void CWallet::KeepKey(int64_t nIndex)
{
// Remove from key pool
@@ -1754,7 +1871,7 @@ std::map<CTxDestination, int64_t> CWallet::GetAddressBalances()
continue;
int nDepth = pcoin->GetDepthInMainChain();
- if (nDepth < (pcoin->IsFromMe() ? 0 : 1))
+ if (nDepth < (pcoin->IsFromMe(ISMINE_ALL) ? 0 : 1))
continue;
for (unsigned int i = 0; i < pcoin->vout.size(); i++)
@@ -2037,7 +2154,7 @@ void CWallet::GetKeyBirthTimes(std::map<CKeyID, int64_t> &mapKeyBirth) const {
// Extract block timestamps for those keys
for (std::map<CKeyID, CBlockIndex*>::const_iterator it = mapKeyFirstBlock.begin(); it != mapKeyFirstBlock.end(); it++)
- mapKeyBirth[it->first] = it->second->nTime - 7200; // block times can be 2h off
+ mapKeyBirth[it->first] = it->second->GetBlockTime() - 7200; // block times can be 2h off
}
bool CWallet::AddDestData(const CTxDestination &dest, const std::string &key, const std::string &value)
diff --git a/src/wallet.h b/src/wallet.h
index b2c06d3f61..ab9550a984 100644
--- a/src/wallet.h
+++ b/src/wallet.h
@@ -24,13 +24,16 @@
#include <vector>
// Settings
-extern int64_t nTransactionFee;
+extern CFeeRate payTxFee;
+extern unsigned int nTxConfirmTarget;
extern bool bSpendZeroConfChange;
// -paytxfee default
static const int64_t DEFAULT_TRANSACTION_FEE = 0;
// -paytxfee will warn if called with a higher fee than this amount (in satoshis) per KB
static const int nHighTransactionFeeWarning = 0.01 * COIN;
+// Largest (in bytes) free transaction we're willing to create
+static const unsigned int MAX_FREE_TRANSACTION_CREATE_SIZE = 1000;
class CAccountingEntry;
class CCoinControl;
@@ -141,28 +144,32 @@ public:
MasterKeyMap mapMasterKeys;
unsigned int nMasterKeyMaxID;
+ // Increment to cause UI refresh, similar to new block
+ int64_t nConflictsReceived;
+
CWallet()
{
- nWalletVersion = FEATURE_BASE;
- nWalletMaxVersion = FEATURE_BASE;
- fFileBacked = false;
- nMasterKeyMaxID = 0;
- pwalletdbEncryption = NULL;
- nOrderPosNext = 0;
- nNextResend = 0;
- nLastResend = 0;
+ SetNull();
}
CWallet(std::string strWalletFileIn)
{
- nWalletVersion = FEATURE_BASE;
- nWalletMaxVersion = FEATURE_BASE;
+ SetNull();
+
strWalletFile = strWalletFileIn;
fFileBacked = true;
+ }
+ void SetNull()
+ {
+ nWalletVersion = FEATURE_BASE;
+ nWalletMaxVersion = FEATURE_BASE;
+ fFileBacked = false;
nMasterKeyMaxID = 0;
pwalletdbEncryption = NULL;
nOrderPosNext = 0;
nNextResend = 0;
nLastResend = 0;
+ nTimeFirstKey = 0;
+ nConflictsReceived = 0;
}
std::map<uint256, CWalletTx> mapWallet;
@@ -211,7 +218,7 @@ public:
// Adds an encrypted key to the store, without saving it to disk (used by LoadWallet)
bool LoadCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret);
bool AddCScript(const CScript& redeemScript);
- bool LoadCScript(const CScript& redeemScript) { return CCryptoKeyStore::AddCScript(redeemScript); }
+ bool LoadCScript(const CScript& redeemScript);
/// Adds a destination data tuple to the store, and saves it to disk
bool AddDestData(const CTxDestination &dest, const std::string &key, const std::string &value);
@@ -222,6 +229,11 @@ public:
/// Look up a destination data tuple in the store, return true if found false otherwise
bool GetDestData(const CTxDestination &dest, const std::string &key, std::string *value) const;
+ // Adds a watch-only address to the store, and saves it to disk.
+ bool AddWatchOnly(const CScript &dest);
+ // Adds a watch-only address to the store, without saving it to disk (used by LoadWallet)
+ bool LoadWatchOnly(const CScript &dest);
+
bool Unlock(const SecureString& strWalletPassphrase);
bool ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, const SecureString& strNewWalletPassphrase);
bool EncryptWallet(const SecureString& strWalletPassphrase);
@@ -244,8 +256,8 @@ public:
void MarkDirty();
bool AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet=false);
- 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 SyncTransaction(const CTransaction& tx, const CBlock* pblock);
+ bool AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate);
void EraseFromWallet(const uint256 &hash);
int ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate = false);
void ReacceptWalletTransactions();
@@ -253,17 +265,21 @@ public:
int64_t GetBalance() const;
int64_t GetUnconfirmedBalance() const;
int64_t GetImmatureBalance() const;
+ int64_t GetWatchOnlyBalance() const;
+ int64_t GetUnconfirmedWatchOnlyBalance() const;
+ int64_t GetImmatureWatchOnlyBalance() const;
bool CreateTransaction(const std::vector<std::pair<CScript, int64_t> >& vecSend,
CWalletTx& wtxNew, CReserveKey& reservekey, int64_t& nFeeRet, std::string& strFailReason, const CCoinControl *coinControl = NULL);
bool CreateTransaction(CScript scriptPubKey, int64_t nValue,
CWalletTx& wtxNew, CReserveKey& reservekey, int64_t& nFeeRet, std::string& strFailReason, const CCoinControl *coinControl = NULL);
bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey);
- std::string SendMoney(CScript scriptPubKey, int64_t nValue, CWalletTx& wtxNew);
- std::string SendMoneyToDestination(const CTxDestination &address, int64_t nValue, CWalletTx& wtxNew);
+ std::string SendMoney(const CTxDestination &address, int64_t nValue, CWalletTx& wtxNew);
+
+ static CFeeRate minTxFee;
+ static int64_t GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarget, const CTxMemPool& pool);
bool NewKeyPool();
bool TopUpKeyPool(unsigned int kpSize = 0);
- int64_t AddReserveKey(const CKeyPool& keypool);
void ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool);
void KeepKey(int64_t nIndex);
void ReturnKey(int64_t nIndex);
@@ -276,17 +292,17 @@ public:
std::set<CTxDestination> GetAccountAddresses(std::string strAccount) const;
- bool IsMine(const CTxIn& txin) const;
- int64_t GetDebit(const CTxIn& txin) const;
- bool IsMine(const CTxOut& txout) const
+ isminetype IsMine(const CTxIn& txin) const;
+ int64_t GetDebit(const CTxIn& txin, const isminefilter& filter) const;
+ isminetype IsMine(const CTxOut& txout) const
{
return ::IsMine(*this, txout.scriptPubKey);
}
- int64_t GetCredit(const CTxOut& txout) const
+ int64_t GetCredit(const CTxOut& txout, const isminefilter& filter) const
{
if (!MoneyRange(txout.nValue))
throw std::runtime_error("CWallet::GetCredit() : value out of range");
- return (IsMine(txout) ? txout.nValue : 0);
+ return ((IsMine(txout) & filter) ? txout.nValue : 0);
}
bool IsChange(const CTxOut& txout) const;
int64_t GetChange(const CTxOut& txout) const
@@ -302,27 +318,34 @@ public:
return true;
return false;
}
- bool IsFromMe(const CTransaction& tx) const
+ bool IsFromMe(const CTransaction& tx) const // should probably be renamed to IsRelevantToMe
+ {
+ return (GetDebit(tx, ISMINE_ALL) > 0);
+ }
+ bool IsConflicting(const CTransaction& tx) const
{
- return (GetDebit(tx) > 0);
+ BOOST_FOREACH(const CTxIn& txin, tx.vin)
+ if (mapTxSpends.count(txin.prevout))
+ return true;
+ return false;
}
- int64_t GetDebit(const CTransaction& tx) const
+ int64_t GetDebit(const CTransaction& tx, const isminefilter& filter) const
{
int64_t nDebit = 0;
BOOST_FOREACH(const CTxIn& txin, tx.vin)
{
- nDebit += GetDebit(txin);
+ nDebit += GetDebit(txin, filter);
if (!MoneyRange(nDebit))
throw std::runtime_error("CWallet::GetDebit() : value out of range");
}
return nDebit;
}
- int64_t GetCredit(const CTransaction& tx) const
+ int64_t GetCredit(const CTransaction& tx, const isminefilter& filter) const
{
int64_t nCredit = 0;
BOOST_FOREACH(const CTxOut& txout, tx.vout)
{
- nCredit += GetCredit(txout);
+ nCredit += GetCredit(txout, filter);
if (!MoneyRange(nCredit))
throw std::runtime_error("CWallet::GetCredit() : value out of range");
}
@@ -342,7 +365,7 @@ public:
void SetBestChain(const CBlockLocator& loc);
DBErrors LoadWallet(bool& fFirstRunRet);
- DBErrors ZapWalletTx();
+ DBErrors ZapWalletTx(std::vector<CWalletTx>& vWtx);
bool SetAddressBook(const CTxDestination& address, const std::string& strName, const std::string& purpose);
@@ -378,7 +401,7 @@ public:
int GetVersion() { LOCK(cs_wallet); return nWalletVersion; }
// Get wallet transactions that conflict with given transaction (spend same outputs)
- std::set<uint256> GetConflicts(const uint256& txid) const;
+ std::set<uint256> GetConflicts(const uint256& txid, bool includeEquivalent) const;
/** Address book entry changed.
* @note called with lock cs_wallet held.
@@ -468,11 +491,19 @@ public:
mutable bool fCreditCached;
mutable bool fImmatureCreditCached;
mutable bool fAvailableCreditCached;
+ mutable bool fWatchDebitCached;
+ mutable bool fWatchCreditCached;
+ mutable bool fImmatureWatchCreditCached;
+ mutable bool fAvailableWatchCreditCached;
mutable bool fChangeCached;
mutable int64_t nDebitCached;
mutable int64_t nCreditCached;
mutable int64_t nImmatureCreditCached;
mutable int64_t nAvailableCreditCached;
+ mutable int64_t nWatchDebitCached;
+ mutable int64_t nWatchCreditCached;
+ mutable int64_t nImmatureWatchCreditCached;
+ mutable int64_t nAvailableWatchCreditCached;
mutable int64_t nChangeCached;
CWalletTx()
@@ -509,11 +540,19 @@ public:
fCreditCached = false;
fImmatureCreditCached = false;
fAvailableCreditCached = false;
+ fWatchDebitCached = false;
+ fWatchCreditCached = false;
+ fImmatureWatchCreditCached = false;
+ fAvailableWatchCreditCached = false;
fChangeCached = false;
nDebitCached = 0;
nCreditCached = 0;
nImmatureCreditCached = 0;
nAvailableCreditCached = 0;
+ nWatchDebitCached = 0;
+ nWatchCreditCached = 0;
+ nAvailableWatchCreditCached = 0;
+ nImmatureWatchCreditCached = 0;
nChangeCached = 0;
nOrderPos = -1;
}
@@ -566,6 +605,10 @@ public:
{
fCreditCached = false;
fAvailableCreditCached = false;
+ fWatchDebitCached = false;
+ fWatchCreditCached = false;
+ fAvailableWatchCreditCached = false;
+ fImmatureWatchCreditCached = false;
fDebitCached = false;
fChangeCached = false;
}
@@ -576,15 +619,36 @@ public:
MarkDirty();
}
- int64_t GetDebit() const
+ // filter decides which addresses will count towards the debit
+ int64_t GetDebit(const isminefilter& filter) const
{
if (vin.empty())
return 0;
- if (fDebitCached)
- return nDebitCached;
- nDebitCached = pwallet->GetDebit(*this);
- fDebitCached = true;
- return nDebitCached;
+
+ int64_t debit = 0;
+ if(filter & ISMINE_SPENDABLE)
+ {
+ if (fDebitCached)
+ debit += nDebitCached;
+ else
+ {
+ nDebitCached = pwallet->GetDebit(*this, ISMINE_SPENDABLE);
+ fDebitCached = true;
+ debit += nDebitCached;
+ }
+ }
+ if(filter & ISMINE_WATCH_ONLY)
+ {
+ if(fWatchDebitCached)
+ debit += nWatchDebitCached;
+ else
+ {
+ nWatchDebitCached = pwallet->GetDebit(*this, ISMINE_WATCH_ONLY);
+ fWatchDebitCached = true;
+ debit += nWatchDebitCached;
+ }
+ }
+ return debit;
}
int64_t GetCredit(bool fUseCache=true) const
@@ -596,7 +660,7 @@ public:
// GetBalance can assume transactions in mapWallet won't change
if (fUseCache && fCreditCached)
return nCreditCached;
- nCreditCached = pwallet->GetCredit(*this);
+ nCreditCached = pwallet->GetCredit(*this, ISMINE_ALL);
fCreditCached = true;
return nCreditCached;
}
@@ -607,7 +671,7 @@ public:
{
if (fUseCache && fImmatureCreditCached)
return nImmatureCreditCached;
- nImmatureCreditCached = pwallet->GetCredit(*this);
+ nImmatureCreditCached = pwallet->GetCredit(*this, ISMINE_SPENDABLE);
fImmatureCreditCached = true;
return nImmatureCreditCached;
}
@@ -634,7 +698,7 @@ public:
if (!pwallet->IsSpent(hashTx, i))
{
const CTxOut &txout = vout[i];
- nCredit += pwallet->GetCredit(txout);
+ nCredit += pwallet->GetCredit(txout, ISMINE_SPENDABLE);
if (!MoneyRange(nCredit))
throw std::runtime_error("CWalletTx::GetAvailableCredit() : value out of range");
}
@@ -645,6 +709,48 @@ public:
return nCredit;
}
+ int64_t GetImmatureWatchOnlyCredit(const bool& fUseCache=true) const
+ {
+ if (IsCoinBase() && GetBlocksToMaturity() > 0 && IsInMainChain())
+ {
+ if (fUseCache && fImmatureWatchCreditCached)
+ return nImmatureWatchCreditCached;
+ nImmatureWatchCreditCached = pwallet->GetCredit(*this, ISMINE_WATCH_ONLY);
+ fImmatureWatchCreditCached = true;
+ return nImmatureWatchCreditCached;
+ }
+
+ return 0;
+ }
+
+ int64_t GetAvailableWatchOnlyCredit(const bool& fUseCache=true) const
+ {
+ if (pwallet == 0)
+ return 0;
+
+ // Must wait until coinbase is safely deep enough in the chain before valuing it
+ if (IsCoinBase() && GetBlocksToMaturity() > 0)
+ return 0;
+
+ if (fUseCache && fAvailableWatchCreditCached)
+ return nAvailableWatchCreditCached;
+
+ int64_t nCredit = 0;
+ for (unsigned int i = 0; i < vout.size(); i++)
+ {
+ if (!pwallet->IsSpent(GetHash(), i))
+ {
+ const CTxOut &txout = vout[i];
+ nCredit += pwallet->GetCredit(txout, ISMINE_WATCH_ONLY);
+ if (!MoneyRange(nCredit))
+ throw std::runtime_error("CWalletTx::GetAvailableCredit() : value out of range");
+ }
+ }
+
+ nAvailableWatchCreditCached = nCredit;
+ fAvailableWatchCreditCached = true;
+ return nCredit;
+ }
int64_t GetChange() const
{
@@ -656,14 +762,14 @@ public:
}
void GetAmounts(std::list<std::pair<CTxDestination, int64_t> >& listReceived,
- std::list<std::pair<CTxDestination, int64_t> >& listSent, int64_t& nFee, std::string& strSentAccount) const;
+ std::list<std::pair<CTxDestination, int64_t> >& listSent, int64_t& nFee, std::string& strSentAccount, const isminefilter& filter) const;
void GetAccountAmounts(const std::string& strAccount, int64_t& nReceived,
- int64_t& nSent, int64_t& nFee) const;
+ int64_t& nSent, int64_t& nFee, const isminefilter& filter) const;
- bool IsFromMe() const
+ bool IsFromMe(const isminefilter& filter) const
{
- return (GetDebit() > 0);
+ return (GetDebit(filter) > 0);
}
bool IsTrusted() const
@@ -676,7 +782,7 @@ public:
return true;
if (nDepth < 0)
return false;
- if (!bSpendZeroConfChange || !IsFromMe()) // using wtx's cached debit
+ if (!bSpendZeroConfChange || !IsFromMe(ISMINE_ALL)) // using wtx's cached debit
return false;
// Trusted if all inputs are from us and are in the mempool:
@@ -687,7 +793,7 @@ public:
if (parent == NULL)
return false;
const CTxOut& parentOut = parent->vout[txin.prevout.n];
- if (!pwallet->IsMine(parentOut))
+ if (pwallet->IsMine(parentOut) != ISMINE_SPENDABLE)
return false;
}
return true;
@@ -700,7 +806,7 @@ public:
void RelayWalletTransaction();
- std::set<uint256> GetConflicts() const;
+ std::set<uint256> GetConflicts(bool includeEquivalent=true) const;
};
@@ -712,20 +818,21 @@ public:
const CWalletTx *tx;
int i;
int nDepth;
+ bool fSpendable;
- COutput(const CWalletTx *txIn, int iIn, int nDepthIn)
+ COutput(const CWalletTx *txIn, int iIn, int nDepthIn, bool fSpendableIn)
{
- tx = txIn; i = iIn; nDepth = nDepthIn;
+ tx = txIn; i = iIn; nDepth = nDepthIn; fSpendable = fSpendableIn;
}
std::string ToString() const
{
- return strprintf("COutput(%s, %d, %d) [%s]", tx->GetHash().ToString().c_str(), i, nDepth, FormatMoney(tx->vout[i].nValue).c_str());
+ return strprintf("COutput(%s, %d, %d) [%s]", tx->GetHash().ToString(), i, nDepth, FormatMoney(tx->vout[i].nValue).c_str());
}
void print() const
{
- LogPrintf("%s\n", ToString().c_str());
+ LogPrintf("%s\n", ToString());
}
};
diff --git a/src/walletdb.cpp b/src/walletdb.cpp
index 80e9dded5f..a95baf83d0 100644
--- a/src/walletdb.cpp
+++ b/src/walletdb.cpp
@@ -112,6 +112,12 @@ bool CWalletDB::WriteCScript(const uint160& hash, const CScript& redeemScript)
return Write(std::make_pair(std::string("cscript"), hash), redeemScript, false);
}
+bool CWalletDB::WriteWatchOnly(const CScript &dest)
+{
+ nWalletDBUpdated++;
+ return Write(std::make_pair(std::string("watchs"), dest), '1');
+}
+
bool CWalletDB::WriteBestBlock(const CBlockLocator& locator)
{
nWalletDBUpdated++;
@@ -404,6 +410,19 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
wss.fAnyUnordered = true;
}
}
+ else if (strType == "watchs")
+ {
+ CScript script;
+ ssKey >> script;
+ char fYes;
+ ssValue >> fYes;
+ if (fYes == '1')
+ pwallet->LoadWatchOnly(script);
+
+ // Watch-only addresses have no birthday information for now,
+ // so set the wallet birthday to the beginning of time.
+ pwallet->nTimeFirstKey = 1;
+ }
else if (strType == "key" || strType == "wkey")
{
CPubKey vchPubKey;
@@ -680,7 +699,7 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet)
return result;
}
-DBErrors CWalletDB::FindWalletTx(CWallet* pwallet, vector<uint256>& vTxHash)
+DBErrors CWalletDB::FindWalletTx(CWallet* pwallet, vector<uint256>& vTxHash, vector<CWalletTx>& vWtx)
{
pwallet->vchDefaultKey = CPubKey();
CWalletScanState wss;
@@ -725,7 +744,11 @@ DBErrors CWalletDB::FindWalletTx(CWallet* pwallet, vector<uint256>& vTxHash)
uint256 hash;
ssKey >> hash;
+ CWalletTx wtx;
+ ssValue >> wtx;
+
vTxHash.push_back(hash);
+ vWtx.push_back(wtx);
}
}
pcursor->close();
@@ -743,11 +766,11 @@ DBErrors CWalletDB::FindWalletTx(CWallet* pwallet, vector<uint256>& vTxHash)
return result;
}
-DBErrors CWalletDB::ZapWalletTx(CWallet* pwallet)
+DBErrors CWalletDB::ZapWalletTx(CWallet* pwallet, vector<CWalletTx>& vWtx)
{
// build list of wallet TXs
vector<uint256> vTxHash;
- DBErrors err = FindWalletTx(pwallet, vTxHash);
+ DBErrors err = FindWalletTx(pwallet, vTxHash, vWtx);
if (err != DB_LOAD_OK)
return err;
diff --git a/src/walletdb.h b/src/walletdb.h
index 3bfb436050..58b4571b16 100644
--- a/src/walletdb.h
+++ b/src/walletdb.h
@@ -7,6 +7,7 @@
#include "db.h"
#include "key.h"
+#include "keystore.h"
#include <list>
#include <stdint.h>
@@ -93,6 +94,8 @@ public:
bool WriteCScript(const uint160& hash, const CScript& redeemScript);
+ bool WriteWatchOnly(const CScript &script);
+
bool WriteBestBlock(const CBlockLocator& locator);
bool ReadBestBlock(CBlockLocator& locator);
@@ -122,8 +125,8 @@ public:
DBErrors ReorderTransactions(CWallet*);
DBErrors LoadWallet(CWallet* pwallet);
- DBErrors FindWalletTx(CWallet* pwallet, std::vector<uint256>& vTxHash);
- DBErrors ZapWalletTx(CWallet* pwallet);
+ DBErrors FindWalletTx(CWallet* pwallet, std::vector<uint256>& vTxHash, std::vector<CWalletTx>& vWtx);
+ DBErrors ZapWalletTx(CWallet* pwallet, std::vector<CWalletTx>& vWtx);
static bool Recover(CDBEnv& dbenv, std::string filename, bool fOnlyKeys);
static bool Recover(CDBEnv& dbenv, std::string filename);
};